Sari la conținutul principal

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
notă

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