Linux для админа Windows 10. Docker для начинающих: контейнеры, тома, compose
Note
Материал сверен с официальной документацией (Ubuntu Server, man-страницы и документация проектов; ссылки — в конце статьи). Примеры вывода — иллюстрации: на вашем сервере значения и формат могут отличаться. Перед работой на боевом сервере проверьте команды на тестовой машине.
Чтобы изолировать приложение в Windows, мы создаём виртуальную машину (ВМ) Hyper-V: у неё свой диск, своё ядро и полная ОС. Docker решает ту же задачу легче: приложение запускается в изолированном процессе, который называется контейнером, и использует ядро самого сервера (в Docker его называют хостом). Поэтому на одном сервере помещается больше приложений, чем виртуальных машин. В статье мы:
- установим Docker Engine на Ubuntu Server по инструкции Docker;
- запустим первый контейнер и разберём основные команды;
- научимся хранить данные так, чтобы они не пропадали вместе с контейнером;
- опишем приложение из двух контейнеров в файле
compose.yaml; - разберём безопасность: именно здесь у новичков бывают самые неприятные сюрпризы.
Речь только о контейнерах Linux. Сопоставим понятия:
| Hyper-V | Docker |
|---|---|
| Виртуальная машина: своё ядро и полная ОС | Контейнер: изолированный процесс на ядре хоста |
| Диск ВМ или шаблон, из которого создают машины | Образ (image): неизменяемый шаблон из слоёв |
| Хранилище шаблонов | Реестр (registry), по умолчанию Docker Hub |
| Виртуальный коммутатор | Сеть Docker (bridge) |
| Виртуальный диск, подключённый к ВМ | Том (volume) или каталог хоста (bind mount) |
| Описание стенда, из которого создаются несколько ВМ (вы описываете результат, а не шаги) | Файл compose.yaml |
Что нужно знать заранее
- Файловая система, диски и права доступа: группы, владельцы, числовые идентификаторы пользователя и группы (UID и GID).
- Пакеты и обновления: apt: репозитории и ключи.
- Службы и процессы: systemd, journalctl, cron: служба
dockerуправляется черезsystemctl. - Сеть в Linux: Netplan, ip, DNS и брандмауэр ufw: порты и
ufw. Без этого раздел о безопасности будет непонятен. - Веб-сервер nginx: сайт, обратный прокси, логи: nginx послужит нам примером контейнера.
Контейнер, образ, реестр
Образ — неизменяемый набор файлов: программа, библиотеки, настройки. Он состоит из слоёв, каждый из которых описывает изменения файловой системы. Контейнер — запущенный экземпляр образа со своим изменяемым слоем поверх него. Из одного образа можно запустить много контейнеров.
Образы хранятся в реестре; по умолчанию это Docker Hub. Имя образа выглядит так: nginx:1.30-alpine, то есть репозиторий и тег (версия или вариант). Если тег не указан, Docker берёт latest. Использовать его не стоит: через полгода тот же запуск принесёт другую версию программы.
Docker устроен как клиент и сервер. Команда docker — клиент, а демон dockerd (фоновая служба) работает от имени root и делает всю работу. Клиент общается с ним через сокет (специальный файл для связи программ) /var/run/docker.sock: к нему имеют доступ root и члены группы docker.
Docker Engine — сервер для Linux, его мы и ставим. Docker Desktop — отдельное приложение для рабочих станций.
Установка Docker Engine на Ubuntu
Ставим по инструкции docs.docker.com. Она поддерживает, в том числе, выпуски с долгой поддержкой (LTS) 24.04 и 26.04.
Warning
Прочитайте раздел о безопасности ниже до первого запуска. Docker меняет правила брандмауэра, и ufw не защищает опубликованные порты контейнеров.
Сначала удалите конфликтующие пакеты. В репозитории Ubuntu есть свой docker.io; Docker относит его и ещё несколько пакетов (в том числе docker-compose и docker-compose-v2) к неофициальным и просит удалить перед установкой. Не смешивайте два источника.
sudo apt remove $(dpkg --get-selections docker.io \
docker-compose docker-compose-v2 docker-doc docker-buildx \
podman-docker containerd runc | cut -f1)
apt может сообщить, что этих пакетов у вас нет: это нормально. Затем подключаем репозиторий Docker: ключ кладём в /etc/apt/keyrings, источник описываем в формате deb822 (устройство источников и ключей — в статье про apt):
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
Устанавливаем пакеты: docker-ce — демон, docker-ce-cli — команда docker, containerd.io — среда запуска контейнеров, docker-buildx-plugin — сборка образов, docker-compose-plugin — команда docker compose.
sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl status docker
sudo docker run hello-world
Образ hello-world скачивается, печатает приветствие и завершается. Пример вывода (начало):
Hello from Docker!
This message shows that your installation appears to be working correctly.
Обновляется Docker обычным путём через apt. Есть и «удобный скрипт» get.docker.com, но сам Docker рекомендует его только для тестовых сред и просит читать скачанные скрипты перед запуском. Не запускайте его на боевом сервере, не прочитав.
Первые команды
В примерах мы публикуем порты на 8081: порт 127.0.0.1:8080 мог остаться занятым учебным сайтом backend из статьи про nginx, и контейнер на нём не запустится. Запустим nginx в контейнере:
sudo docker run -d --name web \
-p 127.0.0.1:8081:80 nginx:1.30-alpine
Эту конструкцию вы будете писать чаще всего:
| Опция | Значение |
|---|---|
-d |
Запустить в фоне и вывести идентификатор контейнера |
--name web |
Своё имя вместо случайного |
-p 127.0.0.1:8081:80 |
Порт 8081 хоста на адресе 127.0.0.1 соединить с портом 80 контейнера |
-e ИМЯ=значение |
Передать переменную окружения |
-v, --mount |
Подключить том или каталог хоста |
--restart unless-stopped |
Политика перезапуска |
--rm |
Удалить контейнер после завершения |
-i -t |
Интерактивный сеанс с терминалом |
Адрес 127.0.0.1 перед портом — это не украшение, а защита; подробности ниже. Проверяем:
sudo docker ps
curl -I http://127.0.0.1:8081
Пример вывода docker ps (часть столбцов опущена):
CONTAINER ID IMAGE STATUS PORTS
2f6a1c0d9e11 nginx:1.30-alpine Up 12 seconds 127.0.0.1:8081->80/tcp
| Команда | Что делает |
|---|---|
docker ps -a |
Все контейнеры, включая остановленные |
docker logs -f --tail 20 web |
Последние строки вывода контейнера и слежение за ним |
docker exec -it web sh |
Запустить в работающем контейнере оболочку |
docker stop web, docker start web |
Остановить (сигнал SIGTERM, затем SIGKILL) и снова запустить |
docker rm web |
Удалить остановленный контейнер |
docker images, docker pull |
Список образов; скачать образ |
Контейнер одноразовый: всё, что приложение записало внутрь него, исчезает при docker rm. Данные, которые нужно сохранить, хранят в томах.
Политика --restart решает, что делать, когда контейнер завершился. no (по умолчанию) не перезапускает; on-failure перезапускает после ошибки; always и unless-stopped перезапускают всегда, но unless-stopped не поднимает контейнер после перезапуска демона, если вы остановили его вручную. Для служб обычно берут unless-stopped.
Остановим и удалим контейнер: sudo docker stop web && sudo docker rm web.
Тома и каталоги хоста
Контейнер может хранить файлы в трёх местах:
- слой контейнера исчезает вместе с контейнером;
- том (volume) — каталог под управлением Docker, живёт отдельно от контейнеров. На хосте он лежит в
/var/lib/docker/volumes/<имя>/_data; - bind mount — каталог или файл хоста, подключённый в контейнер.
Документация считает тома предпочтительным способом хранить данные: их проще копировать и переносить. Bind mount нужен, когда файлы должны быть доступны и хосту, например конфигурация или каталог сайта. Покажем, что данные в томе переживают контейнеры (в учебных командах с alpine тег опущен ради краткости):
admin-lab@lnx1:~$ sudo docker volume create app-data
admin-lab@lnx1:~$ sudo docker run --rm -v app-data:/data alpine \
sh -c 'echo saved > /data/test.txt'
admin-lab@lnx1:~$ sudo docker run --rm -v app-data:/data alpine \
cat /data/test.txt
saved
Оба контейнера удалены (--rm), а файл остался в томе app-data. Тома показывают docker volume ls и docker volume inspect. Теперь каталог сайта с хоста, подключённый только для чтения (:ro):
sudo mkdir -p /srv/site
echo '<h1>Hello from a bind mount</h1>' | sudo tee /srv/site/index.html
sudo docker run -d --name web -p 127.0.0.1:8081:80 \
-v /srv/site:/usr/share/nginx/html:ro nginx:1.30-alpine
Каталог /usr/share/nginx/html — то место, откуда образ nginx отдаёт страницы. Что важно знать про bind mount:
- по умолчанию контейнер может писать в подключённый каталог хоста: менять и удалять там файлы. Для неизменяемых данных добавляйте
:ro; - права проверяет ядро хоста по числовым UID и GID, а не по именам: имя пользователя внутри контейнера не важно (в образе nginx рабочие процессы запускаются с UID 101);
- подключённый каталог закрывает собой то, что лежало в этом месте образа;
- если пути на хосте нет,
-vмолча создаст каталог, даже когда вы имели в виду файл. Опция--mount type=bind,...в этом случае выдаст ошибку.
Удалите контейнер командой sudo docker rm -f web: опция -f позволяет удалить и работающий.
Сети
Контейнеры подключаются к виртуальным сетям внутри сервера (тип bridge — аналог виртуального коммутатора). Из внешней сети в контейнер можно попасть только через опубликованный порт (-p). Compose создаёт для проекта отдельную сеть, где службы находят друг друга по имени и обычному порту приложения; публиковать порты для этого не нужно. У каждого контейнера свой сетевой стек, поэтому localhost внутри него означает сам этот контейнер; службу на хосте вызывают по адресу хоста.
Docker Compose: приложение из двух контейнеров
Длинные команды docker run неудобно хранить и повторять. Docker Compose описывает приложение в файле compose.yaml: какие службы (services) запускать, из каких образов, с какими портами и томами. Файл можно хранить в системе контроля версий, а запускать одной командой. Это описание стенда, по которому его разворачивают заново.
Вызывайте docker compose (через пробел: это плагин docker-compose-plugin). Не путайте его со старой программой docker-compose через дефис.
Сделаем приложение из двух контейнеров: web (nginx в роли обратного прокси) и app (простой веб-сервер на Python в роли «приложения»). Наружу, и только на 127.0.0.1, опубликован один web.
mkdir -p ~/lab-app/nginx ~/lab-app/app
cd ~/lab-app
echo '<h1>Hello from the app</h1>' > app/index.html
nano nginx/default.conf
Содержимое nginx/default.conf:
server {
listen 80;
location / {
proxy_pass http://app:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Адрес app здесь — это имя службы из compose.yaml. Создайте файл compose.yaml (nano compose.yaml) в ~/lab-app:
services:
web:
image: nginx:1.30-alpine
ports:
- "127.0.0.1:8081:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
app:
condition: service_started
restart: true
restart: unless-stopped
app:
image: python:3.13-alpine
command: ["python", "-m", "http.server", "8000", "--directory", "/srv/app"]
volumes:
- ./app:/srv/app:ro
restart: unless-stopped
ports— строка в кавычках, адрес127.0.0.1указан явно. Без него порт будет опубликован на всех интерфейсах;- у
appнетports: до него можно дойти только по сети Compose, по имениappи порту 8000; depends_onзадаёт порядок:appсоздаётся раньшеweb. ГотовностиappCompose не ждёт:service_startedгарантирует лишь запуск контейнера. Строкуrestart: trueразберём в разделе об обновлении;- пути в
volumesначинаются с./: так Compose отличает каталог хоста от имени тома; - версии образов закреплены до ветки (
3.13,1.30): исправления внутри ветки придут приdocker compose pull. Для полной фиксации указывайте полный тег и меняйте его сами.
Запускаем из каталога ~/lab-app:
sudo docker compose config
sudo docker compose up -d
sudo docker compose ps
docker compose config проверяет файл и показывает итоговую конфигурацию. Пример вывода docker compose ps (часть столбцов опущена):
NAME SERVICE STATUS PORTS
lab-app-app-1 app Up 5 seconds
lab-app-web-1 web Up 5 seconds 127.0.0.1:8081->80/tcp
Имя проекта (lab-app) Compose берёт из имени каталога. Проверка:
admin-lab@lnx1:~/lab-app$ curl http://127.0.0.1:8081/
<h1>Hello from the app</h1>
| Команда | Что делает |
|---|---|
docker compose up -d |
Создать и запустить службы; изменившиеся пересоздаются, тома сохраняются |
docker compose logs -f --tail 20 web |
Журнал службы |
docker compose exec web nginx -s reload |
Выполнить команду в работающей службе |
docker compose pull |
Скачать новые версии образов |
docker compose down |
Удалить контейнеры и сеть проекта |
down не удаляет именованные тома: данные остаются. Опция down -v удалит и тома, и данные.
Чтобы показать приложение сети, на хосте настраивают nginx, как в статье про nginx. Контейнер остаётся доступным только через него:
server {
listen 80;
server_name lab-app.lab.example;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Когда закончите, уберите стенд: он перезапускается вместе с сервером (restart: unless-stopped) и занимает порт 8081. Если вы включали сайт на хостовом nginx, отключите и его (sudo rm ссылки в sites-enabled, затем nginx -t и reload).
cd ~/lab-app
sudo docker compose down
sudo docker volume rm app-data
sudo rm -r /srv/site
Обновление образов и очистка
Образ не обновляется сам, и работающие контейнеры продолжают использовать старый. Обновление: sudo docker compose pull, затем sudo docker compose up -d; пересоздаются те службы, у которых образ изменился.
Если обновился только app, он получает новый IP-адрес, а имя службы остаётся прежним. nginx разрешает имя из proxy_pass при чтении конфигурации (при запуске и при reload), поэтому web продолжил бы ходить на старый адрес и отвечать 502. Параметр restart: true в depends_on заставляет Compose перезапускать web после обновления app. Без него выполните sudo docker compose exec web nginx -s reload или sudo docker compose restart web.
Старые образы занимают место. Сколько занято образами, контейнерами и томами, показывает sudo docker system df. Освободить место помогают:
sudo docker image pruneудаляет «висячие» образы (без тега); с опцией-a— все образы, не используемые ни одним контейнером;sudo docker system pruneудаляет остановленные контейнеры, неиспользуемые сети, «висячие» образы и кэш сборки; с--volumesзатрагивает и анонимные тома.
Обе команды спрашивают подтверждение: читайте список и не добавляйте -f, пока не поймёте последствия.
Вторая «утечка» места — журналы. Docker по умолчанию пишет вывод контейнеров в файлы JSON без ротации, и разговорчивый контейнер может заполнить диск. Ограничить размер можно в /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Перед перезапуском проверьте файл: sudo dockerd --validate --config-file=/etc/docker/daemon.json (при успехе команда отвечает configuration OK). Ошибка в JSON не даст демону запуститься, и все контейнеры останутся остановленными. Затем перезапустите службу в окно обслуживания: sudo systemctl restart docker. Настройки действуют только на вновь созданные контейнеры.
Безопасность: что нужно знать до первого запуска
Группа docker — это root
Демон работает от root. Кто может им управлять, тот может запустить контейнер с подключённым корнем файловой системы хоста и менять там что угодно. Поэтому документация предупреждает: группа docker даёт права root. Команда sudo usermod -aG docker admin-lab из руководства по настройке после установки фактически делает пользователя администратором сервера. Добавляйте в группу только тех, у кого и так есть sudo. Если права root недопустимы, у Docker есть режим rootless (демон и контейнеры работают без прав root).
Опубликованные порты обходят ufw
ufw — надстройка над iptables, то есть над правилами фильтрации пакетов в ядре Linux (статья про ufw). Правила собраны в цепочки: в INPUT проверяются пакеты, адресованные самому серверу, а таблица nat подменяет адреса и порты. Docker направляет трафик контейнеров через таблицу nat, и пакеты уходят в контейнер раньше, чем попадают в цепочки INPUT и OUTPUT, на которых работает ufw. Поэтому ufw deny 8081 порт не закроет, а ufw status покажет только ваше правило и ничего не скажет о правилах Docker.
Документация называет публикацию портов небезопасной по умолчанию: -p 8081:80 без адреса открывает порт на всех интерфейсах сервера. Как ограничить доступ:
- Публиковать только на
127.0.0.1:-p 127.0.0.1:8081:80вdocker runи"127.0.0.1:8081:80"в Compose. Это решение по умолчанию. Наружу приложение показывает nginx на хосте, а администратор заходит через SSH-туннель. Нужен Docker Engine 28.0.0 или новее: в более ранних выпусках узлы из того же сегмента сети могли достучаться до портов, опубликованных на петлевом интерфейсе (loopback). Адрес по умолчанию можно менять в настройках демона, но ключipвdaemon.jsonдействует только для стандартной сетиbridge, а не для сетей Compose, поэтому адрес надёжнее указывать в каждом-pиports. - Привязать к адресу внутренней сети:
-p 192.168.10.20:8081:80. Порт будет слушать только на этом адресе сервера. - Ограничить источники правилом
iptables. Для ваших правил Docker предусмотрел цепочкуDOCKER-USER, которую обрабатывают раньше его собственных (примеры — на странице «Docker with iptables» документации). Но правила, добавленные командойiptables, действуют до перезагрузки сервера: если не настроить их восстановление, после неё порты снова откроются для всех, аufw statusэтого не покажет. Поэтому считайте этот способ дополнительным слоем, основными остаются способы 1 и 2, а порты проверяйте снаружи после каждой перезагрузки.
Проверяйте снаружи, например с PC1. Если порт закрыт, TcpTestSucceeded будет False:
Test-NetConnection 192.168.10.20 -Port 8081
Не открывайте API демона и панели управления
По умолчанию демон слушает только Unix-сокет. Открыть его по TCP можно только с TLS (шифрованием): в актуальных выпусках (Docker 28 и новее) демон без TLS на сетевом TCP-адресе не запускается, а раньше такой порт позволял удалённому пользователю получить root на хосте. Брандмауэр не уберегает от обращений из контейнеров. Для удалённого управления используйте SSH: DOCKER_HOST=ssh://пользователь@хост. Пользователь должен иметь доступ к сокету, то есть фактически права root (см. выше про группу docker); о настройке SSH — в статье про SSH.
То же верно для веб-панелей управления контейнерами и любого контейнера с подключённым /var/run/docker.sock: доступ к сокету равен управлению демоном, то есть правам root. Не публикуйте такие панели в интернет, держите их во внутренней сети или за VPN.
Не используйте --privileged
Опция включает все возможности ядра, отключает профили seccomp (фильтр системных вызовов) и AppArmor (мандатный контроль доступа), открывает все устройства хоста. По документации, такой контейнер не изолирован и может получить оболочку root на хосте. Если нужна одна привилегия, выдавайте её точечно (--cap-add, --device). Docker рекомендует убирать все возможности, кроме явно нужных. Если приложение позволяет, запускайте его не от root (--user) и с файловой системой только для чтения (--read-only).
Базы данных и служебные порты — не наружу
Приложение обращается к базе данных по имени службы внутри сети Compose, публиковать её порт не нужно. Для администрирования публикуйте порт на 127.0.0.1 и подключайтесь через SSH-туннель.
Образы и секреты
- Берите образы из доверенных источников: Docker Official Images, Verified Publisher, Docker-Sponsored Open Source. Происхождение неизвестного образа вы не проверите.
- Не запускайте из интернета команды
docker runбез разбора:--privilegedили-v /:/hostсводят изоляцию на нет. - Закрепляйте версии (
nginx:1.30-alpine, а неlatest) и регулярно обновляйте образы: исправления уязвимостей приходят с новым образом. - Не вшивайте пароли и ключи в образ и в
compose.yamlиз репозитория. Compose умеет передавать секреты файлами в/run/secrets/; это надёжнее переменных окружения, которые легко попадают в журналы.
Типичные ошибки и недоразумения
- «Закрыл порт в ufw, а он открыт». Опубликованные порты Docker обходит
ufw. Публикуйте на127.0.0.1. - Данные пропали. Они лежали в слое контейнера, а не в томе. Или выполнили
docker compose down -vлибоdocker volume prune -a. - Обновили образ, а работает старая версия.
docker pullне трогает запущенные контейнеры: нуженdocker compose up -d. А сlatestверсия может смениться при любом запуске. - После обновления
appсайт отвечает 502. Прокси запомнил старый адрес: перезагрузите его (docker compose exec web nginx -s reload) или используйтеrestart: true. - Вместо файла создался каталог. Пути для bind mount не было, и Docker создал каталог. Создайте файл до запуска.
- Правка конфигурации nginx не действует. Её читают при старте: перезагрузите (
docker compose exec web nginx -s reload). - Диск заполнился. Журналы контейнеров без ротации, неиспользуемые образы: смотрите
docker system df. - Без
sudoжалуется на~/.docker. Каталог создан под root, пока вы запускали команды черезsudo. Исправьте владельца командойchown, как описано в руководстве Docker.
Проверьте себя
- Контейнер запущен как
-p 5432:5432, аufwзапрещает входящие соединения. Достижим ли порт из офисной сети? Что изменить? Достижим: Docker направляет трафик в контейнер раньше правилufw. Публикуйте порт на127.0.0.1(или на адресе внутренней сети), а базу не публикуйте вовсе. - Чем том отличается от bind mount и что происходит с данными при
docker rm? Том создаёт и хранит Docker, bind mount — каталог или файл хоста. Данные в слое контейнера пропадают приdocker rm, данные в томе и каталоге хоста остаются. - Что делает
docker compose downи чем опасен-v? Удаляет контейнеры и сеть проекта, но не именованные тома. С-vтома тоже удаляются, и данные теряются. - Почему членство в группе
dockerравносильно правам root? Демон работает от root, а доступ к его сокету позволяет запускать контейнеры с подключённым корнем файловой системы хоста. - Как
webобращается кappв одном проекте Compose и нужно ли публиковать портapp? По имени службы (http://app:8000): Compose создаёт общую сеть, где службы видят друг друга по имени. Публиковать портappне нужно.
Что дальше
- Веб-сервер nginx: сайт, обратный прокси, логи — nginx на хосте как точка входа для контейнеров, порты которых опубликованы на
127.0.0.1. - Сеть в Linux: Netplan, ip, DNS и брандмауэр ufw — как проверять открытые порты и что делает
ufw. - SSH: ключи, безопасная настройка и передача файлов — входы по ключам и туннели
-Lк закрытым портам; по тому же SSH работаетDOCKER_HOST=ssh://…. - Диагностика сети в Windows: ping, tracert, nslookup и другие — как искать причину, если порт или имя с компьютера Windows недоступны.
Серия на этом закончена. Дальше стоит разобраться с резервным копированием данных контейнеров (тома), HTTPS-сертификатами и мониторингом сервера: подробно об этом — отдельные статьи позже.
Источники
- Docker: Install Docker Engine on Ubuntu — конфликтующие пакеты, репозиторий Docker, установка, проверка, предупреждение о брандмауэре
- Docker: Linux post-installation steps — группа
dockerи права root, ошибка прав на~/.docker - Docker: Packet filtering and firewalls — Docker и ufw
- Docker: Docker with iptables — цепочка
DOCKER-USER - Docker: Port publishing and mapping — публикация портов, привязка к адресу, ключ
ip - Docker: docker container run — опции
docker run,--privileged, политики перезапуска - Docker: Volumes — тома и их жизненный цикл
- Docker: Bind mounts — каталоги хоста,
ro, создание отсутствующего пути - Docker: Compose file reference, services —
ports,volumes,depends_on(restart: true),restart - Docker: Networking in Compose — сеть проекта, имена служб, новый адрес пересозданного контейнера
- Docker: Docker Engine security — поверхность атаки демона, возможности ядра, доступ по SSH
- Docker: Configure logging drivers — журналы без ротации,
max-size - Docker: Trusted content — Docker Official Images и другие доверенные источники
- Docker: Manage secrets in Compose — секреты в
/run/secrets/ - Docker Official Images: nginx — каталог
/usr/share/nginx/html, настройка конфигурации