20 вопросов
ВМ - полная эмуляция железа, своя ОС, гипервизор. Контейнер - изоляция процессов на общем ядре ОС (namespaces, cgroups). Контейнер легче и быстрее стартует, меньше накладных расходов. В Go бинарник компилируется в статический или с минимальными зависимостями и упаковывается в образ; один процесс в контейнере - типичный сценарий.
Образ - неизменяемый шаблон (слои файловой системы + метаданные). Контейнер - запущенный экземпляр образа (читаемый слой + записываемый слой поверх). Один образ можно запустить много раз - получится несколько контейнеров. В Go собирают образ из Dockerfile (COPY бинарника или multi-stage build с компиляцией внутри).
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /server .
FROM scratch
COPY --from=builder /server /server
ENTRYPOINT ["/server"]Каждая инструкция в Dockerfile создает слой. Слои кешируются по хешу контекста; при изменении инструкции или файлов выше по контексту все последующие слои пересобираются. Поэтому копирование go.mod и go.sum и go mod download до COPY кода - частый паттерн: зависимости кешируются отдельно от кода. В Go multi-stage: слой с go build пересобирается при изменении кода, базовый образ и зависимости - из кеша.
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o app .Multi-stage - несколько этапов в одном Dockerfile; итоговый образ содержит только артефакт последнего этапа. В первом этапе компилируют Go-бинарник (нужен golang образ), во втором копируют только бинарник в минимальный образ (scratch, alpine). Итог: маленький образ без компилятора и исходников, быстрый деплой и меньше поверхность атак.
FROM golang:1.21 AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o server .
FROM alpine:3.19
COPY --from=build /app/server /server
EXPOSE 8080
CMD ["/server"]Compose описывает мультиконтейнерное приложение: сервисы, сети, тома. Один файл docker-compose.yml, запуск docker compose up. Для Go: сервис с билдом из Dockerfile или образом, порты, переменные окружения, зависимости (postgres, redis). Удобно для локальной разработки и тестов.
services:
app:
build: .
ports: ["8080:8080"]
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
depends_on: [db]
db:
image: postgres:16
environment: POSTGRES_PASSWORD: pass
volumes: [pgdata:/var/lib/postgresql/data]HEALTHCHECK в Dockerfile или compose - команда, которая периодически проверяет, что контейнер жив. По результату (exit 0 - healthy, 1 - unhealthy) Docker помечает контейнер. В Go приложение отдает HTTP endpoint /health (проверка БД, зависимостей) или выполняет легкую логику. Оркестраторы (Kubernetes) используют те же проверки через probes.
HEALTHCHECK --interval=30s --timeout=3s CMD wget -q -O- http://localhost:8080/health || exit 1Pod - минимальная единица запуска (один или несколько контейнеров, общая сеть/тома). Deployment - декларативное управление репликами Pod (rolling update, откат). Service - стабильный сетевой доступ к набору Pod (ClusterIP, NodePort, LoadBalancer). Ingress - маршрутизация HTTP/HTTPS снаружи к сервисам (хосты, пути). В Go деплоят образ в Pod через Deployment; Service дает DNS имя; Ingress - внешний доступ.
Pod - группа контейнеров с общими сетевым namespace и томами. Обычно один контейнер на Pod (например, Go-сервис). Pod имеет IP в сети кластера, живет на ноде; при падении или пересоздании получает новый IP. В манифесте задают образ, порты, ресурсы (requests/limits), переменные окружения, probes.
spec:
containers:
- name: app
image: myregistry/app:v1
ports: [{containerPort: 8080}]
livenessProbe:
httpGet: {path: /health, port: 8080}Liveness - контейнер жив; при неудаче kubelet перезапускает контейнер. Readiness - контейнер готов принимать трафик; при неудаче Pod убирается из Service. Startup - для медленного старта; до первой успешной проверки liveness/readiness не считаются проваленными. В Go реализуют HTTP endpoint (например /health, /ready) или exec-проверку. Важно: readiness не должен падать при временной потере БД, иначе все Pod перестанут получать трафик.
livenessProbe:
httpGet: {path: /health, port: 8080}
initialDelaySeconds: 5
readinessProbe:
httpGet: {path: /ready, port: 8080}Helm - пакетный менеджер для Kubernetes: шаблонизация манифестов (values.yaml), версионирование релизов, откат. Chart - каталог с templates и values. В Go-проектах образ упаковывают в chart; один chart может описать Deployment, Service, Ingress, ConfigMap. Удобно для деплоя в разные окружения (dev/stage/prod) подстановкой values.
helm install myapp ./chart -f values-prod.yaml
helm upgrade myapp ./chart --set image.tag=v2ConfigMap - непроекрипционные данные (конфиг, URL). Secret - чувствительные данные (пароли, ключи), хранятся base64. Подключают как переменные окружения или файлы (volumeMounts). В Go читают из env (os.Getenv) или из смонтированного файла. Не коммитить секреты в репозиторий; использовать внешние хранилища (Vault) или CI-секреты при установке.
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef: {name: app-secrets, key: database-url}HPA автоматически масштабирует число реплик Deployment по метрикам (CPU, memory, custom). Задают min/max реплик и целевое использование (например, 70% CPU). В Go приложение должно отдавать метрики в формате, который собирает метрик-сервер (обычно стандартные cAdvisor метрики с нод). Для кастомных метрик нужен адаптер (Prometheus adapter и т.п.).
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: app}
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource: {name: cpu, target: {type: Utilization, averageUtilization: 70}}Sidecar - дополнительный контейнер в том же Pod, который дополняет основной (логирование, прокси, синхронизация). Общая сеть: localhost между контейнерами; общие тома для обмена файлами. Примеры: envoy как прокси, fluentd для логов, init-контейнер для миграций перед стартом приложения. В Go-сервисе основной контейнер - бинарник; sidecar - отдельный образ.
containers:
- name: app
image: myapp
- name: envoy
image: envoyproxy/envoy
# проксирует трафик к appNamespace - виртуальное разделение ресурсов внутри кластера (не изоляция сети по умолчанию). Удобно для окружений (dev, staging, prod) или команд. Ресурсы (Deployment, Service) принадлежат namespace; DNS внутри namespace - по короткому имени сервиса. В Go имена сервисов в конфиге могут включать namespace (svc.namespace.svc.cluster.local) или использовать короткое имя в том же namespace.
kubectl get pods -n production
kubectl create namespace stagingDaemonSet - по одному Pod на каждой ноде (агенты, сбор логов, сетевые плагины). StatefulSet - стабильная идентичность Pod (имена pod-0, pod-1), стабильные тома при пересоздании, порядок деплоя и масштабирования. Для обычного Go-сервиса без состояния используют Deployment. StatefulSet - для БД, очередей с привязкой к диску; DaemonSet - для агентов на нодах.
Volume - каталог, доступный контейнеру в Pod. emptyDir - временный, живет пока Pod жив. persistentVolumeClaim - привязка к PVC и диску (сохраняется при пересоздании Pod). configMap/secret - монтирование конфига или секрета как файлы. В Go приложение читает конфиг из смонтированного тома или из env; для состояния (файлы, SQLite) используют PVC.
volumes:
- name: config
configMap: {name: app-config}
volumeMounts:
- name: config
mountPath: /etc/apprequests - гарантированные ресурсы для планирования (scheduler учитывает при размещении Pod). limits - верхняя граница; при превышении CPU throttling, memory - OOMKill. Для Go важно задать разумный memory limit (heap + другие аллокации); при нехватке контейнер убивается. GOMEMLIMIT можно выставить под limit, чтобы GC не дал процессу вырасти выше лимита. CPU request/limit влияют на планировщик и долю CPU.
resources:
requests: {memory: "128Mi", cpu: "100m"}
limits: {memory: "512Mi", cpu: "500m"}Rolling update - постепенная замена старых Pod новыми (maxSurge, maxUnavailable). Без даунтайма, откат через kubectl rollout undo. Recreate - все старые Pod убиваются, затем создаются новые; даунтайм есть. По умолчанию Deployment использует RollingUpdate. В Go приложение должно корректно завершаться по SIGTERM (graceful shutdown) и не держать долгие соединения без возможности дождаться дренажа.
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 01) Multi-stage build: итоговый образ только с бинарником. 2) Минимальный базовый образ (scratch, alpine, distroless). 3) Не root пользователь (USER в Dockerfile). 4) Один процесс на контейнер. 5) Health endpoint для liveness/readiness. 6) Graceful shutdown по SIGTERM. 7) Конфиг через env или смонтированные файлы, не хардкод. 8) Версия образа по тегу (не latest в проде). 9) CGO_ENABLED=0 для статической сборки где возможно.
RUN adduser -D -g '' appuser
USER appuser
ENTRYPOINT ["/app/server"]Distroless - образы без shell, пакетного менеджера и лишних утилит. Минимальная поверхность атак и размер. Для статического Go-бинарника подходит образ на базе scratch или gcr.io/distroless/static. Отладка сложнее (нет shell) - при необходимости временно переключаются на alpine. Идеально для production Go-сервисов.
FROM gcr.io/distroless/static-debian12
COPY --from=build /app/server /server
ENTRYPOINT ["/server"]