Docker на Ubuntu: Повний посібник з встановлення та використання
Docker — це платформа контейнеризації з відкритим вихідним кодом, яка пакує застосунки та їхні залежності в ізольовані, портативні одиниці, що називаються контейнерами. На відміну від віртуальних машин, контейнери спільно використовують ядро ОС хоста, що робить їх значно легшими, швидшими при запуску та ефективнішими з точки зору ресурсів — критична відмінність для тих, хто запускає навантаження в середовищі VPS Hosting, де обчислювальні ресурси безпосередньо впливають на вартість і продуктивність.
Цей посібник охоплює повний процес встановлення Docker на Ubuntu 20.04, 22.04 та 24.04 LTS, включаючи посилення безпеки після встановлення, робочі процеси Docker Compose та виробничо-релевантні шаблони команд, які більшість посібників не згадує.
Передумови та системні вимоги
Перш ніж виконувати будь-яку команду, перевірте наступне:
- Версія Ubuntu: 20.04 LTS (Focal), 22.04 LTS (Jammy) або 24.04 LTS (Noble). Команда `lsb_release -cs`, що використовується під час налаштування репозиторію, автоматично визначить вашу кодову назву.
- Архітектура: `amd64`, `arm64` або `armhf` — усі підтримуються офіційним репозиторієм Docker.
- Версія ядра: Docker вимагає ядро Linux 3.10 або вище. Виконайте `uname -r` для підтвердження.
- Привілеї користувача: `sudo` або root-доступ є обов’язковими для встановлення та керування демоном.
- Дисковий простір: Щонайменше 2 GB вільного місця на розділі, де розміщено `/var/lib/docker`, — саме там Docker зберігає образи, контейнери, томи та кеш збірки. На виробничих системах змонтуйте цей каталог на окремому розділі або томі.
Критичний крок перед встановленням: Якщо ви раніше встановлювали Docker із стандартного репозиторію `apt` Ubuntu (пакет `docker.io`), спочатку видаліть його, щоб уникнути конфліктів з офіційними пакетами Docker CE:
“`bash
sudo apt remove docker docker-engine docker.io containerd runc
“`
Крок 1: Оновлення системних пакетів
Оновіть індекс пакетів та встановлені пакети до останніх версій перед додаванням будь-якого нового репозиторію:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Це гарантує, що резолвер залежностей `apt` працює з актуальними метаданими пакетів і що базові системні бібліотеки не застаріли — поширене джерело непомітних помилок виконання в контейнеризованих застосунках.
Крок 2: Встановлення Docker Engine з офіційного репозиторію
Стандартні репозиторії `apt` Ubuntu містять пакет `docker.io`, який підтримується Canonical і зазвичай відстає на кілька версій від офіційного релізу Docker. Для виробничого використання завжди встановлюйте з власного репозиторію Docker.
2.1 Встановлення транспорту та залежностей для перевірки
“`bash
sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y
“`
Навіщо `gnupg`? Починаючи з Ubuntu 22.04, `gpg` не завжди присутній за замовчуванням. Явне його включення запобігає тихому збою імпорту GPG-ключа.
2.2 Додавання офіційного GPG-ключа Docker
“`bash
sudo install -m 0755 -d /usr/share/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
“`
Крок `chmod a+r` часто пропускається в посібниках, але є необхідним на системах, де `apt` працює в контексті обмеженого користувача — без нього менеджер пакетів не може прочитати keyring і видасть помилку `NO_PUBKEY` під час `apt update`.
2.3 Додавання стабільного репозиторію Docker
“`bash
echo
"deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" |
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
“`
Підстановка `arch=$(dpkg –print-architecture)` є необхідною на ARM-серверах. Жорстке кодування `amd64` тут — поширена помилка, яка призводить до тихих збоїв розв’язання пакетів на ARM-інстансах.
2.4 Встановлення Docker Engine, CLI та плагінів
“`bash
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
“`
Опис пакетів:
| Пакет | Роль |
|---|
| — | — |
|---|
| `docker-ce` | Демон Docker Engine (`dockerd`) |
|---|
| `docker-ce-cli` | Клієнтський CLI (команда `docker`) |
|---|
| `containerd.io` | Низькорівневе середовище виконання контейнерів (сумісне з OCI) |
|---|
| `docker-buildx-plugin` | Розширені можливості збірки (мультиплатформенність, BuildKit) |
|---|
| `docker-compose-plugin` | Compose V2, інтегрований як плагін Docker CLI |
|---|
Примітка щодо `containerd.io`: Це не те саме, що пакет `containerd` у стандартному репозиторії Ubuntu. `containerd.io` від Docker — це конкретна, протестована версія середовища виконання containerd. Змішування двох є відомим джерелом збоїв запуску демона.
Крок 3: Перевірка встановлення
Підтвердіть, що демон активний і налаштований на запуск при завантаженні:
“`bash
sudo systemctl status docker
sudo systemctl enable docker
“`
Перевірте встановлену версію:
“`bash
sudo docker –version
sudo docker info
“`
`docker info` є більш інформативним, ніж `–version` окремо — він показує драйвер сховища (зазвичай `overlay2`), драйвер cgroup (`systemd` проти `cgroupfs`), а також кількість CPU та обсяг пам’яті, до яких Docker має доступ.
Запустіть канонічний димовий тест:
“`bash
sudo docker run hello-world
“`
Успішний запуск виводить повідомлення «Hello from Docker!» і підтверджує, що демон Docker, завантаження образу з Docker Hub та виконання контейнера — все працює коректно.
Крок 4: Налаштування Docker для доступу без root
За замовчуванням сокет Docker (`/var/run/docker.sock`) належить `root` та групі `docker`. Будь-який користувач, що не входить до групи `docker`, повинен використовувати `sudo` для кожної команди Docker.
“`bash
sudo usermod -aG docker $USER
“`
Застосуйте членство в групі без виходу із системи:
“`bash
newgrp docker
“`
Перевірте:
“`bash
docker run hello-world
“`
Попередження щодо безпеки: Членство в групі `docker` фактично еквівалентне `sudo` без пароля. Користувач у групі `docker` може легко змонтувати файлову систему хоста в контейнер і обійти всі засоби контролю доступу на рівні файлової системи. На багатокористувацьких системах або спільних серверах розгляньте використання rootless Docker натомість:
“`bash
dockerd-rootless-setuptool.sh install
“`
Режим rootless запускає демон Docker і контейнери в непривілейованому просторі імен користувача, що значно зменшує поверхню атаки. Це рекомендована конфігурація для будь-якого середовища, де кілька користувачів спільно використовують один хост.
Крок 5: Довідник основних команд Docker
Керування образами
“`bash
Pull a specific image version from Docker Hub
docker pull nginx:1.27-alpine
List locally cached images
docker images
Remove a specific image
docker rmi nginx:1.27-alpine
Remove all dangling (untagged) images to reclaim disk space
docker image prune
Remove all unused images (not just dangling)
docker image prune -a
“`
Порада для виробництва: Завжди завантажуйте теговані версії (наприклад, `nginx:1.27-alpine`), а не `latest` в будь-якому автоматизованому або виробничому робочому процесі. Тег `latest` є змінним — він може вказувати на інший образ після публікації в реєстрі, порушуючи відтворюваність.
Життєвий цикл контейнера
“`bash
Run a container interactively with a pseudo-TTY
docker run -it ubuntu:22.04 /bin/bash
Run a container in detached mode with port mapping and a name
docker run -d -p 8080:80 –name my-nginx nginx:1.27-alpine
List running containers
docker ps
List all containers (including stopped)
docker ps -a
Stop a running container gracefully (SIGTERM, then SIGKILL after timeout)
docker stop my-nginx
Start a stopped container
docker start my-nginx
Remove a stopped container
docker rm my-nginx
Force-remove a running container (sends SIGKILL immediately)
docker rm -f my-nginx
View real-time logs
docker logs -f my-nginx
Execute a command inside a running container
docker exec -it my-nginx /bin/sh
“`
Перевірка ресурсів та системи
“`bash
Display real-time resource usage statistics
docker stats
Inspect detailed container metadata (JSON)
docker inspect my-nginx
Display disk usage by Docker objects
docker system df
Remove all stopped containers, unused networks, dangling images, and build cache
docker system prune
“`
`docker system prune` є однією з найважливіших команд обслуговування для серверів, що працюють тривалий час. Без періодичного очищення кеш збірки Docker і зупинені контейнери можуть займати десятки гігабайт на активному хості розробки або CI.
Крок 6: Docker Compose — оркестрація багатоконтейнерних застосунків
Docker Compose V2 (`docker-compose-plugin`, встановлений раніше) викликається як `docker compose` (з пробілом), а не застарілий `docker-compose` (з дефісом). Обидва синтаксиси працюють, якщо у вас встановлено плагін, але V2 є поточним стандартом.
6.1 Розуміння структури файлу Compose
Створіть каталог проєкту та файл `compose.yml` (бажана назва файлу в Compose V2; `docker-compose.yml` залишається підтримуваним для зворотної сумісності):
“`bash
mkdir ~/my-web-app && cd ~/my-web-app
nano compose.yml
“`
Виробничо-реалістичний приклад з Nginx та бекенд-сервісом:
“`yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
depends_on:
- app
restart: unless-stopped
app:
image: node:20-alpine
working_dir: /usr/src/app
volumes:
- ./app:/usr/src/app
command: node server.js
environment:
- NODE_ENV=production
restart: unless-stopped
“`
Пояснення ключових директив Compose:
- `restart: unless-stopped` — Контейнер автоматично перезапускається після збою або перезавантаження системи, якщо він не був явно зупинений оператором. Це правильна політика для довготривалих сервісів; `always` перезапускатиме навіть навмисно зупинені контейнери.
- `depends_on` — Контролює порядок запуску, але не чекає, поки сервіс буде *готовий* (наприклад, база даних приймає з’єднання). Для перевірки готовності використовуйте `healthcheck` у поєднанні з `condition: service_healthy`.
- `volumes` з `:ro` — Монтування файлів конфігурації як тільки для читання запобігає зміні скомпрометованим процесом контейнера власної конфігурації.
6.2 Команди робочого процесу Compose
“`bash
Start all services in detached mode
docker compose up -d
View logs for all services
docker compose logs -f
View logs for a specific service
docker compose logs -f web
List running Compose services
docker compose ps
Scale a specific service to multiple replicas
docker compose up -d –scale app=3
Stop services without removing containers
docker compose stop
Stop and remove containers, networks, and volumes
docker compose down –volumes
Rebuild images before starting (useful after code changes)
docker compose up -d –build
“`
6.3 Перевірка запущеного сервісу
“`bash
curl -I http://localhost:8080
“`
Відповідь `200 OK` підтверджує, що Nginx обслуговує коректно. Для сервісів, що працюють на віддаленому екземплярі VPS Hosting, замініть `localhost` на публічну IP-адресу вашого сервера та переконайтеся, що відповідний порт відкритий у вашому брандмауері (`ufw allow 8080/tcp`).
Крок 7: Основи мережі Docker
Розуміння мережевої моделі Docker є необхідним для побудови багатоконтейнерних застосунків, які безпечно взаємодіють.
Стандартні мережеві драйвери:
| Драйвер | Випадок використання |
|---|
| — | — |
|---|
| `bridge` | За замовчуванням для автономних контейнерів; ізольований мережевий простір імен на хості |
|---|
| `host` | Контейнер спільно використовує мережевий стек хоста; максимальна продуктивність, нульова ізоляція |
|---|
| `none` | Без мережевого доступу; корисно для пакетної обробки або навантажень з підвищеними вимогами до безпеки |
|---|
| `overlay` | Багатохостова мережа для кластерів Docker Swarm |
|---|
| `macvlan` | Призначає MAC-адресу контейнеру; відображається як фізичний пристрій у мережі |
|---|
Створення та використання власної bridge-мережі:
“`bash
Create an isolated network
docker network create my-app-network
Run containers attached to the custom network
docker run -d –name db –network my-app-network postgres:16-alpine
docker run -d –name api –network my-app-network my-api-image
Containers on the same custom bridge network can resolve each other by name
Inside 'api', you can connect to 'db' using the hostname 'db'
“`
Власні bridge-мережі забезпечують автоматичне DNS-розв’язання між контейнерами за іменем контейнера. Стандартна мережа `bridge` — ні. Це критична відмінність, яка призводить до збоїв з’єднання, коли розробники припускають, що контейнери в стандартній мережі можуть звертатися один до одного за іменем.
Крок 8: Постійні дані з томами Docker
Контейнери є ефемерними за своєю природою. Будь-які дані, записані у файлову систему контейнера, втрачаються при його видаленні. Для постійного зберігання використовуйте томи або bind-монтування.
“`bash
Create a named volume
docker volume create pgdata
Use the volume with a container
docker run -d
–name postgres-db
-e POSTGRES_PASSWORD=securepassword
-v pgdata:/var/lib/postgresql/data
postgres:16-alpine
List volumes
docker volume ls
Inspect a volume (shows mount point on host)
docker volume inspect pgdata
Remove unused volumes
docker volume prune
“`
Томи проти bind-монтувань:
| Функція | Іменований том | Bind-монтування |
|---|
| — | — | — |
|---|
| Керується Docker | Так | Ні |
|---|
| Потрібен шлях хоста | Ні | Так |
|---|
| Портативність між хостами | Так (з драйверами томів) | Ні |
|---|
| Найкраще для | Даних бази даних, стану застосунку | Коду розробки, файлів конфігурації |
|---|
| Механізм резервного копіювання | `docker run –volumes-from` | Стандартні інструменти файлової системи |
|---|
Крок 9: Підтримання Docker в актуальному стані
Офіційний репозиторій Docker обробляє оновлення через стандартний механізм `apt`:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Щоб оновити лише пакети, пов’язані з Docker, без оновлення всієї системи:
“`bash
sudo apt install –only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
“`
Перевіряйте примітки до релізів Docker перед оновленнями основних версій, особливо щодо змін у драйвері сховища, обробці версій cgroup або застарілих версіях API, які можуть вплинути на існуючі файли `compose.yml`.
Docker проти альтернативних підходів до контейнеризації
| Функція | Docker Engine | Podman | LXC/LXD | containerd (автономний) |
|---|
| — | — | — | — | — |
|---|
| Архітектура демона | Централізований демон | Без демона | На основі демона | На основі демона |
|---|
| Підтримка rootless | Так (v20+) | Нативна | Обмежена | Так |
|---|
| Підтримка Docker Compose | Нативна | Через `podman-compose` | Ні | Ні |
|---|
| Відповідність OCI | Так | Так | Ні (формат LXC) | Так |
|---|
| Інтеграція з Kubernetes | Через CRI-dockerd shim | Нативний CRI | Ні | Нативний CRI |
|---|
| Підтримка Windows/macOS | Docker Desktop | Обмежена | Ні | Ні |
|---|
| Найкраще підходить для | Загальної розробки та виробництва | Орієнтованих на безпеку, rootless | Системних контейнерів, VM | Вузлів Kubernetes |
|---|
Для команд, що запускають контейнеризовані навантаження у масштабі на bare metal, середовище Dedicated Servers надає повний контроль над параметрами ядра, плануванням вводу-виводу сховища та конфігурацією мережі — все це безпосередньо впливає на щільність контейнерів і продуктивність.
Контрольний список посилення безпеки для виробництва
Перш ніж запускати Docker у виробничому середовищі, вирішіть наступне:
Конфігурація демона (`/etc/docker/daemon.json`):
“`json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"userns-remap": "default",
"live-restore": true,
"no-new-privileges": true
}
“`
- `log-opts` з `max-size` та `max-file`: Без ротації логів JSON-файли логів Docker заповнять ваш диск. Це одна з найпоширеніших причин несподіваних збоїв сервера на контейнеризованих хостах.
- `userns-remap: "default"`: Вмикає перемаппінг простору імен користувачів, тому root контейнера (UID 0) відображається на непривілейований UID на хості.
- `live-restore: true`: Дозволяє контейнерам продовжувати роботу, якщо демон Docker аварійно завершується або перезапускається під час оновлення — критично для обслуговування без простоїв.
- `no-new-privileges: true`: Запобігає отриманню процесами контейнера додаткових привілеїв через бінарні файли `setuid` або `setgid`.
Міркування щодо мережі та брандмауера:
Docker безпосередньо маніпулює `iptables` і за замовчуванням обходить правила `ufw`. Контейнер з опублікованим портом (`-p 8080:80`) буде доступний з інтернету, навіть якщо `ufw deny 8080` встановлено. Щоб застосувати правила `ufw` поверх маніпуляцій Docker з `iptables`, додайте `"iptables": false` до `daemon.json` та керуйте маршрутизацією вручну, або використовуйте `–network host` Docker з явними правилами `ufw`.
Для проєктів, що потребують завершення HTTPS, поєднайте ваш контейнеризований застосунок з належно налаштованим зворотним проксі (Nginx або Traefik) та дійсним сертифікатом. SSL Certificates є обов’язковою умовою для будь-якого виробничого веб-сервісу, що працює за контейнеризованим стеком.
Якщо ваше навантаження включає інференс машинного навчання, обслуговування моделей або GPU-прискорену обробку даних всередині контейнерів, NVIDIA Container Toolkit інтегрується безпосередньо з Docker Engine. GPU Hosting забезпечує необхідне апаратне забезпечення для цих навантажень.
Для команд, що керують кількома проєктами з веб-інтерфейсом керування контейнерами, VPS with cPanel пропонує середовище керованої панелі управління, яке може доповнити розгортання на основі Docker для простіших стеків застосунків.
Ключові технічні висновки та матриця рішень
Коли використовувати Docker на VPS проти виділеного сервера:
- Використовуйте VPS для середовищ розробки, стейджингу та виробничих навантажень з низьким і середнім трафіком, де щільність контейнерів становить 10–50 контейнерів.
- Використовуйте виділений сервер, коли щільність контейнерів перевищує 50 екземплярів, коли потрібна передбачувана продуктивність вводу-виводу (без ефекту галасливого сусіда), або коли для вашого навантаження потрібне налаштування параметрів ядра (`sysctl`).
Операційний контрольний список перед запуском у виробництво:
- Налаштуйте ротацію логів у `daemon.json` (`max-size`, `max-file`)
- Увімкніть `live-restore` для виживання після перезапуску демона без простою контейнерів
- Використовуйте іменовані томи, а не bind-монтування, для даних сервісів зі станом
- Закріплюйте версії образів у всіх файлах `compose.yml` — ніколи не використовуйте `latest` у виробництві
- Увімкніть `userns-remap` або запускайте rootless Docker на багатокористувацьких хостах
- Перевіряйте правила `iptables` після встановлення Docker, щоб переконатися, що політика брандмауера не обходиться
- Встановіть `restart: unless-stopped` для всіх довготривалих сервісів
- Запускайте `docker system prune` за розкладом cron для запобігання вичерпанню диска
- Використовуйте власні bridge-мережі для всієї міжконтейнерної комунікації — ніколи не покладайтеся на стандартний bridge для виявлення сервісів
FAQ
Чи використовує Docker на Ubuntu `systemd` або `cgroupfs` як драйвер cgroup за замовчуванням?
Починаючи з Docker Engine 20.10, стандартним драйвером cgroup на системах на основі `systemd` (включаючи всі сучасні релізи Ubuntu LTS) є `systemd`. Це відповідає вимогам Kubernetes і дозволяє уникнути нестабільності, спричиненої одночасним запуском двох менеджерів cgroup. Ви можете перевірити це за допомогою `docker info | grep -i cgroup`.
У чому різниця між `docker compose down` та `docker compose stop`?
`docker compose stop` зупиняє запущені контейнери, але зберігає їх разом з пов’язаними мережами. `docker compose down` зупиняє контейнери, а потім видаляє їх разом з мережами, створеними Compose. Додавання `–volumes` до `down` також видаляє іменовані томи, визначені у файлі Compose — використовуйте цей прапор з обережністю у виробництві, оскільки він безповоротно видаляє постійні дані.
Чому Docker обходить правила брандмауера `ufw` на Ubuntu?
Docker вставляє власні правила `iptables` у ланцюжки `DOCKER` та `DOCKER-USER`, які обробляються до правил ланцюжка `INPUT` `ufw`. Це означає, що порт, опублікований за допомогою `-p`, доступний з інтернету незалежно від політики `ufw`. Правильним способом усунення є безпосереднє додавання правил до ланцюжка `DOCKER-USER` або прив’язка опублікованих портів до конкретного інтерфейсу (наприклад, `-p 127.0.0.1:8080:80`), коли зовнішній доступ не потрібен.
Як обмежити CPU та пам’ять, які може споживати контейнер Docker?
Використовуйте прапори обмеження ресурсів під час виконання: `docker run –memory="512m" –cpus="1.5" my-image`. У Compose встановіть їх під ключем `deploy.resources` (Compose V2) або ключами верхнього рівня `mem_limit` та `cpus`. Без обмежень один некерований контейнер може вичерпати ресурси хоста і вивести з ладу всі інші контейнери на тому самому хості.
Чи можна запускати Docker всередині контейнера Docker (Docker-in-Docker)?
Так, але це категорично не рекомендується для виробничого використання. Поширений шаблон для CI-конвеєрів — монтування сокета Docker хоста (`-v /var/run/docker.sock:/var/run/docker.sock`) у CI-контейнер, що надає контейнеру повний контроль над демоном Docker хоста — значний ризик безпеки. Безпечнішою альтернативою є використання прапора `–allow security.insecure` BuildKit або спеціалізованих інструментів, таких як Kaniko або Buildah, які збирають OCI-образи без необхідності в демоні Docker.
