Основы Docker: полное руководство по работе с контейнерами
Полное руководство по Docker для начинающих: от установки до управления контейнерами
- Зачем вообще Docker
- Установка
- Возможности Docker CLI
- Образы контейнеров
- Работа с контейнерами
- Проброс портов и каталогов
- Внутри контейнера
- Статус, остановка и перезапуск контейнера
- Копирование данных в обе стороны
- Логи приложения в контейнере
- Полная информация по контейнеру
- Изменение параметров запуска контейнера
- Изменение лимитов CGroups
- Работа с репозиториями на hub.docker.com
- Известные проблемы и особенности
- Дополнительные рекомендации
- Зачем вообще Docker
- Установка
- Возможности Docker CLI
- Образы контейнеров
- Работа с контейнерами
- Проброс портов и каталогов
- Внутри контейнера
- Статус, остановка и перезапуск контейнера
- Копирование данных в обе стороны
- Логи приложения в контейнере
- Полная информация по контейнеру
- Изменение параметров запуска контейнера
- Изменение лимитов CGroups
- Работа с репозиториями на hub.docker.com
- Известные проблемы и особенности
- Дополнительные рекомендации
Основы использования Docker
Зачем вообще Docker
Кроме того, что это “модно и молодежно”, для многих разработчиков или админов это весьма удобный инструмент. Но и как у любого инструмента есть свои минусы. Под капотом у Docker’а те же механизмы ядра Linux, что и у LXC - namespaces, CGroups и т.п. То есть все то же самое, чем пользуются LXC и OpenVZ. Из преимуществ разве что много разных плюшек в CLI, которых нет в LXC или в OpenVZ.
Установка
Ставим по официальному мануалу. Учтите, что между минорными версиями (например 1.8 и 1.10) может быть весьма большая разница в функционале. Подробнее можно прочитать на github в Changelog или на странице с релизами.
Проверка после установки
После установки проверяем, что демон запущен:
# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2025-07-04 10:21:42 MSK; 8h ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 3050 (dockerd)
Tasks: 21
Memory: 118.3M
CPU: 5.150s
CGroup: /system.slice/docker.service
└─3050 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
...
Возможности Docker CLI
Управление сводится к использованию утилиты docker
с указанием режима. В любой момент можно посмотреть нужную опцию, запустив docker с аргументом --help
. Более подробно как обычно в man страницах (например “man docker-images” для опций по docker images) или в официальной документации.
Образы контейнеров
Начальное состояние
В самом начале у нас нет ни запущенных контейнеров, ни загруженных образов:
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
Поиск образов
Поэтому ищем нужный нам образ. Например nginx:
$ docker search nginx | head -n 5
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 20875 [OK]
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo… 108
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGIN… 51
nginx/unit This repository is retired, use the Docker o… 65
Более подробная информация по доступным образам есть в Docker Hub.
Скачивание образа
Дальше скачиваем образ и проверяем его доступность локально:
$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
fdd5d7827f33: Pull complete
a3ed95caeb02: Pull complete
716f7a5f3082: Pull complete
7b10f03a0309: Pull complete
Digest: sha256:f6a001272d5d324c4c9f3f183e1b69e9e0ff12debeb7a092730d638c33e0de3e
Status: Downloaded newer image for nginx:latest
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest af4b3d7d5401 3 weeks ago 190.5 MB
Работа с контейнерами
Ниже примеры наиболее полезных действий, остальное смотрите в docker --help
.
Запуск контейнера
Чаще всего используют docker run
для создания и запуска контейнера. Пример на упомянутом ранее контейнере nginx:
Важно: Если не указать always
для опции --restart
, то контейнер не будет перезапускаться в случае сбоя и не будет автоматически запущен после перезагрузки сервера.
$ docker run --name some-nginx -v /var/www:/usr/share/nginx/html:ro -p 80:80 -p 443:443 --restart=always -d nginx
920683cf8ca54624f6bab551a89c8445208d52061d501669f7cbf14ae63c0c4a
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920683cf8ca5 nginx "nginx -g 'daemon off" 16 seconds ago Up 15 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp some-nginx
Полную информацию о созданном контейнере можно посмотреть при помощи docker inspect
.
Проброс портов и каталогов
В примере выше мы из образа nginx запустили контейнер с названием some-nginx
. Дополнительно мы пробросили папку /var/www
на хостовой системе внутрь контейнера как /usr/share/nginx/html
. И тут же активировали проброс портов 80/tcp и 443/tcp:
# netstat -nlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1027/sshd
tcp6 0 0 :::80 :::* LISTEN 3713/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 1027/sshd
tcp6 0 0 :::443 :::* LISTEN 3706/docker-proxy
Тестирование доступа
Создаем тестовый файл и проверяем доступ:
# uptime > /var/www/uptime.txt
# curl http://127.0.0.1/uptime.txt
15:39:05 up 1:32, 2 users, load average: 0.00, 0.01, 0.05
Аналогичным образом внутрь контейнера можно пробросить и конфиги. В нашем случае nginx.conf
нужно прокинуть внутрь контейнера как /etc/nginx/nginx.conf
. Подробности по каждому из контейнеров, а также какие конфиги куда “положить” - проверяйте в Docker Hub.
Внутри контейнера
Подключение к контейнеру
Смотрим что внутри контейнера:
root@ubuntu-512mb-ams3-01:~# docker exec -ti some-nginx bash
root@920683cf8ca5:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.5 31596 2828 ? Ss 19:31 0:00 nginx: master process nginx -g daemon off;
nginx 6 0.0 0.3 31972 1704 ? S 19:31 0:00 nginx: worker process
root 7 2.5 0.3 20212 1872 ? Ss 19:32 0:00 bash
root 11 0.0 0.2 17492 1152 ? R+ 19:32 0:00 ps aux
root@920683cf8ca5:/# ls -l /usr/share/nginx/html/
total 4
-rw-r--r-- 1 root root 62 Apr 3 19:39 uptime.txt
root@920683cf8ca5:/# netstat -nlp
bash: netstat: command not found
root@7d06e0aad2cd:/# exit
То есть по факту внутри контейнера запущен лишь nginx и наш шелл. И обратите внимание, что многих “привычных” команд зачастую нет и не будет в образах (речь про netstat
).
Альтернативный способ просмотра процессов
Есть более простой вариант посмотреть что работает внутри:
$ docker top some-nginx
UID PID PPID C STIME TTY TIME CMD
root 3936 2924 0 15:44 ? 00:00:00 nginx: master process nginx -g daemon off;
sshd 3946 3936 0 15:44 ? 00:00:00 nginx: worker process
Статус, остановка и перезапуск контейнера
Просмотр запущенных контейнеров
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920683cf8ca5 nginx "nginx -g 'daemon off" 9 minutes ago Up 9 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp some-nginx
Остановка контейнера
$ docker stop some-nginx
some-nginx
Проверка статуса
Проверяем запущенные, потом смотрим все (в т.ч. и остановленные):
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920683cf8ca5 nginx "nginx -g 'daemon off" 9 minutes ago Exited (0) 3 seconds ago some-nginx
Запуск и перезапуск
$ docker start some-nginx
some-nginx
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920683cf8ca5 nginx "nginx -g 'daemon off" 10 minutes ago Up 1 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp some-nginx
$ docker restart some-nginx
some-nginx
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920683cf8ca5 nginx "nginx -g 'daemon off" 10 minutes ago Up 1 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp some-nginx
Копирование данных в обе стороны
Важно: Учтите, что контейнеры чаще всего недолговечны и могут быть удалены/пересозданы в любой момент. И выживут только файлы и папки, “проброшенные” в контейнер с хостовой системы.
Копирование в контейнер
Создаем тестовый файл и копируем в контейнер:
# dmesg > test.txt
# ls -l test.txt
-rw-r--r-- 1 root root 36815 Apr 3 15:48 test.txt
# docker cp test.txt some-nginx:/root/
# docker exec -ti some-nginx bash
root@920683cf8ca5:/# ls -l /root/test.txt
-rw-r--r-- 1 root root 36815 Apr 3 19:48 /root/test.txt
Копирование из контейнера
Теперь создадим файл внутри контейнера и скопируем его в хостовую систему:
root@920683cf8ca5:/# ps aux > /root/ps.txt
root@920683cf8ca5:/# exit
# docker cp some-nginx:/root/ps.txt /root/
# ls -l /root/ps.txt
-rw-r--r-- 1 root root 410 Apr 3 15:49 /root/ps.txt
# cat /root/ps.txt
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.5 31596 2828 ? Ss 19:44 0:00 nginx: master process nginx -g daemon off;
nginx 6 0.0 0.3 31972 1704 ? S 19:44 0:00 nginx: worker process
root 7 0.3 0.3 20216 1932 ? Ss 19:49 0:00 bash
root 13 0.0 0.2 17492 1152 ? R+ 19:49 0:00 ps aux
Логи приложения в контейнере
Как правило контейнеры создаются только ради одного приложения. Логи приложения можно посмотреть командой:
docker logs --tail=30 -t container_name
Опции:
--tail=30
- вывод последних 30 строк лога-t
- добавлять timestamp
Мониторинг логов в реальном времени
Чтобы следить за логом в реальном времени (как tail -f
):
docker logs -f -t container_name
Подробнее здесь
Полная информация по контейнеру
Получить полную информацию по контейнеру можно с помощью команды:
docker inspect name
Много json данных, из которых нас как правило будут интересовать:
- параметры запуска - Args
- параметры сети и пробрасываемых портов - PortBindings
- примонтированные файлы и папки - Binds
Пример вывода docker inspect
[
{
"Id": "69cf22b27cda0719c58c33322d759e4114549446c291724d2a6508cfc7bd10ee",
"Created": "2025-01-22T14:33:19.392229731Z",
"Path": "docker-entrypoint.sh",
"Args": [
"--replSet",
"rs0",
"--keyFile",
"/etc/custom-mongo/mongo-keyfile",
"--auth",
"--wiredTigerCacheSizeGB",
"50"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 3178412,
"ExitCode": 0,
"Error": "",
"StartedAt": "2025-05-16T20:17:51.183141305Z",
"FinishedAt": "2025-05-16T20:13:19.330081207Z"
},
"HostConfig": {
"Binds": [
"/mnt/docker/mongodb7/data:/data/db:rw",
"/mnt/docker/mongodb7/etc/:/etc/custom-mongo:ro"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
"compress": "false",
"max-file": "10",
"max-size": "50m"
}
},
"NetworkMode": "bridge",
"PortBindings": {
"27017/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "27017"
}
]
}
}
}
]
Изменение параметров запуска контейнера
Нужно пересоздавать выполнить пересоздание контейнера, для изменения параметров запуска.
Если есть конкретная команда, которая использовалась для запуска контейнера, это сильно поможет. В большинстве случаев в этом может помочь history
.
Пример пересоздания
# если необходимо смотрим текущие параметры
docker inspect name
# удаляем контейнер
docker rm name
# создаем с новыми параметрами
docker run --restart=always -d --name name <new parameters>
Указывается --restart=always -d
так как в большинстве случаев эти параметры необходимы.
Изменение лимитов CGroups
Информацию о настройке лимитов Docker можно посмотреть в мане. Для понимания что какой ключ делает созданы 2 таблицы.
Лимиты памяти
Ключ Docker | Какой лимит cgroups меняет |
---|---|
-m или --memory | memory.limit_in_bytes |
--memory-swap | memory.memsw.limit_in_bytes |
--memory-swappiness | memory.swappiness |
--memory-reservation | memory.soft_limit_in_bytes |
--oom-kill-disable | memory.oom_control |
--kernel-memory | memory.kmem.limit_in_bytes |
Лимиты CPU и диска
Ключ Docker | Какой лимит cgroups меняет |
---|---|
--cpu-shares | cpu.shares |
--cpus (в более ранних версиях docker --cpu-period и --cpu-quota ) | cpu.cfs_period_us и cpu.cfs_period_us |
--blkio-weight | blkio.weight |
Применение лимитов
Эти ключи указываются при создании контейнера. Для ключей --memory
и --cpus
(--cpu-period
+ --cpu-quota
) значения лимита указываются через знак равно. Для остальных лимиты указываются через пробел.
Можно также на ходу понизить, повысить или задать жесткий лимит для контейнера (правда набор меньше - docker update --help
в помощь).
Пример изменения лимитов
# docker update --blkio-weight 200 --cpu-shares 100 some-nginx
some-nginx
# cat /sys/fs/cgroup/cpu/docker/69cf22b27cda0719c58c33322d759e4114549446c291724d2a6508cfc7bd10ee/cpu.shares
100
# cat /sys/fs/cgroup/blkio/docker/69cf22b27cda0719c58c33322d759e4114549446c291724d2a6508cfc7bd10ee/blkio.weight
200
Важно: Учтите, что эти изменения временные. Для постоянных лимитов нужно указывать эти опции при создании контейнера.
Работа с репозиториями на hub.docker.com
Авторизация
Сначала нужно залогиниться:
docker login
Будет запрос имени пользователя (не email, а именно имя пользователя) и пароля. После этого можно работать с приватными репозиториями, к которым есть доступ у вашего аккаунта.
Работа с образами
Например, стягивать images и работать с ними:
docker pull user/repo
Известные проблемы и особенности
Не пользуйтесь
docker attach
, т.к. не всегда работает сочетание клавиш для detach. А нажатие Ctrl+C может “остановить” весь контейнерПо умолчанию docker демон сам управляет правилами в iptables, но это отключаемо
Дополнительные рекомендации
- Изучите официальную документацию Docker
- Используйте
docker --help
для получения справки по командам - Всегда проверяйте статус контейнеров после внесения изменений
- Помните о важности правильного управления данными в контейнерах
- Используйте переменные окружения для конфигурации приложений