🐳 Docker

Полный справочник: образы и контейнеры, Dockerfile и лучшие практики, тома, сети, сборка и BuildKit, реестры, диагностика, безопасность и уборка места.

Шпаргалки · Инфраструктура · #docker #containers #devops #dockerfile

Основные понятия

Термин Смысл
Образ (image) неизменяемый шаблон: файловая система + метаданные, из слоёв
Контейнер запущенный экземпляр образа (изолированный процесс)
Реестр (registry) хранилище образов: Docker Hub, GHCR, GitLab, ECR, Harbor
Том (volume) данные вне жизненного цикла контейнера
Сеть (network) связь контейнеров между собой и с хостом
Dockerfile рецепт сборки образа

Контейнер использует ядро хоста (в отличие от виртуальной машины): быстрее и легче, но изоляция слабее.

Запуск контейнеров

docker run hello-world
docker run -d --name web -p 8080:80 nginx                     # в фоне, порт хост:контейнер
docker run -it --rm ubuntu bash                                # интерактивно, удалить после выхода
docker run -d --name db -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data -p 5432:5432 postgres:16
docker run --restart unless-stopped --memory 512m --cpus 1 nginx
docker run -v "$PWD":/app -w /app node:22 npm test             # папка хоста внутрь
docker run --env-file .env --network mynet --user 1000:1000 image
Флаг Смысл
-d в фоне
-it интерактивный терминал
--rm удалить после остановки
-p 8080:80 проброс порта
-v том или bind mount
-e / --env-file переменные окружения
--name имя контейнера
--network сеть
--restart политика перезапуска (no, on-failure, always, unless-stopped)
--memory, --cpus ограничения ресурсов
--read-only, --cap-drop ALL усиление безопасности

Управление контейнерами

docker ps [-a]                       # запущенные (все)
docker stop|start|restart web        docker kill web          docker rm [-f] web        docker pause web
docker logs -f --tail 100 web        docker logs --since 10m web
docker exec -it web sh               docker exec web cat /etc/hosts
docker cp web:/app/log.txt .         docker cp ./a.txt web:/tmp/
docker inspect web                    docker inspect -f '{{.NetworkSettings.IPAddress}}' web
docker stats [--no-stream]           docker top web           docker port web
docker diff web                      docker rename web web2
docker wait web; docker update --restart=always web

Образы

docker images                        docker pull nginx:1.27              docker push registry/app:1.0
docker build -t app:1.0 .            docker build -f docker/Dockerfile --target prod --build-arg VER=2 .
docker tag app:1.0 ghcr.io/me/app:1.0
docker rmi app:1.0                   docker history app:1.0              docker image inspect app
docker save -o app.tar app:1.0       docker load -i app.tar               # перенос без реестра
docker login ghcr.io                 docker logout
docker search nginx
docker buildx build --platform linux/amd64,linux/arm64 -t me/app:1.0 --push .       # мультиплатформа

Тег latest не означает «свежий»: закрепляйте версии (postgres:16.4), а для воспроизводимости используйте digest (image@sha256:…).

Dockerfile

# syntax=docker/dockerfile:1
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS prod
ENV NODE_ENV=production
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
ENTRYPOINT ["node"]
CMD ["dist/server.js"]
Инструкция Назначение
FROM базовый образ (scratch, alpine, debian-slim, distroless)
WORKDIR рабочая папка
COPY / ADD копирование (ADD умеет архивы и URL: лучше COPY)
RUN команда при сборке (создаёт слой)
ENV / ARG переменная окружения / аргумент сборки
EXPOSE документирует порт (не публикует)
USER пользователь запуска
ENTRYPOINT / CMD команда запуска / аргументы по умолчанию
HEALTHCHECK проверка здоровья
VOLUME, LABEL, STOPSIGNAL, SHELL прочее

Лучшие практики

  1. Многоэтапная сборка оставляет в итоговом образе только нужное.
  2. Порядок слоёв: редко меняющееся (зависимости) выше, код ниже: работает кэш.
  3. .dockerignore: node_modules, .git, *.log, .env, dist: меньше контекст, нет утечки секретов.
  4. Лёгкая база (alpine, -slim, distroless), закреплённая версия.
  5. Запуск не от root (USER), только нужные права, --read-only.
  6. Объединяйте RUN (apt-get update && apt-get install -y --no-install-recommends x && rm -rf /var/lib/apt/lists/*).
  7. Один процесс на контейнер, логи в stdout / stderr.
  8. Секреты не кладите в образ и ENV: --secret (BuildKit), переменные при запуске, Docker / Kubernetes secrets.
  9. Форма CMD ["exec", "form"] (JSON-массив) передаёт сигналы процессу напрямую; в shell-форме процесс обёрнут в sh.
  10. Включайте HEALTHCHECK, сканируйте образы (docker scout, Trivy).

Тома и данные

docker volume create data            docker volume ls            docker volume inspect data           docker volume rm data
docker run -v data:/var/lib/app image                       # именованный том (управляет Docker)
docker run -v /host/path:/container/path:ro image            # bind mount (папка хоста, :ro только чтение)
docker run --tmpfs /tmp image                                # в памяти
docker run --rm -v data:/d -v "$PWD":/b alpine tar czf /b/backup.tgz -C /d .     # резервная копия тома

Данные внутри контейнера без тома исчезают вместе с ним.

Сети

docker network create appnet         docker network ls            docker network inspect appnet
docker run -d --network appnet --name api image             # контейнеры в одной сети видят друг друга по имени
docker network connect appnet web    docker network disconnect appnet web
Драйвер Применение
bridge по умолчанию на одном хосте
host сеть хоста без изоляции
none без сети
overlay между хостами (Swarm)
macvlan контейнер с адресом из физической сети

В пользовательской bridge-сети работает DNS по имени контейнера (в сети bridge по умолчанию нет). Порт -p 127.0.0.1:8080:80 публикует только на localhost: без адреса порт открыт для всех интерфейсов и обходит ufw.

Диагностика

docker logs web                      # почему упал
docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' web
docker events                        docker run --rm -it --pid=container:web nicolaka/netshoot
docker exec web env                  docker exec web ps aux
docker system df                     docker system info
Симптом Причина
Exit code 0 сразу основной процесс завершился (нет долгоживущей команды)
Exit 137 / OOMKilled не хватило памяти
Exit 139 segfault
port is already allocated порт занят на хосте
Не видит БД по localhost внутри контейнера localhost это он сам: используйте имя сервиса
Permission denied на томе UID внутри и снаружи не совпадают

Уборка

docker system df
docker container prune -f            docker image prune -f             docker image prune -a              # неиспользуемые образы
docker builder prune                 docker network prune             docker volume prune                 # осторожно: удаляет тома
docker system prune -af --volumes    # всё неиспользуемое, включая тома

Внимание: docker volume prune и --volumes удаляют данные баз без возврата. Проверьте docker volume ls заранее.

Безопасность

Не давайте контейнерам --privileged и доступ к /var/run/docker.sock (это root на хосте). Ограничивайте возможности (--cap-drop ALL --cap-add NET_BIND_SERVICE), используйте --security-opt no-new-privileges, rootless Docker / Podman, обновляйте базовые образы, подписывайте (cosign) и сканируйте их.

Альтернативы и экосистема

Podman и Buildah (без демона, совместимы с CLI), containerd, nerdctl. Оркестрация: Docker Compose, Swarm, Kubernetes. Утилиты: dive (слои образа), Hadolint (линтер Dockerfile), Trivy и Grype (уязвимости), Watchtower (автообновление), Portainer (веб-интерфейс), lazydocker.