Лаб. работа "Docker Compose: Управление многоконтейнерными приложениями"
Лабораторная работа по теме “Docker Compose: Управление многоконтейнерными приложениями”
Цель работы
Изучить инструмент Docker Compose для управления многоконтейнерными приложениями. Получить практические навыки создания и управления сложными приложениями, состоящими из нескольких сервисов, настройки сетей, томов и переменных окружения.
Краткие теоретические сведения
Docker Compose — это инструмент для определения и запуска многоконтейнерных Docker-приложений. Он позволяет описать всю инфраструктуру приложения в одном файле docker-compose.yml и управлять всем стеком с помощью простых команд.
Ключевые концепции Docker Compose:
- Сервисы (Services) — каждый сервис представляет собой контейнер, который будет запущен. Сервисы могут использовать готовые образы или собираться из Dockerfile.
- Сети (Networks) — обеспечивают изолированное взаимодействие между контейнерами. По умолчанию создается сеть
default, но можно создать собственные. - Тома (Volumes) — используются для персистентного хранения данных. Могут быть именованными томами или bind mounts.
- Зависимости (depends_on) — определяют порядок запуска сервисов и гарантируют, что сервис не запустится до готовности зависимых сервисов.
- Переменные окружения — позволяют гибко конфигурировать сервисы для разных окружений.
Преимущества Docker Compose:
- Декларативное описание всей инфраструктуры
- Простота развертывания и масштабирования
- Воспроизводимость окружений
- Управление сложными многокомпонентными приложениями
Краткий справочник по командам Docker Compose
Основные команды
docker-compose up— запуск всех сервисов, описанных в docker-compose.ymldocker-compose up -d— запуск в фоновом режиме (detached)docker-compose down— остановка и удаление всех контейнеров, сетей и томовdocker-compose ps— просмотр статуса сервисовdocker-compose logs— просмотр логов всех сервисовdocker-compose logs -f— просмотр логов в реальном времениdocker-compose restart— перезапуск всех сервисовdocker-compose build— пересборка образов для сервисовdocker-compose exec <service> <command>— выполнение команды в контейнере сервиса
Команды для работы с отдельными сервисами
docker-compose up <service>— запуск конкретного сервисаdocker-compose stop <service>— остановка конкретного сервисаdocker-compose start <service>— запуск остановленного сервисаdocker-compose logs <service>— логи конкретного сервисаdocker-compose exec <service> bash— подключение к командной оболочке сервиса
Команды для очистки
docker-compose down -v— удаление томов вместе с контейнерамиdocker-compose down --rmi all— удаление всех образовdocker-compose down --remove-orphans— удаление осиротевших контейнеров
Требования к окружению
- Операционная система: Debian 13 “Trixie” или новее
- Docker Engine установлен и настроен
- Docker Compose установлен (обычно входит в состав Docker)
- Доступ в Интернет для загрузки образов
- Учетная запись пользователя без прав
root - Текстовый редактор (nano, vim или другой)
Порядок выполнения работы
Часть 1. Проверка установки Docker Compose
Проверка версии Docker Compose Убедитесь, что Docker Compose установлен и работает корректно.
1docker-compose --version 2# или для Docker Compose V2 3docker compose versionПроверка доступности Docker Убедитесь, что Docker Engine работает:
1docker version
Часть 2. Создание простого веб-приложения
Создание рабочей директории Создайте директорию для работы с Docker Compose:
1mkdir ~/docker-compose-lab 2cd ~/docker-compose-labСоздание простого веб-приложения Создайте файл
app.pyс простым Flask-приложением:1from flask import Flask, jsonify 2import os 3import socket 4 5app = Flask(__name__) 6 7@app.route('/') 8def hello(): 9 return jsonify({ 10 'message': 'Hello from Docker Compose!', 11 'hostname': socket.gethostname(), 12 'container_id': os.environ.get('HOSTNAME', 'unknown') 13 }) 14 15@app.route('/health') 16def health(): 17 return jsonify({'status': 'healthy'}), 200 18 19@app.route('/info') 20def info(): 21 return jsonify({ 22 'container_id': os.environ.get('HOSTNAME', 'unknown'), 23 'python_version': os.sys.version, 24 'environment': os.environ.get('ENVIRONMENT', 'development') 25 }) 26 27if __name__ == '__main__': 28 app.run(host='0.0.0.0', port=5000)Создание requirements.txt Создайте файл с зависимостями:
1flask==2.3.3 2requests==2.31.0Создание Dockerfile для приложения Создайте файл
Dockerfile:1FROM python:3.11-slim 2 3WORKDIR /app 4 5COPY requirements.txt . 6RUN pip install --no-cache-dir -r requirements.txt 7 8COPY app.py . 9 10EXPOSE 5000 11 12CMD ["python", "app.py"]
Часть 3. Создание первого docker-compose.yml
Создание базового docker-compose.yml Создайте файл
docker-compose.yml:1version: '3.8' 2 3services: 4 web: 5 build: . 6 ports: 7 - "5000:5000" 8 environment: 9 - ENVIRONMENT=development 10 volumes: 11 - .:/app 12 restart: unless-stoppedЗапуск приложения Запустите приложение с помощью Docker Compose:
1docker-compose up --buildПриложение будет доступно по адресу
http://localhost:5000. Проверьте работу:1curl http://localhost:5000 2curl http://localhost:5000/health 3curl http://localhost:5000/infoЗапуск в фоновом режиме Остановите приложение (Ctrl+C) и запустите в фоновом режиме:
1docker-compose up -d --buildПросмотр статуса сервисов Проверьте статус запущенных сервисов:
1docker-compose psПросмотр логов Посмотрите логи приложения:
1docker-compose logs 2docker-compose logs -f web
Часть 4. Добавление базы данных
Создание обновленного docker-compose.yml Обновите
docker-compose.yml, добавив PostgreSQL:1version: '3.8' 2 3services: 4 web: 5 build: . 6 ports: 7 - "5000:5000" 8 environment: 9 - ENVIRONMENT=development 10 - DATABASE_URL=postgresql://user:password@db:5432/myapp 11 volumes: 12 - .:/app 13 depends_on: 14 - db 15 restart: unless-stopped 16 17 db: 18 image: postgres:15-alpine 19 environment: 20 POSTGRES_DB: myapp 21 POSTGRES_USER: user 22 POSTGRES_PASSWORD: password 23 volumes: 24 - db_data:/var/lib/postgresql/data 25 ports: 26 - "5432:5432" 27 restart: unless-stopped 28 29volumes: 30 db_data:Обновление приложения для работы с БД Обновите
app.pyдля работы с PostgreSQL:1from flask import Flask, jsonify 2import os 3import socket 4import psycopg2 5from psycopg2 import OperationalError 6 7app = Flask(__name__) 8 9def get_db_connection(): 10 try: 11 conn = psycopg2.connect( 12 host=os.environ.get('DB_HOST', 'db'), 13 database=os.environ.get('POSTGRES_DB', 'myapp'), 14 user=os.environ.get('POSTGRES_USER', 'user'), 15 password=os.environ.get('POSTGRES_PASSWORD', 'password') 16 ) 17 return conn 18 except OperationalError as e: 19 return None 20 21@app.route('/') 22def hello(): 23 conn = get_db_connection() 24 if conn: 25 try: 26 cur = conn.cursor() 27 cur.execute("SELECT version();") 28 db_version = cur.fetchone()[0] 29 cur.close() 30 conn.close() 31 db_status = "connected" 32 except Exception as e: 33 db_status = f"error: {str(e)}" 34 else: 35 db_status = "disconnected" 36 37 return jsonify({ 38 'message': 'Hello from Docker Compose!', 39 'hostname': socket.gethostname(), 40 'container_id': os.environ.get('HOSTNAME', 'unknown'), 41 'database_status': db_status 42 }) 43 44@app.route('/health') 45def health(): 46 conn = get_db_connection() 47 if conn: 48 conn.close() 49 return jsonify({'status': 'healthy', 'database': 'connected'}), 200 50 else: 51 return jsonify({'status': 'unhealthy', 'database': 'disconnected'}), 503 52 53@app.route('/info') 54def info(): 55 return jsonify({ 56 'container_id': os.environ.get('HOSTNAME', 'unknown'), 57 'python_version': os.sys.version, 58 'environment': os.environ.get('ENVIRONMENT', 'development'), 59 'database_url': os.environ.get('DATABASE_URL', 'not configured') 60 }) 61 62if __name__ == '__main__': 63 app.run(host='0.0.0.0', port=5000)Обновление requirements.txt Добавьте зависимость для PostgreSQL:
1flask==2.3.3 2requests==2.31.0 3psycopg2-binary==2.9.7Перезапуск с новой конфигурацией Остановите текущие сервисы и запустите с новой конфигурацией:
1docker-compose down 2docker-compose up -d --buildПроверка работы с базой данных Проверьте работу приложения:
1curl http://localhost:5000 2curl http://localhost:5000/health
Часть 5. Работа с сетями
Создание пользовательских сетей Обновите
docker-compose.ymlдля использования пользовательских сетей:1version: '3.8' 2 3services: 4 web: 5 build: . 6 ports: 7 - "5000:5000" 8 environment: 9 - ENVIRONMENT=development 10 - DATABASE_URL=postgresql://user:password@db:5432/myapp 11 volumes: 12 - .:/app 13 depends_on: 14 - db 15 networks: 16 - frontend 17 - backend 18 restart: unless-stopped 19 20 db: 21 image: postgres:15-alpine 22 environment: 23 POSTGRES_DB: myapp 24 POSTGRES_USER: user 25 POSTGRES_PASSWORD: password 26 volumes: 27 - db_data:/var/lib/postgresql/data 28 networks: 29 - backend 30 restart: unless-stopped 31 32networks: 33 frontend: 34 driver: bridge 35 backend: 36 driver: bridge 37 internal: true 38 39volumes: 40 db_data:Перезапуск с новой конфигурацией Примените изменения:
1docker-compose down 2docker-compose up -d --buildПроверка сетей Посмотрите созданные сети:
1docker network ls 2docker network inspect docker-compose-lab_frontend 3docker network inspect docker-compose-lab_backend
Часть 6. Добавление Redis
Добавление Redis в docker-compose.yml Обновите конфигурацию, добавив Redis:
1version: '3.8' 2 3services: 4 web: 5 build: . 6 ports: 7 - "5000:5000" 8 environment: 9 - ENVIRONMENT=development 10 - DATABASE_URL=postgresql://user:password@db:5432/myapp 11 - REDIS_URL=redis://redis:6379 12 volumes: 13 - .:/app 14 depends_on: 15 - db 16 - redis 17 networks: 18 - frontend 19 - backend 20 restart: unless-stopped 21 22 db: 23 image: postgres:15-alpine 24 environment: 25 POSTGRES_DB: myapp 26 POSTGRES_USER: user 27 POSTGRES_PASSWORD: password 28 volumes: 29 - db_data:/var/lib/postgresql/data 30 networks: 31 - backend 32 restart: unless-stopped 33 34 redis: 35 image: redis:7-alpine 36 networks: 37 - backend 38 restart: unless-stopped 39 40networks: 41 frontend: 42 driver: bridge 43 backend: 44 driver: bridge 45 internal: true 46 47volumes: 48 db_data:Обновление приложения для работы с Redis Обновите
app.py:1from flask import Flask, jsonify 2import os 3import socket 4import psycopg2 5import redis 6from psycopg2 import OperationalError 7from redis import ConnectionError as RedisConnectionError 8 9app = Flask(__name__) 10 11def get_db_connection(): 12 try: 13 conn = psycopg2.connect( 14 host=os.environ.get('DB_HOST', 'db'), 15 database=os.environ.get('POSTGRES_DB', 'myapp'), 16 user=os.environ.get('POSTGRES_USER', 'user'), 17 password=os.environ.get('POSTGRES_PASSWORD', 'password') 18 ) 19 return conn 20 except OperationalError as e: 21 return None 22 23def get_redis_connection(): 24 try: 25 r = redis.Redis( 26 host=os.environ.get('REDIS_HOST', 'redis'), 27 port=6379, 28 decode_responses=True 29 ) 30 r.ping() 31 return r 32 except RedisConnectionError: 33 return None 34 35@app.route('/') 36def hello(): 37 conn = get_db_connection() 38 redis_conn = get_redis_connection() 39 40 db_status = "disconnected" 41 redis_status = "disconnected" 42 43 if conn: 44 try: 45 cur = conn.cursor() 46 cur.execute("SELECT version();") 47 db_version = cur.fetchone()[0] 48 cur.close() 49 conn.close() 50 db_status = "connected" 51 except Exception as e: 52 db_status = f"error: {str(e)}" 53 54 if redis_conn: 55 try: 56 redis_conn.set('hello_count', 0, ex=3600) 57 redis_conn.incr('hello_count') 58 redis_status = "connected" 59 except Exception as e: 60 redis_status = f"error: {str(e)}" 61 62 return jsonify({ 63 'message': 'Hello from Docker Compose!', 64 'hostname': socket.gethostname(), 65 'container_id': os.environ.get('HOSTNAME', 'unknown'), 66 'database_status': db_status, 67 'redis_status': redis_status 68 }) 69 70@app.route('/health') 71def health(): 72 conn = get_db_connection() 73 redis_conn = get_redis_connection() 74 75 db_healthy = conn is not None 76 redis_healthy = redis_conn is not None 77 78 if conn: 79 conn.close() 80 if redis_conn: 81 redis_conn.close() 82 83 if db_healthy and redis_healthy: 84 return jsonify({'status': 'healthy', 'database': 'connected', 'redis': 'connected'}), 200 85 else: 86 return jsonify({ 87 'status': 'unhealthy', 88 'database': 'connected' if db_healthy else 'disconnected', 89 'redis': 'connected' if redis_healthy else 'disconnected' 90 }), 503 91 92@app.route('/info') 93def info(): 94 return jsonify({ 95 'container_id': os.environ.get('HOSTNAME', 'unknown'), 96 'python_version': os.sys.version, 97 'environment': os.environ.get('ENVIRONMENT', 'development'), 98 'database_url': os.environ.get('DATABASE_URL', 'not configured'), 99 'redis_url': os.environ.get('REDIS_URL', 'not configured') 100 }) 101 102if __name__ == '__main__': 103 app.run(host='0.0.0.0', port=5000)Обновление requirements.txt Добавьте зависимость для Redis:
1flask==2.3.3 2requests==2.31.0 3psycopg2-binary==2.9.7 4redis==4.6.0Перезапуск с полным стеком Запустите полный стек приложений:
1docker-compose down 2docker-compose up -d --buildПроверка работы всех сервисов Проверьте работу всех компонентов:
1curl http://localhost:5000 2curl http://localhost:5000/health 3curl http://localhost:5000/info
Часть 7. Использование переменных окружения
Создание .env файла Создайте файл
.env:1# Database configuration 2POSTGRES_DB=myapp 3POSTGRES_USER=appuser 4POSTGRES_PASSWORD=secure_password_123 5 6# Application configuration 7ENVIRONMENT=production 8DEBUG=false 9 10# Redis configuration 11REDIS_PASSWORD=redis_password_456Обновление docker-compose.yml для использования переменных Обновите
docker-compose.yml:1version: '3.8' 2 3services: 4 web: 5 build: . 6 ports: 7 - "5000:5000" 8 environment: 9 - ENVIRONMENT=${ENVIRONMENT} 10 - DEBUG=${DEBUG} 11 - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:${POSTGRES_DB} 12 - REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379 13 volumes: 14 - .:/app 15 depends_on: 16 - db 17 - redis 18 networks: 19 - frontend 20 - backend 21 restart: unless-stopped 22 23 db: 24 image: postgres:15-alpine 25 environment: 26 POSTGRES_DB: ${POSTGRES_DB} 27 POSTGRES_USER: ${POSTGRES_USER} 28 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} 29 volumes: 30 - db_data:/var/lib/postgresql/data 31 networks: 32 - backend 33 restart: unless-stopped 34 35 redis: 36 image: redis:7-alpine 37 command: redis-server --requirepass ${REDIS_PASSWORD} 38 networks: 39 - backend 40 restart: unless-stopped 41 42networks: 43 frontend: 44 driver: bridge 45 backend: 46 driver: bridge 47 internal: true 48 49volumes: 50 db_data:Перезапуск с переменными окружения Примените изменения:
1docker-compose down 2docker-compose up -d --build
Часть 8. Масштабирование сервисов
Масштабирование веб-сервиса Запустите несколько экземпляров веб-сервиса:
1docker-compose up -d --scale web=3Проверка масштабирования Посмотрите статус всех сервисов:
1docker-compose psТестирование балансировки нагрузки Выполните несколько запросов для проверки распределения нагрузки:
1for i in {1..10}; do curl http://localhost:5000; echo; done
Часть 9. Мониторинг и отладка
Просмотр логов всех сервисов Посмотрите логи всех сервисов:
1docker-compose logs 2docker-compose logs -fПросмотр логов конкретного сервиса Посмотрите логи конкретного сервиса:
1docker-compose logs web 2docker-compose logs db 3docker-compose logs redisВыполнение команд в контейнерах Подключитесь к контейнеру веб-сервиса:
1docker-compose exec web bashВнутри контейнера выполните:
1ls -la 2cat app.py 3exitПроверка сетевого взаимодействия Проверьте доступность сервисов из контейнера:
1docker-compose exec web ping db 2docker-compose exec web ping redis
Часть 10. Очистка ресурсов
Остановка всех сервисов Остановите все сервисы:
1docker-compose downПолная очистка с удалением томов Удалите все ресурсы, включая тома:
1docker-compose down -vПроверка очистки Проверьте, что ресурсы удалены:
1docker-compose ps 2docker network ls 3docker volume ls
Задания для самостоятельного выполнения
Создание многоэтапного приложения Создайте приложение, состоящее из:
- Frontend (React/Vue.js приложение)
- Backend API (Node.js/Python Flask)
- База данных (PostgreSQL)
- Кэш (Redis)
- Nginx как reverse proxy
Использование профилей Создайте профили для development и production окружений. В development профиле добавьте:
- Adminer для управления БД
- Redis Commander для управления Redis
- Монтирование исходного кода
Настройка health checks Добавьте health checks для всех сервисов в docker-compose.yml. Настройте:
- Проверку доступности БД
- Проверку API endpoints
- Проверку Redis
Создание backup скрипта Создайте скрипт для автоматического backup базы данных с использованием volumes и cron.
Контрольные вопросы
- Что такое Docker Compose и в чем его отличие от Docker?
- Какие основные секции есть в docker-compose.yml файле?
- Как работает секция
depends_onи какие проблемы она решает? - В чем разница между volumes и bind mounts в Docker Compose?
- Как создать пользовательские сети и зачем это нужно?
- Как использовать переменные окружения в Docker Compose?
- Что такое масштабирование сервисов и как его реализовать?
- Как настроить health checks для сервисов?
- В чем преимущества использования профилей в Docker Compose?
- Как организовать backup и восстановление данных в Docker Compose?
Требования к отчету
Отчет по лабораторной работе должен содержать:
- Титульный лист
- Цель работы
- Пошаговое описание выполнения работы с приведением всех вводимых команд и их выводов (можно в виде скриншотов или текстовых блоков)
- Содержимое созданного docker-compose.yml файла с комментариями
- Результаты тестирования всех endpoints приложения
- Письменные ответы на контрольные вопросы
- Вывод, в котором необходимо кратко описать полученные знания и навыки, а также привести примеры использования Docker Compose в реальных проектах