Сборка Docker-образов в пайплайне, тестирование контейнеризованных приложений.
Интеграция Docker в CI-пайплайны позволяет создавать воспроизводимые окружения для сборки и тестирования. Изучите основы работы с Docker в GitHub Actions и GitLab CI.
Docker в CI-пайплайнах решает ключевые проблемы:
┌─────────────────────────────────────────────────────────────┐
│ CI Pipeline │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Build │ → │ Test │ → │ Deploy │ │
│ │ Docker │ │ in │ │ Image │ │
│ │ Image │ │ Container│ │ to │ │
│ │ │ │ │ │ Registry│ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
# Базовая сборка
docker build -t myapp:latest .
# Сборка с указанием Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .
# Сборка с build-arg
docker build --build-arg ENV=production -t myapp:prod .
# Сборка без кэша (для воспроизводимости)
docker build --no-cache -t myapp:latest .# Запуск с автoудалением
docker run --rm myapp:latest npm test
# Запуск с переменными окружения
docker run --rm -e DB_HOST=localhost -e DB_PORT=5432 myapp:latest pytest
# Запуск с монтированием volume
docker run --rm -v $(pwd)/tests:/app/tests myapp:latest pytest
# Запуск с сетью для интеграционных тестов
docker run --rm --network=host myapp:latest pytest# Удаление всех остановленных контейнеров
docker container prune -f
# Удаление неиспользуемых образов
docker image prune -f
# Полная очистка (включая build cache)
docker system prune -f --volumes
# Очистка buildx cache
docker buildx prune -fname: Docker Build and Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run tests in container
run: docker run --rm myapp:${{ github.sha }} npm test
- name: Cleanup
if: always()
run: docker system prune -fname: Docker Compose Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start services with Docker Compose
run: docker compose up -d
- name: Wait for services to be ready
run: |
echo "Waiting for database..."
sleep 10
- name: Run integration tests
run: docker compose exec -T app pytest tests/integration/
- name: Show logs on failure
if: failure()
run: docker compose logs
- name: Cleanup
if: always()
run: docker compose down -vversion: '3.8'
services:
app:
build: .
environment:
- DB_HOST=db
- DB_PORT=5432
- DB_NAME=testdb
depends_on:
db:
condition: service_healthy
command: pytest tests/
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=testdb
- POSTGRES_USER=test
- POSTGRES_PASSWORD=test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test"]
interval: 5s
timeout: 5s
retries: 5name: Build with Buildx
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build image
uses: docker/build-push-action@v5
with:
context: .
tags: myapp:${{ github.sha }}
load: true # Загрузить в локальный Docker
- name: Run tests
run: docker run --rm myapp:${{ github.sha }} npm teststages:
- build
- test
- deploy
variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:
stage: build
image: docker:24-dind
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_NAME .
- docker push $IMAGE_NAME
test:
stage: test
image: docker:24-dind
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $IMAGE_NAME
- docker run --rm $IMAGE_NAME npm test
needs: ["build"]# Для сложных сценариев с Docker Compose
test:
stage: test
image:
name: docker:24-dind
services:
- name: docker:24-dind
command: ["--experimental"]
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
script:
- docker compose up -d
- sleep 10
- docker compose exec -T app pytest
- docker compose down -vbuild:
stage: build
image: docker:24-dind
services:
- docker:24-dind
variables:
DOCKER_TLS_CERTDIR: ""
script:
# Пытаемся загрузить кэшированный образ
- docker pull $CI_REGISTRY_IMAGE:cache || true
# Собираем с кэшем
- >
docker build
--cache-from $CI_REGISTRY_IMAGE:cache
-t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
-t $CI_REGISTRY_IMAGE:cache
.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:cache# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Запуск тестов по умолчанию
CMD ["pytest", "tests/"]# GitHub Actions
- name: Run unit tests
run: docker run --rm myapp:latest pytest tests/unit/ -v# docker-compose.test.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
environment:
- DATABASE_URL=postgresql://test:test@db:5432/testdb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
command: pytest tests/integration/
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=testdb
- POSTGRES_USER=test
- POSTGRES_PASSWORD=test
redis:
image: redis:7-alpine# Workflow
- name: Run integration tests
run: docker compose -f docker-compose.test.yml up --abort-on-container-exit# docker-compose.e2e.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- DEBUG=true
selenium:
image: selenium/standalone-chrome:latest
ports:
- "4444:4444"
shm_size: 2gb
e2e-tests:
build:
context: .
dockerfile: Dockerfile.e2e
depends_on:
- app
- selenium
environment:
- BASE_URL=http://app:8000
- SELENIUM_URL=http://selenium:4444/wd/hub# Создать сеть
docker network create test-network
# Запустить контейнеры в сети
docker run -d --network=test-network --name=db postgres:15
docker run --rm --network=test-network -e DB_HOST=db myapp:latest pytest- name: Create test network
run: docker network create test-net
- name: Start database
run: docker run -d --network=test-net --name=db -e POSTGRES_PASSWORD=test postgres:15
- name: Run tests
run: docker run --rm --network=test-net -e DB_HOST=db myapp:latest pytest
- name: Cleanup
if: always()
run: |
docker stop db
docker network rm test-net- name: Run tests
id: tests
run: docker run --rm myapp:latest pytest
- name: Show container logs on failure
if: failure()
run: docker logs $(docker ps -aq --filter "ancestor=myapp:latest") | head -100- name: Debug on failure
if: failure()
run: |
echo "Test failed. Container info:"
docker ps -a --filter "ancestor=myapp:latest"
docker logs $(docker ps -q --filter "ancestor=myapp:latest" | head -1)# Плохо — тег может измениться
FROM python:latest
# Хорошо — фиксированная версия
FROM python:3.11.7-slim
# Лучше — SHA256 для полной воспроизводимости
FROM python@sha256:abc123def456...# Используйте slim-образы для тестов
FROM python:3.11-slim
# Устанавливайте только необходимые зависимости
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*- name: Cleanup Docker
if: always()
run: |
docker stop $(docker ps -aq) || true
docker system prune -f --volumes# Копируйте зависимости первыми для кэширования
COPY requirements.txt .
RUN pip install -r requirements.txt
# Затем копируйте код
COPY . .# .dockerignore
.git
.gitignore
__pycache__
*.pyc
.pytest_cache
.coverage
htmlcov/
.env
.venv
node_modules
Docker в CI-пайплайнах обеспечивает:
Ключевые команды:
docker build -t name:tag . — сборка образаdocker run --rm — запуск с автoудалениемdocker system prune -f — очистка ресурсовdocker compose up -d — запуск мультиконтейнерных тестовВ следующей теме вы изучите работу с Docker-реестрами для публикации и хранения образов.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.