Docker для початківців у DevOps
Зміст
- Що таке Docker
- Проблеми, які вирішує Docker
- Як виглядала розробка до Docker
- Переваги використання Docker
- Розробка з Docker
- Dockerfile
- Docker Image
- Docker Container
- Docker Compose
- Container Registry
Що таке Docker
Docker — це платформа з відкритим кодом, яка автоматизує розгортання, масштабування та управління додатками в ізольованих середовищах, що називаються контейнерами.
Docker використовує технологію контейнеризації для пакування додатка та його залежностей в стандартизованій одиниці, яка містить усе необхідне для роботи: код, системні інструменти, бібліотеки та налаштування.
Проблеми, які вирішує Docker
Docker вирішує ряд важливих проблем, з якими стикаються розробники та DevOps-інженери:
-
Проблема "працює на моєму комп'ютері" — коли програма коректно працює в середовищі розробки, але виходить з ладу при перенесенні на тестування чи в продакшн.
-
Складна налаштування середовища — коли потрібно витрачати багато часу на налаштування серверів та залежностей.
-
Конфлікти залежностей — коли різні додатки потребують різних версій однієї й тієї ж бібліотеки.
-
Неефективне використання ресурсів — порівняно з віртуальними машинами, які вимагають багато ресурсів.
-
Складність масштабування — традиційний спосіб масштабування додатків вимагає більше зусиль і часу.
Як виглядала розробка до Docker
До появи Docker процес розробки та розгортання програмного забезпечення стикався з багатьма труднощами:
1. Традиційне розгортання на фізичних серверах
Розробник --> Тестувальник --> Адміністратор
(Працює --> Не працює --> Потрібні додаткові зусилля)
(Win/Mac) --> (Linux) --> (Продакшн сервер)
- Для кожного додатка зазвичай виділявся окремий фізичний сервер
- Ресурси використовувались неефективно
- Розгортання займало дні або тижні
- Складний процес оновлення та мігрування
2. Віртуальні машини (VM)
+---------------------------+
| Додаток A | Додаток B |
+---------------------------+
| Гостьова ОС | Гостьова ОС |
+---------------------------+
| Hypervisor |
+---------------------------+
| Хост ОС |
+---------------------------+
| Сервер |
+---------------------------+
- Кращий рівень ізоляції
- Але вимагали повноцінну гостьову ОС для кожної VM
- Споживали багато ресурсів (CPU, RAM, дисковий простір)
- Займали час на завантаження
- Вимагали ліцензій для кожної ОС
- Складно автоматизувати
3. Ручне налаштування середовища
- Розробники писали документацію з інструкціями встановлення
- Системні адміністратори вручну налаштовували кожен сервер
- Складний процес відтворення ідентичного середовища
- Багато часу на діагностику помилок середовища
Переваги використання Docker
Docker надає ряд значних переваг для сучасної розробки:
-
Легка переносимість
- "Build once, run anywhere" (Збирай один раз, запускай де завгодно)
- Однакова поведінка в різних середовищах
-
Швидкість
- Контейнери запускаються за секунди
- Швидкий процес розробки та тестування
-
Ефективне використання ресурсів
- Контейнери набагато легші за VM
- Можливість запускати більше екземплярів на тому ж обладнанні
-
Ізоляція
- Додатки працюють незалежно один від одного
- Зменшення конфліктів залежностей
-
Повторюваність
- Гарантовано однакове середовище в будь-який час
- Декларативний опис середовища (Інфраструктура як код)
-
Масштабованість
- Легко масштабувати додатки горизонтально
- Інтеграція з оркестраторами (Kubernetes, Docker Swarm)
-
Версійність
- Легко відстежувати зміни в інфраструктурі
- Можливість швидкого відкату до попередньої версії
Розробка з Docker
Використання Docker істотно змінює процес розробки:
1. Стандартизоване середовище
+-------------------+ +-------------------+ +-------------------+
| Середовище розр. | | Тестове середов. | | Продакшн середов. |
+-------------------+ +-------------------+ +-------------------+
| Контейнер A | | Контейнер A | | Контейнер A |
+-------------------+ +-------------------+ +-------------------+
| Docker | | Docker | | Docker |
+-------------------+ +-------------------+ +-------------------+
| Windows/Mac/Lin | | Linux | | Linux |
+-------------------+ +-------------------+ +-------------------+
- Ідентичне середовище на всіх етапах
- Менше помилок, пов'язаних із відмінностями середовищ
2. DevOps практики
- Пришвидшення циклу розробки
- CI/CD інтеграція (легка автоматизація тестів та розгортання)
- Інфраструктура як код (IaC)
- Зручні відкати до попередніх версій
3. Локальна розробка
- Розробники можуть працювати з мікросервісами локально
- Можливість репродукувати складні мультисервісні системи на одній машині
- Швидкий старт для нових розробників у проекті
Dockerfile
Dockerfile — це текстовий файл із інструкціями, які описують, як побудувати Docker образ. Він автоматизує процес створення контейнерів і забезпечує повторюваність.
Структура Dockerfile
# Базовий образ
FROM node:14
# Метадані
LABEL maintainer="example@gmail.com"
LABEL version="1.0"
# Встановлення робочої директорії
WORKDIR /app
# Копіювання файлів
COPY package*.json ./
# Виконання команд
RUN npm install
# Копіювання решти файлів
COPY . .
# Відкриття портів
EXPOSE 3000
# Змінні оточення
ENV NODE_ENV=production
# Команда для запуску
CMD ["npm", "start"]
Пояснення основних інструкцій
- FROM — визначає базовий образ, з якого починається збірка
- LABEL — додає метадані до образу
- WORKDIR — встановлює робочу директорію для наступних інструкцій
- COPY/ADD — копіює файли з хоста до контейнера
- RUN — виконує команди під час збірки образу
- EXPOSE — інформує про порти, які слухає контейнер
- ENV — встановлює змінні оточення
- CMD/ENTRYPOINT — визначає команду, яка виконується при запуску контейнера
Приклад Dockerfile для Python застосунку
# Базовий образ з Python 3.9
FROM python:3.9-slim
# Метадані
LABEL maintainer="developer@example.com"
LABEL description="Simple Flask application"
# Встановлення робочої директорії
WORKDIR /app
# Встановлення залежностей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копіювання коду застосунку
COPY . .
# Визначення змінної оточення
ENV FLASK_APP=app.py
ENV FLASK_ENV=production
# Відкриття порту
EXPOSE 5000
# Запуск застосунку
CMD ["flask", "run", "--host=0.0.0.0"]
Кроки для створення та використання Dockerfile
- Створіть файл з назвою
Dockerfile
(без розширення) у кореневій директорії вашого проекту - Напишіть інструкції збірки образу
- Збудуйте образ за допомогою команди
docker build
- Використовуйте образ для створення контейнерів
# Створення образу
docker build -t myapp:latest .
# Перевірка створеного образу
docker images
Кращі практики для Dockerfile
- Використовуйте .dockerignore — для виключення непотрібних файлів
- Групуйте інструкції RUN — щоб зменшити кількість шарів
- Використовуйте багатоетапну збірку — для зменшення розміру фінального образу
- Встановлюйте конкретні версії — для забезпечення стабільності
- Мінімізуйте кількість шарів — об'єднуйте команди де це можливо
Docker Image
Docker Image (образ) — це легкий, автономний, виконуваний пакет, який включає все необхідне для запуску додатка: код, runtime, системні інструменти, бібліотеки та налаштування.
Характеристики Docker Image
- Незмінний (Immutable) — після створення не може бути змінений
- Багатошаровий — складається з шарів, які можуть бути повторно використані
- Базується на UnionFS — файлова система, що дозволяє шарам працювати як одне ціле
- Може бути розповсюджений через Container Registry
Структура Docker Image
+---------------------------+
| Додаток (верхній шар) |
+---------------------------+
| Залежності |
+---------------------------+
| Налаштування |
+---------------------------+
| Базовий образ (ОС) |
+---------------------------+
Команди для роботи з образами
# Перегляд доступних образів
docker images
# Завантаження образу з Docker Hub
docker pull nginx:latest
# Збірка образу з Dockerfile
docker build -t myapp:1.0 .
# Перейменування образу
docker tag myapp:1.0 username/myapp:1.0
# Завантаження образу в Container Registry
docker push username/myapp:1.0
# Видалення образу
docker rmi myapp:1.0
# Перегляд історії шарів образу
docker history myapp:1.0
# Інспектування метаданих образу
docker inspect myapp:1.0
Приклад багатоетапної збірки
Багатоетапна збірка дозволяє зменшити розмір фінального образу:
# Етап збірки
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Етап продакшн
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Приклад створення та використання образу
- Створіть просту Node.js програму
# Створення директорії проекту
mkdir docker-node-example
cd docker-node-example
# Створення файлу package.json
cat > package.json << EOF
{
"name": "docker-node-example",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.1"
}
}
EOF
# Створення файлу index.js
cat > index.js << EOF
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send('Hello from Docker!');
});
app.listen(PORT, () => {
console.log(\`Server running on port \${PORT}\`);
});
EOF
# Створення Dockerfile
cat > Dockerfile << EOF
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
EOF
- Збудуйте образ та запустіть контейнер
# Збірка образу
docker build -t node-app:1.0 .
# Перевірка створеного образу
docker images
# Запуск контейнера
docker run -p 3000:3000 -d --name my-node-app node-app:1.0
# Перевірка запущеного контейнера
docker ps
# Перевірка роботи програми
curl http://localhost:3000
Docker Container
Docker Container (контейнер) — це запущений екземпляр Docker образу. Це легке, ізольоване середовище виконання, що містить все необхідне для роботи додатка.
Характеристики контейнерів
- Ізольовані — використовують namespace та cgroups Linux для ізоляції
- Легкі — використовують образ на основі шарів і розділяють ядро ОС
- Динамічні — можуть бути легко запущені, зупинені, переміщені
- Стан — на відміну від образів, мають стан і можуть змінюватися
Порівняння з віртуальними машинами
+------------+ +------------+ +-------------+ +-------------+
| Додаток A | | Додаток B | | Додаток A | | Додаток B |
+------------+ +------------+ +-------------+ +-------------+
| Bins/ | | Bins/ | | Гостьова ОС | | Гостьова ОС |
| Libs | | Libs | +-------------+ +-------------+
+------------+ +------------+ | Hypervisor |
| Docker Engine | +-----------------------------+
+----------------------------+ | Хост ОС |
| Хост ОС | +-----------------------------+
+----------------------------+ | Інфраструктура |
| Інфраструктура | +-----------------------------+
+----------------------------+
Контейнери Docker Віртуальні машини
Життєвий цикл контейнера
+--------+
| Образ |
+--------+
|
v
+-----------------+ +------------------+
| Створення | -----> | Запуск |
+-----------------+ +------------------+
|
v
+------------------+ +----------------+
| Робота | -----> | Зупинка |
+------------------+ +----------------+
|
v
+----------------+
| Видалення |
+----------------+
Основні команди для роботи з контейнерами
# Запуск контейнера
docker run -d --name web -p 80:80 nginx
# Перегляд запущених контейнерів
docker ps
# Перегляд всіх контейнерів (включно зі зупиненими)
docker ps -a
# Зупинка контейнера
docker stop web
# Запуск зупиненого контейнера
docker start web
# Перезапуск контейнера
docker restart web
# Видалення контейнера (має бути зупинений)
docker rm web
# Видалення контейнера (навіть якщо запущений)
docker rm -f web
# Перегляд логів контейнера
docker logs web
# Виконання команди всередині контейнера
docker exec -it web bash
# Копіювання файлів в/з контейнер
docker cp file.txt web:/path/in/container/
docker cp web:/path/in/container/file.txt ./local-path/
Приклад запуску та взаємодії з контейнером
- Запуск контейнера з веб-сервером nginx:
# Запуск контейнера nginx
docker run -d --name my-nginx -p 8080:80 nginx
# Перевірка запущених контейнерів
docker ps
# Перевірка роботи веб-сервера
curl http://localhost:8080
- Налаштування контейнера:
# Створення HTML-файлу на хості
echo "<h1>My Custom Nginx Page</h1>" > index.html
# Копіювання файлу в контейнер
docker cp index.html my-nginx:/usr/share/nginx/html/
# Перевірка змін
curl http://localhost:8080
- Збереження змін у новий образ:
# Створення нового образу на основі змін у контейнері
docker commit my-nginx my-custom-nginx:1.0
# Перевірка нового образу
docker images
# Запуск контейнера з нового образу
docker run -d --name custom-nginx -p 8081:80 my-custom-nginx:1.0
# Перевірка
curl http://localhost:8081
Монтування томів (Volumes)
Томи дозволяють зберігати дані поза контейнером:
# Створення тому
docker volume create my-data
# Запуск контейнера з монтуванням тому
docker run -d --name db -v my-data:/var/lib/mysql mysql:5.7
# Прямий маппінг директорії з хоста
docker run -d --name web -v $(pwd)/html:/usr/share/nginx/html -p 8080:80 nginx
Обмеження ресурсів контейнера
# Обмеження CPU та пам'яті
docker run -d --name limited-app \
--cpus=0.5 \
--memory=512m \
my-app:1.0
Docker Compose
Docker Compose — це інструмент для визначення та запуску багатоконтейнерних Docker додатків. Він використовує YAML-файл для налаштування сервісів, мереж та томів.
Проблеми, які вирішує Docker Compose
- Складність управління багатьма контейнерами — через CLI потрібно виконувати багато команд
- Взаємозалежність контейнерів — контейнери потрібно запускати в певному порядку
- Повторюваність середовища — тяжко забезпечити однакові параметри запуску
- Складність в управлінні томами та мережами — потребує додаткових команд
Структура docker-compose.yml файлу
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- app
app:
build: ./app
environment:
- DB_HOST=db
- DB_USER=root
- DB_PASSWORD=example
depends_on:
- db
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=example
- MYSQL_DATABASE=myapp
volumes:
db_data:
networks:
default:
driver: bridge
Основні секції та параметри
- version — версія формату Compose файлу
-
services — визначення сервісів (контейнерів)
- image — використовуваний Docker образ
- build — шлях до Dockerfile для збірки образу
- ports — публікація портів (хост:контейнер)
- volumes — монтування томів
- environment — змінні оточення
- depends_on — залежності між сервісами
- restart — політика перезапуску
- volumes — визначення іменованих томів
- networks — налаштування мереж
Основні команди Docker Compose
# Запуск всіх сервісів (в фоновому режимі)
docker-compose up -d
# Зупинка всіх сервісів
docker-compose down
# Зупинка і видалення всіх сервісів (включно з томами)
docker-compose down -v
# Перегляд статусу сервісів
docker-compose ps
# Перегляд логів
docker-compose logs
# Логі конкретного сервісу
docker-compose logs app
# Виконання команди в сервісі
docker-compose exec app bash
# Масштабування сервісу
docker-compose up -d --scale web=3
Приклад повноцінного веб-додатка з Docker Compose
Створімо простий веб-додаток із трьома компонентами: веб-сервер, бекенд API та база даних.
- Структура проекту:
my-docker-app/
├── docker-compose.yml
├── nginx/
│ ├── Dockerfile
│ └── default.conf
├── api/
│ ├── Dockerfile
│ ├── package.json
│ ├── index.js
│ └── ...
├── db/
│ └── init.sql
└── .env
- Файл
.env
з змінними оточення:
DB_USER=appuser
DB_PASSWORD=apppassword
DB_NAME=appdb
DB_PORT=5432
- Створення
docker-compose.yml
:
version: '3'
services:
nginx:
build: ./nginx
ports:
- "80:80"
depends_on:
- api
networks:
- frontend
api:
build: ./api
environment:
- DB_HOST=db
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME}
- NODE_ENV=production
depends_on:
- db
networks:
- frontend
- backend
db:
image: postgres:13
volumes:
- db_data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
ports:
- "${DB_PORT}:5432"
networks:
- backend
volumes:
db_data:
networks:
frontend:
backend:
- Створення Nginx конфігурації:
# Створення директорії
mkdir -p nginx
# Створення конфігураційного файлу
cat > nginx/default.conf << EOF
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://api:3000;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
}
}
EOF
# Створення Dockerfile для Nginx
cat > nginx/Dockerfile << EOF
FROM nginx:alpine
COPY default.conf /etc/nginx/conf.d/default.conf
EOF
- Створення Node.js API:
# Створення директорії
mkdir -p api
# Створення package.json
cat > api/package.json << EOF
{
"name": "docker-api-example",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.1",
"pg": "^8.5.1"
}
}
EOF
# Створення index.js
cat > api/index.js << EOF
const express = require('express');
const { Pool } = require('pg');
const app = express();
const PORT = process.env.PORT || 3000;
// Підключення до PostgreSQL
const pool = new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: 5432,
});
app.use(express.json());
// Основний маршрут
app.get('/', (req, res) => {
res.json({ message: 'API працює!' });
});
// Запит до бази даних
app.get('/users', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM users');
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Помилка бази даних' });
}
});
app.listen(PORT, () => {
console.log(\`API сервер запущено на порту \${PORT}\`);
});
EOF
# Створення Dockerfile для API
cat > api/Dockerfile << EOF
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
EOF
- Створення ініціалізаційного скрипта для бази даних:
# Створення директорії
mkdir -p db
# Створення скрипта ініціалізації
cat > db/init.sql << EOF
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email) VALUES
('Іван Петренко', 'ivan@example.com'),
('Марія Коваленко', 'maria@example.com');
EOF
- Запуск додатка з Docker Compose:
# Запуск всіх сервісів
docker-compose up -d
# Перевірка статусу
docker-compose ps
# Тестування API
curl http://localhost/users
- Керування додатком:
# Перегляд логів всіх сервісів
docker-compose logs
# Перегляд логів конкретного сервісу
docker-compose logs api
# Зупинка всіх сервісів
docker-compose stop
# Запуск сервісів знову
docker-compose start
# Зупинка і видалення всіх контейнерів
docker-compose down
# Зупинка, видалення контейнерів і томів
docker-compose down -v
Container Registry
Container Registry — це сховище для збереження та розповсюдження Docker образів. Це дозволяє зберігати образи в центральному місці та надавати до них доступ іншим користувачам або серверам.
Типи Container Registry
-
Публічні реєстри
- Docker Hub — офіційний реєстр Docker
- GitHub Container Registry — інтегрований з GitHub
- Quay.io — від Red Hat
- Google Container Registry — від Google Cloud
-
Приватні реєстри
- AWS Elastic Container Registry — від Amazon
- Azure Container Registry — від Microsoft
- GitLab Container Registry — інтегрований з GitLab
- JFrog Artifactory — універсальний репозиторій
-
Локальні реєстри
- Docker Registry — базовий реєстр з відкритим кодом
- Harbor — корпоративний реєстр з підтримкою безпеки
- Nexus Repository — багатоцільовий репозиторій
Docker Hub
Docker Hub — це найпопулярніший публічний реєстр для Docker образів. Він містить більше мільйона офіційних та спільнотних образів.
Можливості Docker Hub:
- Публічні та приватні репозиторії
- Офіційні образи — підтримуються Docker Inc
- Автоматична збірка — інтеграція з GitHub/BitBucket
- Команди — колективний доступ
- Вебхуки — автоматизація CI/CD
Робота з Docker Hub:
-
Реєстрація на Docker Hub:
- Відвідайте hub.docker.com
- Створіть обліковий запис
-
Авторизація в CLI:
docker login
- Робота з образами:
# Завантаження образу
docker pull nginx:latest
# Перейменування образу для відправки
docker tag my-app:1.0 username/my-app:1.0
# Відправка образу в Docker Hub
docker push username/my-app:1.0
# Пошук образів
docker search nginx
Локальний реєстр
Локальний реєстр дозволяє зберігати образи в приватній мережі, що важливо для:
- Зменшення залежності від зовнішніх сервісів
- Підвищення безпеки
- Пришвидшення завантаження образів
Запуск локального реєстру з Docker:
# Запуск простого реєстру
docker run -d -p 5000:5000 --name registry registry:2
# Запуск реєстру з постійним сховищем
docker run -d -p 5000:5000 --name registry \
-v $PWD/registry-data:/var/lib/registry \
registry:2
Використання локального реєстру:
# Перейменування образу для локального реєстру
docker tag my-app:1.0 localhost:5000/my-app:1.0
# Відправка образу в локальний реєстр
docker push localhost:5000/my-app:1.0
# Завантаження образу з локального реєстру
docker pull localhost:5000/my-app:1.0
Налаштування безпеки реєстру:
- Створення сертифіката та ключа:
mkdir -p certs
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout certs/domain.key -x509 -days 365 \
-out certs/domain.crt
- Запуск реєстру з HTTPS:
docker run -d -p 5000:5000 --name registry \
-v $PWD/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
- Запуск реєстру з базовою автентифікацією:
# Створення файлу з паролем
mkdir auth
docker run --entrypoint htpasswd registry:2 -Bbn myuser mypassword > auth/htpasswd
# Запуск реєстру з автентифікацією
docker run -d -p 5000:5000 --name registry \
-v $PWD/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
Комплексний приклад роботи з реєстрами
Розглянемо сценарій розробки, збірки та розгортання додатку з використанням реєстрів:
1. Локальна розробка
# Розробка додатку та Dockerfile
# ...
# Збірка локального образу
docker build -t my-web-app:dev .
# Тестування
docker run -p 8080:80 my-web-app:dev
2. Відправка в приватний реєстр (для CI/CD)
# Авторизація в приватному реєстрі
docker login my-private-registry.example.com
# Перейменування образу
docker tag my-web-app:dev my-private-registry.example.com/project/my-web-app:1.0.0
# Відправка образу
docker push my-private-registry.example.com/project/my-web-app:1.0.0
3. Розгортання в продакшн
# На продакшн-сервері
docker login my-private-registry.example.com
# Завантаження образу
docker pull my-private-registry.example.com/project/my-web-app:1.0.0
# Розгортання
docker run -d --restart unless-stopped -p 80:80 my-private-registry.example.com/project/my-web-app:1.0.0
Сценарій повного циклу DevOps з Docker
Розглянемо повний сценарій від розробки до розгортання, використовуючи Docker і GitLab CI/CD:
1. Підготовка проекту
# Клонування репозиторію
git clone https://gitlab.com/myuser/my-web-app.git
cd my-web-app
# Створення Dockerfile
cat > Dockerfile << EOF
FROM nginx:alpine
COPY ./html /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
EOF
# Створення простого веб-сайту
mkdir -p html
cat > html/index.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>Docker DevOps Demo</title>
</head>
<body>
<h1>Вітаємо в Docker DevOps Demo!</h1>
<p>Версія: 1.0.0</p>
</body>
</html>
EOF
# Створення файлу .gitlab-ci.yml для CI/CD
cat > .gitlab-ci.yml << EOF
stages:
- build
- test
- deploy
variables:
DOCKER_REGISTRY: registry.gitlab.com/myuser
IMAGE_NAME: my-web-app
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
build:
stage: build
image: docker:20.10
services:
- docker:20.10-dind
script:
- docker build -t $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG .
- docker tag $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG $DOCKER_REGISTRY/$IMAGE_NAME:latest
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG
- docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
test:
stage: test
image: docker:20.10
services:
- docker:20.10-dind
script:
- docker pull $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG
- docker run -d --name test-container -p 8080:80 $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG
- apk add --no-cache curl
- sleep 5
- curl -s http://localhost:8080 | grep "Docker DevOps Demo"
deploy-staging:
stage: deploy
image: docker:20.10
services:
- docker:20.10-dind
script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\\r' | ssh-add -
- mkdir -p ~/.ssh
- echo -e "Host *\\n\\tStrictHostKeyChecking no\\n\\n" > ~/.ssh/config
- ssh user@staging-server "docker pull $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG &&
docker stop web-app || true &&
docker rm web-app || true &&
docker run -d --name web-app -p 80:80 $DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
only:
- master
EOF
# Додавання файлів та комміт
git add .
git commit -m "Initial commit with Docker setup"
git push
2. Створення докер-композ файлу для локальної розробки
# Створення docker-compose.yml
cat > docker-compose.yml << EOF
version: '3'
services:
web:
build: .
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
EOF
# Запуск локального середовища
docker-compose up -d
# Перевірка
curl http://localhost:8080
3. Внесення змін та перевірка CI/CD
# Внесення змін
cat > html/index.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>Docker DevOps Demo</title>
</head>
<body>
<h1>Вітаємо в Docker DevOps Demo!</h1>
<p>Версія: 1.0.1</p>
<p>Нові зміни в проекті!</p>
</body>
</html>
EOF
# Перевірка локально
docker-compose restart
# Комміт і пуш змін
git add html/index.html
git commit -m "Update version to 1.0.1"
git push
Найкращі практики використання Docker
1. Безпека
- Використовуйте офіційні образи — вони регулярно оновлюються
- Сканування вразливостей — використовуйте інструменти на кшталт Trivy, Clair
- Не запускайте контейнери від імені root — використовуйте користувача без привілеїв
- Підписування образів — використовуйте Docker Content Trust
# Приклад запуску контейнера не від root
docker run -d --user 1000:1000 nginx
2. Оптимізація образів
- Багатоетапна збірка — зменшує розмір фінального образу
- Мінімальні базові образи — використовуйте alpine або slim варіанти
- Об'єднання шарів — групуйте команди RUN
- Використання .dockerignore — виключення непотрібних файлів
# Приклад багатоетапної збірки
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
3. Моніторинг та логування
- Централізоване логування — використовуйте ELK Stack або Grafana Loki
- Моніторинг контейнерів — Prometheus, Grafana, cAdvisor
- Health checks — перевірка стану контейнерів
# Приклад додавання health check в docker-compose.yml
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
4. CI/CD інтеграція
- Автоматизована збірка — інтеграція з CI/CD системами
- Тегування за commit hash — унікальні ідентифікатори образів
- Сканування коду та образів — частина піпелайну
5. Продакшн налаштування
- Обмеження ресурсів — встановлюйте ліміти CPU і пам'яті
- Restart policies — автоматичний перезапуск при збоях
- Оркестрація — використовуйте Kubernetes або Docker Swarm
# Приклад запуску з обмеженням ресурсів
docker run -d --name api \
--cpus=0.5 \
--memory=512m \
--restart=unless-stopped \
my-api:1.0
Висновок
Docker революціонізував спосіб розробки, доставки та запуску програмного забезпечення. Він вирішує проблему "Працює на моєму комп'ютері", забезпечує ізоляцію, ефективне використання ресурсів та повторюваність середовища.
Ключові компоненти екосистеми Docker:
- Dockerfile — інструкції для побудови образів
- Docker Images — незмінні пакети з кодом та залежностями
- Docker Containers — запущені екземпляри образів
- Docker Compose — інструмент для багатоконтейнерних додатків
- Container Registry — репозиторії для збереження образів
Освоєння Docker та пов'язаних технологій є незамінним навиком для сучасних DevOps-інженерів та розробників, що дозволяє створювати більш надійні, масштабовані та ефективні системи.