Construirea și rularea imaginii
Vom construi imaginea aplicației direct din fișierele existente în repository.
Dockerfile multi-stage
Fișierul Dockerfile conține două etape:
# --- build stage ---
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/ticketing .
# --- runtime stage ---
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/ticketing /ticketing
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/ticketing"]
Prima etapă folosește imaginea Go pentru a descărca dependențele și a compila aplicația. A doua etapă copiază numai executabilul rezultat într-o imagine distroless, făr ă compilator, manager de pachete sau shell.
Avantajele principale sunt:
- imagine runtime mai mică și cu mai puține componente
- separarea mediului de build de mediul de execuție
- rularea procesului cu un utilizator non-root
- reducerea suprafeței de atac
Pentru un mediu de producție, imaginile de bază pot fi fixate și prin digest. În laborator păstrăm referințele din repository pentru lizibilitate.
Contextul de build
Fișierul .dockerignore exclude elementele care nu trebuie trimise către builder:
.git
.env
*.md
docker-compose.yml
Dockerfile
Acest lucru reduce contextul de build și evită includerea accidentală a fișierului .env în imagine.
Construirea imaginii
Din rădăcina repository-ului rulați:
docker build --tag ticketing-api:lab1 .
Punctul final reprezintă contextul de build. Verificați rezultatul:
docker image ls ticketing-api
docker image history ticketing-api:lab1
docker image inspect ticketing-api:lab1
Puteți confirma utilizatorul configurat în imagine:
docker image inspect --format '{{.Config.User}}' ticketing-api:lab1
Rezultatul așteptat este nonroot:nonroot.
Rularea aplicației în memorie
docker container run -d \
--name ticketing-api \
--publish 8080:8080 \
--env USE_POSTGRES=false \
ticketing-api:lab1
Opțiunea --publish 8080:8080 mapează portul 8080 al gazdei la portul 8080 din container. Instrucțiunea EXPOSE documentează portul imaginii, dar nu îl publică singură.
Verificați starea și logurile:
docker container ls
docker container logs ticketing-api
curl -sS http://localhost:8080/health
Răspunsul endpoint-ului de health trebuie să fie:
{"status":"ok"}
Operații pe tichete
Creați un tichet:
curl -sS -X POST http://localhost:8080/tickets \
-H 'Content-Type: application/json' \
-d '{"title":"Login broken","description":"500 on submit","priority":"high","reporter":"ana"}'
Listați tichetele:
curl -sS http://localhost:8080/tickets
Inspectați configurația containerului:
docker container inspect ticketing-api
docker container top ticketing-api
O limitare intenționată a imaginii distroless
Încercați:
docker container exec -it ticketing-api sh
Comanda trebuie să eșueze deoarece imaginea runtime nu conține shell. Acesta este un compromis intenționat: imaginea este minimalistă, dar debugging-ul interactiv în interiorul containerului este limitat. Pentru investigare folosim loguri, inspectare externă și imagini de debug dedicate.
Caracterul efemer al memoriei
Reporniți aplicația și listați din nou tichetele:
docker container restart ticketing-api
curl -sS http://localhost:8080/tickets
Lista este goală deoarece stocarea in-memory este reconstruită la pornirea procesului.
La finalul secțiunii:
docker container rm --force ticketing-api
Checkpoint
- imaginea este construită prin două etape
- containerul rulează ca utilizator non-root
- portul trebuie publicat explicit
- datele in-memory nu supraviețuiesc repornirii procesului