Skip to content

11. (Л) Вступ до Docker. Контейнери vs віртуальні машини, образи, Docker Hub

Зміст лекції

  1. Проблема «у мене все працює»
  2. Що таке Docker?
  3. Контейнери vs віртуальні машини
  4. Ключові концепції: образи та контейнери
  5. Шари образу
  6. Docker Hub — публічний реєстр образів
  7. Встановлення Docker
  8. Основні команди CLI
  9. Практичний приклад: PostgreSQL у контейнері

Проблема «у мене все працює»

Уявіть типову ситуацію в команді розробників:

Розробник: «Я написав код, він запускається у мене локально»
Тестувальник: «У мене не запускається»
Розробник: «Але у мене все працює!»

Причини можуть бути різними:

  • Різні версії Python, бібліотек або системних пакетів
  • Різні операційні системи (Windows, macOS, Linux)
  • Різна конфігурація середовища (змінні оточення, шляхи до файлів)
  • Залежності встановлені в різному порядку

Docker вирішує цю проблему: якщо додаток запускається в контейнері на одній машині — він запуститься точно так само на будь-якій іншій.

Що таке Docker?

Docker — це платформа для розробки, доставки та запуску застосунків у контейнерах.

Контейнер — це ізольоване середовище, яке містить усе необхідне для роботи застосунку:

  • Код застосунку
  • Середовище виконання (Python, Node.js тощо)
  • Системні бібліотеки та залежності
  • Конфігурацію

Docker не є єдиною технологією контейнеризації, але є найпопулярнішою. Він побудований на основі вбудованих можливостей ядра Linux (namespaces, cgroups).

Контейнери vs Віртуальні машини

Обидві технології вирішують схожу задачу — ізоляцію середовища. Але підходи принципово різні.

Віртуальна машина (VM)

┌─────────────────────────────────────┐
│           Ваш застосунок            │
├─────────────────────────────────────┤
│         Гостьова ОС (Linux)         │  ← повноцінна ОС
├─────────────────────────────────────┤
│           Гіпервізор                │  ← VirtualBox, VMware, KVM
├─────────────────────────────────────┤
│          Хостова ОС                 │
├─────────────────────────────────────┤
│           Залізо                    │
└─────────────────────────────────────┘

Гіпервізор — це програмний шар, який дозволяє запускати кілька віртуальних машин на одному фізичному комп'ютері. Він розподіляє апаратні ресурси (CPU, RAM, диск) між гостьовими ОС та ізолює їх одну від одної. Приклади: VirtualBox, VMware, KVM (вбудований у Linux).

Віртуальна машина емулює повноцінний комп'ютер із власним ядром ОС. Це потребує значних ресурсів:

  • Розмір образу: гігабайти
  • Час запуску: десятки секунд або хвилини
  • Споживання RAM: сотні мегабайт тільки на ОС

Контейнер Docker

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  Контейнер 1 │  │  Контейнер 2 │  │  Контейнер 3 │
│   (Python)   │  │ (PostgreSQL) │  │    (Nginx)   │
├──────────────┴──┴──────────────┴──┴──────────────┤
│               Docker Engine                       │
├───────────────────────────────────────────────────┤
│               Хостова ОС (ядро Linux)             │
├───────────────────────────────────────────────────┤
│                    Залізо                         │
└───────────────────────────────────────────────────┘

Контейнери використовують спільне ядро хостової ОС. Кожен контейнер ізольований.

  • Час запуску: секунди або долі секунди
  • Розмір образу: мегабайти
  • Споживання RAM: тільки те, що потрібно застосунку

Порівняльна таблиця

Критерій Контейнер Віртуальна машина
Час запуску Секунди Хвилини
Розмір МБ ГБ
Ізоляція Процесна Повна (своя ОС)
Продуктивність Близька до нативної Витрати на гіпервізор
Безпека Трохи нижча Вища (повна ізоляція)
Портативність Дуже висока Висока

Коли використовувати VM: потрібна повна ізоляція ОС, різні ядра (Windows vs Linux), вимоги безпеки на рівні ОС.

Коли використовувати Docker: розробка, тестування, мікросервіси, CI/CD, швидке розгортання застосунків.

Ключові концепції: образи та контейнери

Docker-образ (Image)

Образ — це незмінний шаблон для створення контейнерів. Він містить:

  • Базову ОС (наприклад, Ubuntu або Alpine Linux)
  • Встановлені пакети та бібліотеки
  • Код застосунку
  • Команду запуску

Docker-контейнер (Container)

Контейнер — це запущений екземпляр образу. З одного образу можна створити багато контейнерів.

         Образ (Image)
         postgresql:17
    ┌─────────┼─────────┐
    │         │         │
    ▼         ▼         ▼
Контейнер1  Контейнер2  Контейнер3
(порт 5432) (порт 5433) (порт 5434)

Основна різниця

Образ Контейнер
Стан Незмінний (read-only) Змінний (writable layer)
Аналогія Клас Об'єкт (екземпляр)
Зберігається На диску В пам'яті (під час роботи)

Шари образу

Образи Docker побудовані за принципом шарів (layers). Кожна інструкція в Dockerfile створює новий шар:

┌─────────────────────────────┐
│  Шар 1: python:3.13-slim    │  ← базовий образ
├─────────────────────────────┤
│  Шар 2: RUN apt-get update  │  ← системні пакети
├─────────────────────────────┤
│  Шар 3: RUN pip install ... │  ← встановлення залежностей
├─────────────────────────────┤
│  Шар 4: COPY app.py /app/   │  ← код застосунку
└─────────────────────────────┘

Перевага шарів: якщо два образи використовують однаковий базовий образ (наприклад, python:3.13-slim), цей шар завантажується один раз і використовується спільно. Це економить місце на диску та час завантаження.

Docker Hub — публічний реєстр образів

Docker Hub (hub.docker.com) — це хмарний сервіс для зберігання та розповсюдження Docker-образів. Це як GitHub, але для образів.

Що можна знайти на Docker Hub

  • Офіційні образи — підтримуються командою Docker або авторами проєктів:

    • postgres — PostgreSQL
    • python — Python інтерпретатор
    • nginx — веб-сервер
    • redis — in-memory база даних
    • ubuntu, alpine — базові ОС
  • Образи від спільноти — завантажені будь-якими користувачами

Формат назви образу

[реєстр/][користувач/]назва[:тег]

Приклади:
postgres              → офіційний образ PostgreSQL, тег latest
postgres:17           → PostgreSQL версії 17
postgres:17-alpine    → PostgreSQL 17 на Alpine Linux (мінімальна ОС)
python:3.13-slim      → Python 3.13, полегшена версія
kurotych/sqlant       → образ користувача kurotych ([hub.docker.com/r/kurotych/sqlant](https://hub.docker.com/r/kurotych/sqlant))

Тег latest — за замовчуванням, якщо тег не вказано. Зазвичай відповідає останній стабільній версії.

Порада: у реальних проєктах завжди вказуйте конкретну версію (наприклад, postgres:17), а не latest. Це гарантує відтворюваність середовища.

Alpine-версії образів

Багато офіційних образів мають варіант із суфіксом -alpine. Alpine Linux — це мінімалістична ОС, що суттєво зменшує розмір образу:

Образ Розмір
python:3.13 ~1 ГБ
python:3.13-slim ~130 МБ
python:3.13-alpine ~50 МБ

Встановлення Docker

Перевірка встановлення

docker --version

docker run hello-world

Якщо ви бачите повідомлення Hello from Docker! — встановлення успішне.

Основні команди CLI

Робота з образами

# Завантажити образ з Docker Hub
docker pull postgres:17

# Показати всі завантажені образи
docker images

# Видалити образ
docker rmi postgres:17
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
postgres     17        a1b2c3d4e5f6   2 weeks ago    432MB
python       3.13      b2c3d4e5f6a7   3 weeks ago    1.02GB

Запуск контейнерів

# Запустити контейнер (базовий синтаксис)
docker run <образ>

# Запустити у фоновому режимі (-d, --detach)
docker run -d postgres:17

# Задати ім'я контейнеру (--name)
docker run -d --name my-db postgres:17

Прапорець -d (--detach) запускає контейнер у фоні — термінал одразу повертається до вас, а контейнер продовжує працювати. Без -d процес контейнера «займає» термінал: ви бачите його вивід у реальному часі, але не можете вводити команди. Якщо закрити такий термінал — контейнер зупиниться. Для серверних застосунків (бази даних, вебсервери) майже завжди використовують -d.

# Передати змінні середовища (-e, --env)
docker run -d --name my-db \
  -e POSTGRES_PASSWORD=secret \
  postgres:17

# Пробросити порт (-p хост:контейнер)
docker run -d --name my-db \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  postgres:17

# Автоматично видалити контейнер після зупинки (--rm)
docker run --rm postgres:17 echo "hello"

Управління контейнерами

# Показати запущені контейнери
docker ps

# Показати всі контейнери (включно зі зупиненими)
docker ps -a

# Зупинити контейнер
docker stop my-db

# Запустити зупинений контейнер
docker start my-db

# Перезапустити контейнер
docker restart my-db

# Видалити контейнер (потрібно спочатку зупинити)
docker rm my-db

# Зупинити та видалити одночасно
docker rm -f my-db

Перегляд та налагодження

# Переглянути логи контейнера
docker logs my-db

# Стежити за логами в реальному часі
docker logs -f my-db

# Переглянути використання ресурсів
docker stats

Як зайти в середину контейнера

Іноді потрібно зайти всередину запущеного контейнера — перевірити файли, виконати команду, продіагностувати проблему. Для цього використовують docker exec:

# Відкрити bash-сесію всередині контейнера
docker exec -it my-db bash

# Або sh, якщо bash недоступний (Alpine-образи)
docker exec -it my-db sh

# Запустити конкретну програму всередині контейнера
docker exec -it my-db psql -U postgres

Прапорці -it означають:

  • -i (interactive) — залишити stdin відкритим
  • -t (tty) — виділити псевдотермінал

Разом вони дають повноцінний інтерактивний термінал усередині контейнера. Щоб вийти з контейнера — введіть exit. Контейнер при цьому не зупиняється, він продовжує працювати у фоні.

Практичний приклад: PostgreSQL у контейнері

Ви вже використовували цей підхід у попередніх лекціях. Тепер ми розуміємо, що відбувається «під капотом».

Запуск PostgreSQL

docker run -d \
  --name postgres-dev \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=mydb \
  -p 5432:5432 \
  postgres:17

Що відбувається:

  1. Docker перевіряє наявність образу postgres:17 локально
  2. Якщо образу немає — завантажує його з Docker Hub
  3. Створює контейнер з ім'ям postgres-dev
  4. Змінні середовища POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB налаштовують PostgreSQL при першому запуску
  5. Порт 5432 контейнера доступний через порт 5432 хоста

Перевірка роботи

# Переглянути запущені контейнери
docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                    NAMES
a1b2c3d4e5f6   postgres:17   "docker-entrypoint.s…"   10 seconds ago   Up 9 seconds    0.0.0.0:5432->5432/tcp   postgres-dev
# Підключитися до бази даних через psql всередині контейнера
docker exec -it postgres-dev psql -U postgres -d mydb

psql (17.4 (Debian 17.4-1.pgdg120+2))
Type "help" for help.

mydb=#
### Зупинка та видалення

# Зупинити контейнер (дані зберігаються)
docker stop postgres-dev

# Запустити знову (дані на місці)
docker start postgres-dev

# Видалити контейнер повністю (дані втрачаються!)
docker rm -f postgres-dev

Важливо: за замовчуванням дані в контейнері зберігаються лише до його видалення. Для постійного зберігання даних використовують томи (volumes) — ми розглянемо їх у занятті: 14

Корисні посилання

Домашнє завдання

Встановити Docker та запустити контейнер з PostgreSQL локально. Перевірити підключення через psycopg2.


Знайшли помилку чи бажаєте додати інформацію, щоб покращити курс? Створіть issue на GitHub