Шпаргалка: Docker

В курсе Docker используется прежде всего как модель слоёв образа, на которой построен werf/Stapel-билдер (см. шпаргалку werf) — реальная сборка Application-пакетов почти всегда идёт через werf build/d8 package build, а не напрямую docker build. Подробный разбор — M3 урок 1, distroless-паттерны — M8 урок 6.

Самые используемые команды

1
2
3
4
5
6
7
docker build -t <name>:<tag> .           # собрать образ из Dockerfile в текущей директории
docker run --rm -it <image> sh            # запустить контейнер с интерактивным shell
docker ps                                  # список работающих контейнеров
docker logs -f <container>
docker exec -it <container> sh
docker images                               # список локальных образов
docker system prune                          # очистка неиспользуемых данных
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FROM golang:1.26 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/bin/server ./cmd/server

FROM gcr.io/distroless/static-debian13
COPY --from=builder /app/bin/server /server
ENTRYPOINT ["/server"]

CLI: сборка

1
2
3
4
5
docker build -t <name>:<tag> <context>
docker build -t <name>:<tag> .                     # context = текущая директория
docker build -f <dockerfile> -t <name>:<tag> <context>   # явный путь к Dockerfile
docker build --target <stage>                        # выбор конкретной стадии multi-stage
docker build --build-arg <ARG>=<value>                # передать build-аргумент (в werf — через dependencies/imports)

CLI: запуск и инспекция

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
docker run -d -p <host-port>:<container-port> <image>   # фоновый запуск с пробросом порта
docker run [-d] [-p <host>:<container>] <image>
docker run <image> <command>                              # переопределить CMD (ENTRYPOINT сохраняется)
docker run --rm -it <image> sh
docker ps                                                  # работающие контейнеры
docker logs [-f] <container>
docker exec -it <container> sh
docker images                                              # список локальных образов
docker images | grep <pattern>
docker history <image>                                      # слои образа и размер каждого
docker inspect <image>                                       # метаданные образа
docker inspect <image> --format='{{json .RootFS.Layers}}'    # список слоёв RootFS в JSON
docker pull <image>
docker system prune                                          # очистка неиспользуемых образов/контейнеров/сетей

Dockerfile: базовые инструкции

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
FROM <image>                     # базовый образ (начальный слой)
FROM <image> AS <name>            # именованная стадия multi-stage build
WORKDIR <path>                     # рабочая директория для последующих инструкций
COPY <src> <dest>                   # копирование файлов из build context в образ
COPY package*.json <dest>            # копировать только манифесты зависимостей — для кэширования слоя
COPY . .                              # копировать весь context после установки зависимостей
COPY --from=<stage> <src> <dest>       # копирование артефакта из другой стадии multi-stage
RUN <command>                           # выполнение команды при сборке (создаёт новый слой)
CMD ["<executable>", "<arg>"]            # команда по умолчанию при запуске контейнера
ENTRYPOINT ["<executable>"]               # неизменяемая часть команды запуска
EXPOSE <port>                              # документирует порт (не публикует автоматически)
ARG <name>                                  # build-аргумент (доступен только на этапе сборки)
ENV <name> <value>                           # переменная окружения (доступна и во время выполнения)
USER <user-or-uid>                             # пользователь по умолчанию для последующих инструкций
LABEL <key>=<value>                             # метаданные образа (не создаёт новый слой с точки зрения ФС)
HEALTHCHECK CMD <command>                        # команда проверки здоровья контейнера

Multi-stage build

1
2
3
4
5
6
7
# syntax=docker/dockerfile:1
FROM ubuntu:24.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py
1
docker build -t hello .                 # собрать образ из multi-stage Dockerfile

Стадии, объявленные до финального FROM, не попадают в итоговый образ — в нём остаются только слои последней стадии плюс то, что явно скопировано через COPY --from=<stage>. Это ключевой механизм уменьшения размера итогового образа: инструменты сборки (компиляторы, npm, go) остаются в промежуточной стадии builder, а в финальный образ копируется только готовый артефакт.

Build secrets (BuildKit)

1
RUN --mount=type=secret,id=<id> <command>     # секрет доступен только на время выполнения RUN, не попадает в слой
1
export <VAR>="$(cat /run/secrets/<id>)"        # чтение секрета внутри RUN с mount

Антипаттерн — передача секрета через ARG/ENV: значение остаётся в истории слоёв образа (docker history) даже после unset:

1
2
3
# ПЛОХО: секрет попадает в историю образа
ARG NPM_TOKEN
RUN npm config set //registry.npmjs.org/:_authToken=${NPM_TOKEN}

Distroless / минимальные образы

1
2
3
4
5
6
7
8
FROM golang:1.26-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /app-binary .

FROM gcr.io/distroless/static-debian13     # без shell, без пакетного менеджера
COPY --from=builder /app-binary /app-binary
ENTRYPOINT ["/app-binary"]
1
2
3
4
gcr.io/distroless/static-debian13   # минимальный образ, статические бинарники (без libc)
gcr.io/distroless/static             # + CA-сертификаты (нужен для HTTPS-запросов из приложения)
gcr.io/distroless/*                    # семейство distroless base images (python, nodejs, java, cc, base)
scratch                                  # полностью пустой образ — даже без CA-сертификатов

Так как в distroless нет /bin/sh, обычные способы отладки не работают:

1
2
3
kubectl exec -it <pod> -- sh                                    # НЕ сработает: no such file or directory
kubectl debug -it <pod> --image=busybox --target=<container>     # эфемерный debug-контейнер — рабочая альтернатива
docker images | grep <name>                                        # сравнить размер distroless- и alpine-образов

Хранилище образов (для понимания copy-on-write)

1
/var/lib/docker/overlay2/     # локальное хранилище слоёв Docker (overlayfs)

Дополнительно: наиболее частые инструкции из официальной документации Docker

1
2
3
4
5
FROM <image>          # база для образа
RUN <command>           # выполняет команду в новом слое поверх текущего образа
WORKDIR <directory>       # рабочая директория для RUN/CMD/ENTRYPOINT/COPY/ADD
COPY <src> <dest>          # копирует файлы из контекста сборки в образ
CMD <command>                # программа по умолчанию при запуске контейнера (только последний CMD учитывается)

Docker Hardened Images (DHI) — минимальные, регулярно патчащиеся образы от Docker с near-zero CVE; Community-уровень бесплатен, но требует явной аутентификации в реестр dhi.io (docker login dhi.io через Docker ID/PAT) перед docker pull/docker build — без логина FROM dhi.io/... не сработает даже для публичных образов:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# syntax=docker/dockerfile:1
FROM dhi.io/python:3.12-dev AS builder
WORKDIR /app
RUN python3 -m venv /venv
ENV PATH="/venv/bin:$PATH"
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["/venv/bin/python3", "-m", "uvicorn", "app:app", "--host=0.0.0.0", "--port=8000"]

FROM dhi.io/python:3.12
WORKDIR /app
COPY --from=builder /venv /venv
ENV PATH="/venv/bin:$PATH"
COPY --from=builder /app .
EXPOSE 8000
CMD ["/venv/bin/python3", "-m", "uvicorn", "app:app", "--host=0.0.0.0", "--port=8000"]

--mount=type=cache кэширует директорию (например, pip/npm-кэш) между сборками без записи в итоговый образ; --mount=type=bind временно монтирует файл из контекста без его копирования — оба типа mount ускоряют повторные сборки в CI.