← Назад к вопросам

Как передать динамический параметр из CI в Docker при сборке образа?

2.0 Middle🔥 191 комментариев
#MLOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Передача динамических параметров в Docker при сборке

Есть несколько способов передать параметры из CI в Docker-образ. Выбор зависит от типа параметров и способа их использования в контейнере.

Метод 1: Docker Build Arguments (ARG)

Это самый чистый способ для параметров, нужных только при сборке.

Dockerfile

# Декларируем аргументы с дефолтными значениями
ARG VERSION=1.0.0
ARG BUILD_DATE
ARG GIT_COMMIT
ARG MODEL_REGISTRY=default-registry

# Используем аргументы для сборки
FROM python:3.11-slim as builder

RUN echo "Building version: $VERSION" && \
    echo "Build date: $BUILD_DATE" && \
    echo "Git commit: $GIT_COMMIT"

WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt

# Сохраняем параметры в файл для будущего использования
RUN echo "VERSION=$VERSION" > /app/build_info.txt && \
    echo "BUILD_DATE=$BUILD_DATE" >> /app/build_info.txt && \
    echo "GIT_COMMIT=$GIT_COMMIT" >> /app/build_info.txt

# Финальный этап
FROM python:3.11-slim
COPY --from=builder /app /app
WORKDIR /app

ENTRYPOINT ["python", "main.py"]

Передача параметров из CI (GitHub Actions)

name: Build and Push Docker Image

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set build variables
        id: vars
        run: |
          echo "version=$(cat VERSION.txt)" >> $GITHUB_OUTPUT
          echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
          echo "git_commit=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
      
      - name: Build Docker image
        run: |
          docker build \
            --build-arg VERSION=${{ steps.vars.outputs.version }} \
            --build-arg BUILD_DATE=${{ steps.vars.outputs.build_date }} \
            --build-arg GIT_COMMIT=${{ steps.vars.outputs.git_commit }} \
            --build-arg MODEL_REGISTRY=${{ secrets.MODEL_REGISTRY }} \
            -t my-app:${{ steps.vars.outputs.version }} \
            .
      
      - name: Push to registry
        run: |
          docker push my-app:${{ steps.vars.outputs.version }}

Передача параметров из CI (GitLab CI)

build_docker:
  image: docker:latest
  services:
    - docker:dind
  
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
  
  script:
    - export VERSION=$(cat VERSION.txt)
    - export BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
    - export GIT_COMMIT=${CI_COMMIT_SHA:0:7}
    
    - docker build \
        --build-arg VERSION=$VERSION \
        --build-arg BUILD_DATE=$BUILD_DATE \
        --build-arg GIT_COMMIT=$GIT_COMMIT \
        --build-arg MODEL_REGISTRY=$MODEL_REGISTRY \
        -t $CI_REGISTRY_IMAGE:$VERSION \
        .
    
    - docker push $CI_REGISTRY_IMAGE:$VERSION
  
  only:
    - tags
    - main

Метод 2: Environment Variables (ENV) для runtime

Эсли параметры нужны во время работы контейнера, используй ENV:

Dockerfile

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Дефолтные переменные окружения
ENV LOG_LEVEL=INFO
ENV MODEL_VERSION=latest
ENV API_ENDPOINT=http://localhost:8000

EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]

Передача при запуске контейнера

# Docker run
docker run \
  -e LOG_LEVEL=DEBUG \
  -e MODEL_VERSION=v2.1.0 \
  -e API_ENDPOINT=http://api.example.com:8000 \
  my-app:latest

# Docker Compose
services:
  ml_service:
    image: my-app:latest
    environment:
      LOG_LEVEL: ${LOG_LEVEL:-DEBUG}
      MODEL_VERSION: ${MODEL_VERSION:-latest}
      API_ENDPOINT: ${API_ENDPOINT:-http://localhost:8000}
      DATABASE_URL: ${DATABASE_URL}

Передача из CI в runtime

# GitHub Actions: передача в docker run
- name: Run tests in container
  run: |
    docker run \
      -e CI_ENVIRONMENT=github-actions \
      -e BUILD_ID=${{ github.run_id }} \
      -e LOG_LEVEL=DEBUG \
      my-app:test pytest tests/

# Kubernetes (если деплойишь в K8s)
- name: Deploy to Kubernetes
  env:
    MODEL_VERSION: ${{ steps.vars.outputs.version }}
  run: |
    kubectl set env deployment/ml-service \
      MODEL_VERSION=$MODEL_VERSION \
      BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')

Метод 3: .env файл для конфигурации

Для сложных сценариев передай целый файл конфигурации:

Dockerfile

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Создаём пустой .env для дефолтов
RUN echo "# Default configuration" > .env.default

CMD ["python", "-m", "uvicorn", "main:app"]

GitHub Actions

- name: Create config file
  run: |
    cat > .env.ci << EOF
    ENVIRONMENT=ci
    VERSION=${{ steps.vars.outputs.version }}
    BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
    GIT_COMMIT=${{ github.sha }}
    MODEL_REGISTRY=${{ secrets.MODEL_REGISTRY }}
    API_KEY=${{ secrets.API_KEY }}
    EOF

- name: Build Docker image with config
  run: |
    docker build \
      --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
      -t my-app:ci \
      .
    
    # Копируем конфиг в образ при сборке
    docker run --rm \
      -v $(pwd)/.env.ci:/tmp/.env.ci \
      alpine:latest \
      cp /tmp/.env.ci /app/.env

Метод 4: Multi-stage build для передачи информации

Этот метод сохраняет информацию о сборке в финальном образе:

ARG VERSION=unknown
ARG BUILD_DATE=unknown
ARG GIT_COMMIT=unknown

FROM python:3.11-slim as builder
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.11-slim
WORKDIR /app

# Копируем результат сборки
COPY --from=builder /app /app

# Сохраняем метаданные в образе
LABEL version="${VERSION}" \
      build_date="${BUILD_DATE}" \
      git_commit="${GIT_COMMIT}"

# Сохраняем в файл для использования в приложении
RUN mkdir -p /app/metadata && \
    echo "${VERSION}" > /app/metadata/version && \
    echo "${BUILD_DATE}" > /app/metadata/build_date && \
    echo "${GIT_COMMIT}" > /app/metadata/git_commit

ENTRYPOINT ["python", "main.py"]

Python код для чтения метаданных

import os
from pathlib import Path

class BuildInfo:
    @staticmethod
    def get_version():
        version_file = Path('/app/metadata/version')
        if version_file.exists():
            return version_file.read_text().strip()
        return os.getenv('VERSION', 'unknown')
    
    @staticmethod
    def get_build_date():
        build_file = Path('/app/metadata/build_date')
        if build_file.exists():
            return build_file.read_text().strip()
        return os.getenv('BUILD_DATE', 'unknown')
    
    @staticmethod
    def get_git_commit():
        commit_file = Path('/app/metadata/git_commit')
        if commit_file.exists():
            return commit_file.read_text().strip()
        return os.getenv('GIT_COMMIT', 'unknown')

# Использование
from fastapi import FastAPI

app = FastAPI()
build_info = BuildInfo()

@app.get('/health')
def health():
    return {
        'status': 'healthy',
        'version': build_info.get_version(),
        'build_date': build_info.get_build_date(),
        'git_commit': build_info.get_git_commit()
    }

Метод 5: Docker Buildkit secrets (для sensitive данных)

Для передачи секретов безопасно (без видимости в истории):

# syntax=docker/dockerfile:1.4

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .

# Передача секрета при сборке
RUN --mount=type=secret,id=api_key \
    export API_KEY=$(cat /run/secrets/api_key) && \
    pip install --no-cache-dir -r requirements.txt

COPY . .
CMD ["python", "main.py"]

Передача секрета из CI

# CLI
docker build \
  --secret api_key=${{ secrets.API_KEY }} \
  --secret model_registry=${{ secrets.MODEL_REGISTRY }} \
  -t my-app:latest \
  .

# Docker Compose (v1.40+)
services:
  ml_app:
    build:
      context: .
      secrets:
        - api_key
        - model_registry
secrets:
  api_key:
    environment: API_KEY_ENV
  model_registry:
    environment: MODEL_REGISTRY_ENV

Сравнение методов

МетодСлучай использованияВидно в образеБезопасность
ARGПараметры сборкиНетСредняя
ENVRuntime конфигДаНизкая
.env fileСложная конфигДаСредняя
LabelsМетаданныеДаВысокая
SecretsCredentailsНетВысокая

Рекомендации

  1. Версия + Build metadata: используй ARG + LABEL
  2. Конфигурация приложения: используй ENV + .env файлы
  3. Секреты (API ключи): используй Buildkit secrets или передавай в runtime
  4. Логирование информации: сохраняй в метаданных образа и в файлы внутри контейнера

Это позволит отслеживать какой код и конфигурация используется в каждом деплойменте.

Как передать динамический параметр из CI в Docker при сборке образа? | PrepBro