Основы Docker: полное руководство по работе с контейнерами - docs.devboxops.com

Основы Docker: полное руководство по работе с контейнерами

Полное руководство по Docker для начинающих: от установки до управления контейнерами

Основы использования 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 или --memorymemory.limit_in_bytes
--memory-swapmemory.memsw.limit_in_bytes
--memory-swappinessmemory.swappiness
--memory-reservationmemory.soft_limit_in_bytes
--oom-kill-disablememory.oom_control
--kernel-memorymemory.kmem.limit_in_bytes

Лимиты CPU и диска

Ключ DockerКакой лимит cgroups меняет
--cpu-sharescpu.shares
--cpus (в более ранних версиях docker --cpu-period и --cpu-quota)cpu.cfs_period_us и cpu.cfs_period_us
--blkio-weightblkio.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 для получения справки по командам
  • Всегда проверяйте статус контейнеров после внесения изменений
  • Помните о важности правильного управления данными в контейнерах
  • Используйте переменные окружения для конфигурации приложений

Ссылки

Top