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