Docker et Go : conteneurisation d'applications en Golang
Dans le développement moderne, la conteneurisation est devenue le standard de facto pour le déploiement et la mise à l'échelle des applications. Docker et Go forment un duo idéal pour créer des microservices légers, rapides et sécurisés. Go se compile en un binaire statique, ce qui le rend particulièrement attractif pour la conteneurisation : l'image finale peut ne peser que quelques mégaoctets. Dans cet article, nous allons voir comment conteneuriser correctement des applications Go, optimiser le Dockerfile et éviter les erreurs typiques.
Pourquoi Docker et Go sont-ils une combinaison idéale ?
Go (Golang) a été conçu pour les architectures cloud modernes. Ses caractéristiques clés sont la compilation statique, la prise en charge intégrée de la concurrence et l'absence de dépendances externes à l'exécution. Docker, quant à lui, fournit un environnement isolé pour exécuter les applications. Ensemble, ils permettent de créer des images qui :
- Prennent un minimum de place — l'image d'une application Go peut faire moins de 10 Mo.
- Se lancent rapidement — le binaire statique ne nécessite ni interpréteur ni machine virtuelle.
- Se mettent à l'échelle facilement — idéales pour l'orchestration dans Kubernetes.
- Sont plus sécurisées — une image minimale réduit la surface d'attaque.
Création d'une application Go simple pour la conteneurisation
Pour commencer, écrivons une application web simple en Go que nous allons conteneuriser. Créez un fichier main.go :
package main
import ( "fmt" "log" "net/http" "os")
func main() { port := os.Getenv("PORT") if port == "" { port = "8080" }
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from Go in Docker! 🐳") })
log.Printf("Server starting on port %s", port) log.Fatal(http.ListenAndServe(":"+port, nil))}Cette application écoute les requêtes HTTP et renvoie un message de bienvenue. Le port peut être défini via la variable d'environnement PORT.
Rédaction du Dockerfile pour une application Go
Créons maintenant un Dockerfile. Commençons par une approche de base, puis optimisons-la.
Dockerfile de base (sans optimisation)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./RUN go mod download
COPY . .RUN go build -o main .
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]Ce Dockerfile utilise une construction multi-étapes — l'un des meilleurs patterns pour Go. La première étape (builder) compile l'application, la seconde (image finale) ne contient que le binaire compilé. Cette approche permet d'éviter d'inclure le compilateur et les outils Go dans l'image finale.
Dockerfile optimisé (bonnes pratiques)
Pour rendre l'image encore plus petite et plus sécurisée, utilisons scratch — une image vide sans shell ni utilitaires :
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./RUN go mod download
COPY . .
# Désactiver CGO, activer les optimisationsRUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o main .
FROM scratch
WORKDIR /root/
COPY --from=builder /app/main .
# Ajouter les certificats racine pour HTTPSCOPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
CMD ["./main"]Optimisations clés :
CGO_ENABLED=0— désactive CGO, ce qui réduit la taille du binaire.-ldflags="-s -w"— supprime la table des symboles et les informations de débogage.scratch— image minimale sans couches superflues.- Copie de
ca-certificates.crt— nécessaire pour fonctionner avec HTTPS.