Community
0
HostiServer
2026-09-16 11:18

Docker на VPS: встановлення і перший контейнер

⏱️ Час читання: ~11 хвилин | 📅 Оновлено: вересень 2026

📚 Серія «Docker на VPS», частина 1 з 5:

  1. Docker на VPS: встановлення і перший контейнер ← ви тут
  2. Docker Compose: кілька сервісів разом
  3. Docker у production
  4. Docker + CI/CD: автодеплой з GitHub Actions / GitLab CI
  5. Gitea / Forgejo у Docker: повний self-hosted стек

Docker на VPS: встановлення і перший контейнер

У попередній серії ми автоматизували сам процес доставки коду: push у гілку — і за кілька хвилин зміни вже на сервері без участі людини. Але схема «push → SSH deploy → перезапуск сервісу» лікує лише один симптом. Другий, не менш болючий, лишається на місці: залежності на сервері все одно доводиться встановлювати руками, і вони конфліктують між проєктами, які живуть на одному й тому самому VPS.

Класична ситуація: один проєкт написаний під Node.js 18 і залежить від конкретної мажорної версії пакетів, другий — новіший, вже на Node.js 20. Обидва мають деплоїтись на той самий сервер. Без Docker це або два системних Node.js, які конфліктують через nvm і змінні PATH, або компроміс, коли один із проєктів працює на версії, під яку він не тестувався. Те саме повторюється з PHP, Python, версіями бібліотек, системними пакетами — будь-яка спільна залежність на хості рано чи пізно стає точкою конфлікту.

Docker вирішує це на рівні архітектури, а не домовленості. Кожен застосунок отримує власне ізольоване середовище зі своїми залежностями, і це середовище описане в коді, а не в голові адміністратора. Той самий образ, який ви зібрали і перевірили локально, запускається на сервері бітово ідентичним. А відкат до попередньої версії — це не «згадати, які файли перезаписати», а один рядок: docker run зі старим тегом образу.

ℹ️ Пов'язана стаття: якщо CI/CD-пайплайн для деплою у вас ще не налаштований, варто почати з матеріалу «Що таке CI/CD: від ручного deploy до автоматизованих pipelines». Автоматизація процесу деплою і контейнеризація того, що деплоїться, — це дві частини однієї задачі: зробити інфраструктуру керованою кодом, а не набором ручних кроків.

2. Ключові концепції Docker

Перш ніж встановлювати щось на сервер, варто розібратися у п'яти термінах, без яких жодна команда Docker не матиме сенсу.

2.1 Image — незмінний шаблон

Image (образ) — це read-only шаблон, з якого запускається контейнер: файлова система, встановлені залежності, змінні середовища, команда запуску за замовчуванням. Образ ніколи не змінюється сам по собі — node:20-alpine, nginx:latest або власний my-app:1.0 залишаються тими самими байтами, доки ви не зберете новий образ явно.

2.2 Container — запущений екземпляр

Container — це процес, запущений з image, з власною файловою системою поверх шарів образу, власним мережевим простором і власним PID namespace. З одного image можна запустити скільки завгодно контейнерів одночасно, і кожен буде ізольованим від інших, навіть якщо вони походять з того самого образу.

2.3 Layer-система і кеш збірки

Кожна інструкція в Dockerfile створює окремий шар (layer), і шари кешуються. Якщо package.json не змінився з минулої збірки, шар з npm install береться з кешу без повторного виконання — це саме та властивість, яка робить повторні збірки в CI в рази швидшими за перші.

Ключові концепції Docker: image, container і шари з кешем збірки

2.4 Реєстри образів

Docker Hub — публічний реєстр за замовчуванням: docker pull nginx без додаткових налаштувань завантажує офіційний образ звідти. Але це не єдиний варіант.

Реєстр Коли підходить Особливість
Docker Hub Публічні офіційні образи, невеликі приватні проєкти Ліміти на анонімні pull-запити для неавторизованих клієнтів
GHCR (GitHub Container Registry) Проєкти, які вже живуть на GitHub Права доступу керуються через ту саму організацію GitHub
Self-hosted registry Закритий периметр, вимоги комплаєнсу Повний контроль, але адміністрування — на вас

2.5 Docker Engine vs Docker Desktop

Docker Desktop — це графічна обгортка для локальної розробки на Mac і Windows, з власною віртуальною машиною під капотом. На VPS вона не потрібна і навіть не встановлюється: сервер отримує тільки Docker Engine — daemon (dockerd) і CLI, без жодного графічного шару. Саме Engine ми ставимо в наступному розділі.

3. Встановлення Docker на VPS

3.1 Чому не apt install docker.io

Найпростіший шлях виявляється пасткою. Пакет docker.io зі стандартного репозиторію Ubuntu чи Debian — це версія, зафіксована на момент випуску дистрибутива, тобто зазвичай 20.x у той час, коли актуальна лінійка вже 26.x і вище. Різниця — це не просто номер версії: у старих збірках відсутні виправлення безпеки і частина сучасних можливостей BuildKit.

3.2 Офіційний спосіб — репозиторій Docker Inc.

Найшвидший надійний варіант — офіційний інсталяційний скрипт:

curl -fsSL https://get.docker.com | sh

Скрипт сам визначає дистрибутив, додає офіційний репозиторій Docker і встановлює актуальну Community Edition разом з containerd і CLI-плагінами (Compose, Buildx). Для production-серверів, де скрипт з інтернету — не бажаний варіант з міркувань безпеки, той самий репозиторій можна додати вручну за офіційною документацією для конкретного дистрибутива.

3.3 Запуск без sudo

За замовчуванням доступ до Docker daemon має тільки root, і кожна команда потребує sudo. Щоб працювати від звичайного користувача:

sudo usermod -aG docker $USER
newgrp docker

Замість newgrp docker можна просто перелогінитись — зміна групи застосується при новому вході в систему.

⚠️ Про безпеку групи docker: членство в групі docker фактично еквівалентне правам root на хості, оскільки daemon працює з root-привілеями і будь-хто з групи може змонтувати кореневу файлову систему хоста всередину контейнера. Додавайте в цю групу тільки тих, кому дійсно потрібен прямий доступ до Docker на цьому сервері.

3.4 Автозапуск після перезавантаження

Офіційний скрипт встановлення вже вмикає автозапуск, але варто перевірити явно:

sudo systemctl enable docker

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

docker --version
docker info
docker run hello-world

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

4. Перші команди: практика з nginx

Теорія стає зрозумілою тільки після кількох команд у терміналі. Пройдемось по життєвому циклу контейнера на прикладі nginx.

4.1 Завантаження образу

docker pull nginx:alpine

Тег вказано явно, а не latest — це принципово для відтворюваності: latest сьогодні і latest через місяць можуть бути різними образами, і сервер після випадкового docker pull без тега одного дня отримає несподівану мажорну версію.

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

docker run -d -p 80:80 --name my-nginx nginx:alpine
Флаг Значення
-d Detached — запуск у фоні, термінал одразу повертається
-p 80:80 Порт хоста : порт контейнера
--name Читабельне ім'я замість випадкового хеша

4.3 Перегляд запущених контейнерів

docker ps
docker ps -a

docker ps показує лише запущені контейнери, -a додає і зупинені — корисно, щоб знайти контейнер, який завершився з помилкою одразу після старту.

4.4 Логи

docker logs my-nginx
docker logs -f my-nginx

-f (follow) працює так само, як tail -f: зручно тримати відкритим під час діагностики проблеми в реальному часі.

4.5 Shell всередині контейнера

docker exec -it my-nginx sh

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

4.6 Зупинка і видалення

docker stop my-nginx
docker rm my-nginx

stop надсилає сигнал завершення процесу всередині контейнера, rm видаляє сам контейнер разом з його файловою системою. Образ, з якого він був створений, при цьому лишається на диску.

4.7 Керування образами на диску

docker images
docker image prune

docker images показує список завантажених образів з розміром, image prune прибирає dangling-образи — ті, що лишились без тега після пересборки з тим самим ім'ям.

5. Перший Dockerfile: власний образ

5.1 .dockerignore — перший файл, а не Dockerfile

Перед тим як писати Dockerfile, варто створити .dockerignore: node_modules, .env, .git, *.log не повинні потрапляти всередину образу. Без цього файлу контекст збірки (усе, що передається daemon'у) роздувається, а секрети з .env можуть випадково опинитись у шарі образу назавжди.

5.2 Структура Dockerfile

Порядок інструкцій має значення — саме він визначає, що потрапить у кеш, а що буде перезбиратись щоразу:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "server.js"]

5.3 Чому package*.json копіюється окремо

Якщо скопіювати весь код одним COPY . . перед встановленням залежностей, будь-яка зміна в коді інвалідує кеш шару з npm ci, і залежності перевстановлюються заново при кожній збірці. Розділивши це на два кроки, шар npm ci береться з кешу доти, доки не зміняться самі package.json чи package-lock.json.

5.4 Alpine чи повний образ

Базовий образ Розмір Коли обрати
node:20-alpine ~130 MB Production за замовчуванням
node:20 ~1.1 GB Потрібні системні бібліотеки, яких немає в Alpine (musl vs glibc)

5.5 CMD чи ENTRYPOINT

Інструкція Поведінка
CMD Аргументи за замовчуванням; повністю перевизначаються при docker run image команда
ENTRYPOINT Фіксований виконуваний файл; аргументи з docker run додаються до нього, а не замінюють його

5.6 Збірка образу

docker build -t my-app:1.0 .

Той самий образ можна позначити другим тегом без повторної збірки — наприклад, docker build -t my-app:latest . в тому самому контексті створить ще один тег на ті самі шари.

5.7 Запуск власного образу

docker run -d -p 3000:3000 --name my-app my-app:1.0

6. Volumes: дані поза контейнером

6.1 Чому дані зникають

Файлова система контейнера ефемерна за задумом: docker rm видаляє все, що було записано всередину під час роботи. Для stateless-застосунку це не проблема, але для бази даних чи будь-якого сервісу, що зберігає стан, це означає втрату даних при кожному оновленні контейнера.

6.2 Bind mount

docker run -v /var/log/myapp:/app/logs my-app:1.0

Директорія з хоста монтується прямо всередину контейнера, зміни видно з обох боків у реальному часі. Зручно для конфігів, які треба редагувати ззовні, і для логів, які потім читає окрема система моніторингу на хості.

6.3 Named volume

docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data postgres:16-alpine

Named volume керується самим Docker'ом і фізично живе в /var/lib/docker/volumes/. Для баз даних це зазвичай кращий вибір за bind mount: Docker сам керує шляхами і правами доступу, а бекап можна знімати через допоміжний контейнер з --volumes-from, не турбуючись про точну структуру директорій хоста.

Параметр Bind mount Named volume
Розташування на хості Ви вказуєте самі Керує Docker
Типове застосування Конфіги, логи, код у розробці Дані баз даних, стан сервісів
Портативність Прив'язана до структури хоста Однакова команда на будь-якому сервері

Порівняння bind mount і named volume у Docker: де фізично живуть дані і хто ними керує

6.4 Керування volumes

docker volume ls
docker volume inspect pgdata
docker volume prune

prune видаляє volumes, які не використовуються жодним контейнером — корисно, але варто перевірити список перед виконанням: даних, видалених таким чином, не повернути.

7. Висновок

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

Незручність, яка стає помітною одразу після перших кількох контейнерів: кожен сервіс — це окремий довгий рядок docker run з портами, змінними середовища і volumes, який легко переплутати чи забути відтворити після оновлення сервера. Коли застосунок складається не з одного контейнера, а з декількох — сам застосунок, база даних, кеш — керувати цим набором окремими командами стає складно і схильно до помилок.

Саме цю проблему вирішує Docker Compose: весь стек описується один раз у файлі docker-compose.yml і піднімається однією командою.

📚 Навігація серії:
Ви читаєте частину 1 з 5 «Docker на VPS: встановлення і перший контейнер».
Далі: Частина 2. Docker Compose: кілька сервісів разом →

🚀 VPS під Docker-навантаження

Контейнери додають накладні витрати на CPU і диск понад сам застосунок: образи, шари, логи, volumes для баз даних. Hostiserver дає ресурси, розраховані саме під це.

🖥️ Виділені Сервери

  • Від $90/міс, повний контроль над залізом для важких контейнерних навантажень
  • Без спільних ресурсів: сусідні орендарі не впливають на продуктивність ваших контейнерів
  • 24/7 підтримка: допоможемо з налаштуванням Docker і мережі між сервісами

💻 Cloud (VPS) Хостинг

  • Від $19.95/міс, KVM-ізоляція, виділені vCPU і RAM
  • NVMe-диски: швидкі шари образів і volumes для баз даних
  • Ідеально для першого Docker-хоста: встановили, підняли контейнер, перевірили на реальному проєкті
  • Легко масштабувати: більше RAM під нові сервіси або окремий VPS під кожен проєкт

💬 Не впевнені, який варіант потрібен?
💬 Напишіть нам — допоможемо з вибором!

Часті запитання

Скільки RAM потрібно для Docker на VPS?

Сам Docker Engine займає мало — до 100-200 MB на daemon і containerd. Основне споживання йде від самих контейнерів: невеликий Node.js-застосунок вкладається в 256-512 MB, база даних на кшталт PostgreSQL комфортно почувається від 1 GB. Для одного застосунку разом з базою даних розумний старт — VPS з 2 GB RAM, з запасом під пікові навантаження та кеш файлової системи.

Чи можна на одному VPS тримати кілька проєктів з різними версіями Node.js?

Так, і це один з головних мотивів переходу на Docker. Кожен контейнер має власний ізольований runtime незалежно від того, що встановлено на хості. Один контейнер працює на node:18-alpine, інший поруч — на node:20-alpine, і вони не бачать середовища одне одного.

У чому практична різниця між image і контейнером?

Image — це незмінний шаблон на диску, схожий на клас у програмуванні. Контейнер — запущений екземпляр цього шаблону, зі своїм процесом і власним шаром для запису поверх read-only шарів образу. Видалення контейнера не видаляє образ, з якого його створено.

Контейнер одразу завершується після запуску — що перевірити?

Спочатку docker ps -a, щоб побачити код завершення, потім docker logs назва_контейнера — у переважній більшості випадків причина видна одразу в останніх рядках виводу: помилка застосунку при старті, відсутня змінна середовища, порт вже зайнятий. Контейнер завершується, коли завершується головний процес усередині нього, тому це майже завжди помилка самого застосунку, а не Docker.

Docker чи звичайний systemd-сервіс для невеликого проєкту?

Якщо на сервері живе один застосунок і його залежності не конфліктують ні з чим, systemd-сервіс простіший і має менше рухомих частин. Docker починає окупати себе, щойно з'являється другий проєкт з іншими вимогами до середовища, потреба у відтворюваних збірках або плани перенести застосунок на інший сервер без ризику «на новому сервері щось інакше».

Чи безпечно давати користувачу доступ до Docker без sudo?

Тут варто дивитись правді у вічі: членство в групі docker рівнозначне root-доступу до хоста, оскільки daemon працює з правами root і дозволяє змонтувати будь-яку директорію хоста всередину контейнера. Додавайте в цю групу лише тих, кому дійсно потрібне повне адміністрування Docker на конкретному сервері, а не всіх, кому просто треба запустити один контейнер.

Named volume чи bind mount для бази даних?

Named volume — типовий вибір для даних бази: Docker сам керує шляхом зберігання, і команда однакова незалежно від сервера. Bind mount має сенс, коли потрібен прямий і передбачуваний доступ до файлів з хоста — наприклад, щоб окрема система бекапів на хості читала файли бази напряму, без проміжного контейнера.

Contents

Поділіться цією статтею

VPS з підтримкою від

$19 95 / міс

Виділені сервери від

$80 / міс

CDN починаючи від

$0 / міс

 

Користуючись цим сайтом, ви погоджуєтеся на використання файлів cookies відповідно до нашої Політики Конфіденційності.