Przejdź do głównej zawartości

Konteneryzacja Docker i Kubernetes

Twój obraz waży 1,2 GB, Trivy zgłasza 40 CVE w warstwie bazowej, a pod właśnie dostał OOMKilled z kodem wyjścia 137 na stagingu. Możesz spędzić popołudnie na czytaniu blogów o najlepszych praktykach dla Dockerfile i analizowaniu wyjścia kubectl describe — albo wpiąć agenta AI w pętlę z faktycznymi plikami i pozwolić mu wygenerować, przeskanować i wyjaśnić poprawkę, podczas gdy ty ją recenzujesz.

Ten artykuł pokazuje, jak prowadzić pracę z Dockerem i Kubernetesem za pomocą Cursora, Claude Code i Codeksa: generowanie wieloetapowych plików Dockerfile, hartowanie manifestów, debugowanie pętli awarii i podłączanie prawdziwych serwerów MCP Docker i Kubernetes, żeby agent czytał żywy stan klastra zamiast zgadywać.

  • Powtarzalny prompt, który zamienia opasły, jednoetapowy Dockerfile w zahartowany, distroless’owy build wieloetapowy poniżej 80 MB
  • Workflow debugowania OOMKilli z exit 137, który koreluje limity, kubectl describe i ostatnie zmiany w kodzie
  • Poprawną, niezhalucynowaną konfigurację bramy MCP Docker i kubernetes-mcp-server (z flagami, które naprawdę istnieją)
  • Jasną zasadę: kiedy Agent Skill bije trwały serwer MCP w pracy z kontenerami
  • Trzy prompty do skopiowania i wklejenia, które możesz uruchomić jeszcze dziś na własnym repozytorium

Ruchem o największej dźwigni jest podanie agentowi twojego aktualnego Dockerfile wraz z realnymi ograniczeniami (runtime, port, narzędzie buildujące) i poproszenie o przepisanie na wieloetapowy. Konfiguracja różni się dla każdego narzędzia, ale prompt jest niemal identyczny.

W Cursorze dołącz plik jako kontekst przez @Dockerfile i uruchom to w trybie Agent (nie wpisuj prefiksu @agent — wybór trybu Agent wystarczy; @ jest zarezerwowane na odwołania do kontekstu, takie jak @Dockerfile czy @package.json):

@Dockerfile @package.json Rewrite this as a multi-stage build for our Node 20
service. Builder stage installs dev deps and runs the build; final stage is
gcr.io/distroless/nodejs20-debian12, runs as UID 65534, copies only dist/ and
production node_modules. Add a HEALTHCHECK hitting /health on 3000. Keep the
final image under 80MB and explain each layer you cut.

Trwała reguła utrzymuje spójność każdego przyszłego Dockerfile. Dodaj .cursor/rules/containers.md:

---
description: Container build standards
globs: ["**/Dockerfile", "**/*.dockerfile"]
---
- Always use multi-stage builds; never ship build tooling in the final image.
- Final stage: distroless or alpine, non-root USER, no shell unless required.
- Pin base images by tag, never `latest`. Add a HEALTHCHECK.

Wynik powinien wyglądać mniej więcej tak — nie chodzi o sam YAML, ale o to, że każda linia jest uzasadniona i że ją zrecenzowałeś:

FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
FROM gcr.io/distroless/nodejs20-debian12 AS production
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER 65534:65534
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD ["node", "dist/healthcheck.js"]
CMD ["dist/server.js"]

Generowanie to dopiero połowa pętli. Styl, który odróżnia recenzenta od kopiuj-wklejacza, to przebieg krytyki — zmuś agenta, żeby zaatakował własny wynik, zanim mu zaufasz.

Ta sama pętla generuj-potem-krytykuj dotyczy manifestów, ale tryb awarii jest inny: agenty uwielbiają wypluwać 200-liniowy Deployment z ustawionym każdym polem, a nie zrecenzujesz tego, czego nie da się przeczytać. Trzymaj prompt zawężony do jednego zasobu i jednej kwestii naraz.

Skoncentrowany prompt na kontekst bezpieczeństwa, który działa we wszystkich trzech narzędziach (żądanie jest identyczne — różni się tylko sposób wywołania):

Poproszenie o diff zamiast pełnego przepisania to kluczowa sztuczka: widzisz dokładnie te pięć linii, które się zmieniły, zamiast ponownie recenzować ścianę YAML-a odtworzonego przez agenta z pamięci (i być może subtelnie zmienionego).

To tutaj asysta AI sama się spłaca. Kod wyjścia 137 oznacza, że jądro zabiło proces przez OOM — ale dlaczego wymaga skorelowania limitu, faktycznego zużycia i tego, co się zmieniło. Podaj agentowi dowody, zamiast prosić go o spekulacje.

  1. Zbierz dowody w jednym miejscu.

    Okno terminala
    kubectl describe pod -l app=api > /tmp/pod.txt
    kubectl top pod -l app=api >> /tmp/pod.txt
    git log --oneline -10 >> /tmp/pod.txt
  2. Podaj agentowi cały pakiet i poproś o uszeregowane hipotezy. W Claude Code: claude "Read /tmp/pod.txt ..."; w Cursorze dołącz plik przez @pod.txt; w Codeksie podaj ścieżkę w prompcie. Prośba jest identyczna we wszystkich narzędziach.

  3. Zastosuj najmniejszą poprawkę i zweryfikuj. Zwykle jest to podniesienie limitu albo wyciek pamięci w ostatnim wdrożeniu. Po rolloucie uruchom ponownie kubectl top i potwierdź, że zbiór roboczy mieści się pod nowym limitem z zapasem.

Prompty z wklejonymi plikami są w porządku, ale prawdziwy skok jakościowy to umożliwienie agentowi odpytywania żywego stanu przez MCP. Liczą się tu dwa serwery i oba bywają nagminnie halucynowane w generowanych przez AI poradnikach — oto konfiguracja, która naprawdę działa.

Nie ma obrazu mcp/docker-toolkit ani endpointu HTTP localhost:8080, na który można wskazać klienta. Docker MCP Toolkit to funkcja Docker Desktop napędzana wtyczką CLI docker mcp (MCP Gateway). Włączasz MCP Toolkit w Docker Desktop, włączasz pożądane serwery z katalogu, a następnie podłączasz klienta przez stdio do procesu bramy:

Dodaj bramę do .cursor/mcp.json:

{
"mcpServers": {
"docker": {
"command": "docker",
"args": ["mcp", "gateway", "run"]
}
}
}

Najpierw włącz serwery z katalogu przez docker mcp server enable <name>; brama udostępnia ich narzędzia każdemu podłączonemu klientowi. Zobacz dokumentację Docker MCP Toolkit oraz docker/mcp-gateway.

Pakiet kubernetes-mcp-server (z containers/kubernetes-mcp-server) jest prawdziwy, ale jego flagi są często zmyślane. Nie ma flag --audit-log, --rbac-mode, --namespace-filter ani --context. Flagi, które istnieją, to --kubeconfig, --read-only, --toolsets, --port, --disable-multi-cluster i --config. RBAC jest egzekwowane przez ServiceAccount powiązane z kubeconfigiem, na który go wskazujesz — nie przez przełącznik CLI.

Zacznij w trybie tylko-do-odczytu, jedynym rozsądnym domyślnym ustawieniu dla narzędzia prowadzonego przez LLM:

.cursor/mcp.json:

{
"mcpServers": {
"kubernetes": {
"command": "npx",
"args": ["-y", "kubernetes-mcp-server@latest", "--read-only"],
"env": { "KUBECONFIG": "/path/to/restricted-kubeconfig" }
}
}
}

Z podłączonym serwerem pytania o klaster stają się konwersacyjne — i osadzone w realnym stanie:

Audit the production cluster: list pods that are not Running, any with no
resource limits set, and any running as root. Group by namespace and flag the
three highest-risk findings.

Nie każde zadanie potrzebuje trwałego połączenia. Agent Skills — instalowane uniwersalnym CLI, npx skills add <owner/repo> (z vercel-labs/skills), działające w Claude Code, Cursorze i Codeksie — to lżejsza opcja dla jednozadaniowego, bezstanowego wzbogacenia: skill do lintowania Dockerfile, generator wartości Helm, skill z checklistą wdrożeniową. Sięgnij po skill, gdy chcesz powtarzalnej wiedzy albo jednorazowej transformacji; sięgnij po serwer MCP, gdy agent musi odczytać żywy stan lub na nim działać (twój działający klaster, demon Dockera). Skill do hartowania Dockerfile plus kubernetes-mcp-server do odczytów na żywo to częste, komplementarne połączenie.

  • Agent wypluwa usunięte API. Jak wyżej, PodSecurityPolicy, extensions/v1beta1 i autoscaling/v2beta2 wciąż wyskakują z nieświeżych danych treningowych. Przypnij to: podaj agentowi wersję klastra i każ mu zweryfikować przez kubectl api-resources.

  • docker mcp gateway run natychmiast kończy działanie. Funkcja MCP Toolkit musi być najpierw włączona w Docker Desktop i musisz przez docker mcp server enable <name> włączyć co najmniej jeden serwer z katalogu. Brama bez niczego włączonego nie ma narzędzi do udostępnienia.

  • Serwer MCP Kubernetes widzi klaster, ale każdy zapis kończy się błędem. To --read-only i zawężone ServiceAccount robią swoją robotę. Jeśli naprawdę potrzebujesz mutacji, zdejmij --read-only świadomie na tę sesję — nie dawaj mu admina.

  • Krok skanowania w CI używa wycofanej akcji. Stara github/codeql-action/upload-sarif@v2 została wycofana w 2025; użyj @v3 (albo @v4). Każ agentowi przeszukać twoje workflowy pod kątem przypiętych wersji akcji i podbić tylko krok wgrywania SARIF:

    - name: Upload Trivy results
    uses: github/codeql-action/upload-sarif@v3
    if: always()
    with:
    sarif_file: 'trivy-results.sarif'
  • „Bezpieczny” devcontainer po cichu wyłącza pytania o uprawnienia. Jeśli tworzysz szablon devcontainera dla Claude Code, ustawieniem VS Code jest claudeCode.allowDangerouslySkipPermissions (a claudeCode.initialPermissionMode dla trybu domyślnego) — a nie klucz claude-code.dangerouslySkipPermissions, który nic nie robi. I zastanów się dwa razy, zanim włączysz pomijanie uprawnień w kontenerze, który nazwałeś „bezpiecznym”: to przeczy samej idei. Wybierz domyślny tryb z pytaniami i odizolowany, ograniczony sieciowo devcontainer.