Go
Docker and deployment
Add a Dockerfile and multi-stage build.
Docker and deployment
The service is packaged with a multi-stage Docker image: the first stage builds, the second carries only the binary.
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server
FROM gcr.io/distroless/static
COPY --from=build /app /app
EXPOSE 8080
ENTRYPOINT ["/app"]
The result is a secure image of a few MB with no shell.
Configuration and health check
A service in a container reads its settings from environment variables and exposes a health endpoint so the orchestrator (Kubernetes, Docker) can check it:
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
On SIGTERM, finishing in-flight requests with srv.Shutdown(ctx) before exiting (graceful shutdown) is a good habit.
Exercise Port setting
Write port(env func(string) string) string: if env("PORT") is empty, return "8080". Instead of os.Getenv, try two cases with fake functions: an empty environment and one returning "9000". Print both results on one line.
Show example solution
package main
import "fmt"
func port(env func(string) string) string {
if p := env("PORT"); p != "" {
return p
}
return "8080"
}
func main() {
bos := func(string) string { return "" }
dolu := func(string) string { return "9000" }
fmt.Println(port(bos), port(dolu))
}
Test yourself
-
Why are <code>go.mod</code> and <code>go.sum</code> copied before the source code?
- Because Docker requires it
- To make the image smaller
- To run tests
- So the dependency layer stays cached and isn't re-downloaded when code changes
Show answer
So the dependency layer stays cached and isn't re-downloaded when code changes — Docker caches layers; as long as go.mod doesn't change, the go mod download layer doesn't rerun.
-
Copy from the earlier stage
FROM gcr.io/distroless/static
COPY ____ /app /app
Show answer
FROM gcr.io/distroless/static
COPY --from=build /app /app
-
Deployment parts
- AS build
- Build stage
- distroless
- Small shell-less base
- PORT
- Setting from environment
- /healthz
- Health check
Next lesson: Dockerfile