Що таке Docker і навіщо він потрібен звичайній людині

Є фраза, яку знає кожен, хто хоч раз торкався розробки чи адміністрування: «на моєму компі працює». Розробник написав код, на його ноутбуці все ідеально тестується, а коли намагаєшся запустити на іншій машині — нічого не працює. Версія бібліотеки інша, системна залежність відсутня, змінна оточення не налаштована. Знайомо?

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

Проблема / контекст: чому «на моєму компі працює» — це класика

До появи контейнерів було два основні підходи:

Варіант 1: встановлюємо все напряму на сервер. Поставили Node.js версії 18.7, PostgreSQL 15.3, ще купу бібліотек і залежностей. Все працює. Але коли треба розгорнути таке саме на іншому сервері, раптом з’ясовується, що там Debian іншої версії, і бібліотека libpq5 має інший хеш. І починається — «а чому ж не працює».

Варіант 2: віртуальна машина. Кожному застосунку — своя повноцінна віртуальна машина зі своєю операційною системою. Працює, але кожна VM важить кілька гігабайт, стартує хвилини, і коштує це дорого.

Docker пропонує третій шлях: контейнер має свою файлову систему і середовище, але використовує ядро хостової операційної системи. Це значно легше за віртуальну машину, але достатньо ізольовано, щоб сервіси не конфліктували між собою.

Як це працює простими словами

У світі Docker є кілька ключових понять, і вони досить логічні, якщо вивести правильну analogію.

Образ — це як інсталятор

Образ (image) — готовий пакет із застосунком, бібліотеками, конфігурацією та інструкцією з запуску. Його не потрібно «встановлювати» в класичному розумінні. Образ просто існує, і з нього можна запускати контейнери.

Офіційні образи існують для всього: від Nginx і PostgreSQL до Node.js і Python. Вони живуть на Docker Hub — публічному каталозі, як магазин застосунків.

Контейнер — це запущений застосунок

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

Проста аналогія: образ — це .exe файл або образ диска, а контейнер — це запущена програма. Ви можете запустити одну і ту ж програму в кількох вікнах — кожне вікно працює самостійно.

Dockerfile — рецепт збирання свого образу

Якщо готового образу немає, його можна зібрати. Dockerfile — це текстовий файл з інструкціями:

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Це буквально рецепт: «візьми Node.js 20, створи теку /app, скопіюй файли залежностей, встанови їх, скопіюй решту коду, відкрий порт 3000 і запусти застосунок».

Навіщо це потрібно на практиці

1. Немає більше «на моєму працює, а на сервері — ні»

Якщо застосунок працює в контейнері, він працюватиме будь-де, де встановлений Docker. Точка. Версію Node.js визначаєш ти в Dockerfile, а не системний адміністратор сервера.

2. Можна безпечно тестувати

Треба спробувати нову версію PostgreSQL? Завантажив образ і запустив — це ніяк не впливає на існуючу базу на хості. Коли тест закінчився, контейнер видалив разом із усім сміттям.

3. Декілька сервісів — один файл конфігурації

Вебсервер + база даних + кеш + черга повідомлень? Команда docker compose up запускає все одним файлом. Для домашніх серверів, pet-проєктів, демонстрацій — це один із найзручніших інструментів, які існують.

4. Ізоляція: якщо один сервіс зламався, інші працюють

Кожен контейнер ізольований. Якщо в одному сервісі трапився витік пам’яті, інші контейнери про це навіть не дізнаються. Це краще, ніж коли всі сервіси працюють на одному сервері й тягнуть один одного вниз.

5. Масштабування

Якщо навантаження виросло, можна просто запустити кілька копій одного контейнера. Не треба налаштовувати новий сервер, копіювати конфігурації й сподіватися на успіх.

Практичний приклад: запускаємо Nginx за 30 секунд

Щоб зрозуміти, як це виглядає на практиці, запустимо простий вебсервер:

docker run -d --name myweb -p 8080:80 nginx

Розберемо команду:

Відкриваємо http://localhost:8080 — і бачимо сторінку Nginx. Все. Без встановлення пакетів, без конфігурації. Один рядок — і вебсервер працює.

docker compose: коли сервісів кілька

Один контейнер — це добре. Але реальні проєкти зазвичай мають 2-5 сервісів. Для цього є docker compose:

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Запускається все одним рядком:

docker compose up -d

Тут два сервіси: Nginx і PostgreSQL. Nginx віддаватиме файли з локальної теки html, а база даних зберігатиме дані у volume під назвою pgdata.

Як перевірити, що все працює

Декілька команд, які знадобляться відразу:

Типові помилки початківця

1. Зберігати дані всередині контейнера

Контейнер — це тимчасова річ. Видалив контейнер — дані зникли. Для даних завжди використовуй volume або монтування локальних тек. Інакше одного ранку прокинешся і знайдеш порожню базу.

2. Запускати все як root

Багато офіційних образів запускають процеси від root всередині контейнера. Для тестів це окей, для проду — нічого хорошого. Шукай варіанти з non-root користувачем або налаштовуй це сам у Dockerfile.

3. Забувати про оновлення образів

nginx:latest сьогодні — це одна версія. Через місяць — інша (або не інша, якщо ти не оновлюєш). Для проду краще фіксувати версії: nginx:1.27, postgres:17.2. Тоді деплой буде передбачуваним.

4. Монтувати занадто багато файлів

Коли через volumes монтується ціла тека проекту, це несе ризики: файли можуть конфліктувати з тим, що очікує контейнер, а права доступу — відрізнятися. Монтувай тільки те, що дійсно потрібно.

5. Ігнорувати ресурсні обмеження

Контейнер без обмежень може спожити всю пам’ять хоста. Додавай mem_limit і cpus у compose, якщо хост не потужний або на ньому працюють інші сервіси.

Висновок / план дії

Docker — це не складно. Це спосіб упакувати застосунок разом із усім, що йому потрібно, і гарантувати, що він працюватиме скрізь однаково.

Що зробити найближчим часом:

  1. Встанови Docker на свій комп’ютер або сервер.
  2. Запусти docker run -d -p 8080:80 nginx — і переконайся, що бачиш сторінку Nginx.
  3. Створи docker-compose.yml з двома сервісами (наприклад, Nginx + PostgreSQL) і запусти docker compose up -d.
  4. Пограйся зі зупинкою, видаленням і перезапуском — зрозумій різницю між stop і down.
  5. Створи власний Dockerfile для простого застосунку (навіть якщо це просто статичний HTML).

Наступного разу, коли хтось скаже «на моєму працює», ти вже знатимеш, чого не вистачає в цій ситуації.