← Назад к вопросам
Как передать динамический параметр из 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 | Параметры сборки | Нет | Средняя |
| ENV | Runtime конфиг | Да | Низкая |
| .env file | Сложная конфиг | Да | Средняя |
| Labels | Метаданные | Да | Высокая |
| Secrets | Credentails | Нет | Высокая |
Рекомендации
- Версия + Build metadata: используй ARG + LABEL
- Конфигурация приложения: используй ENV + .env файлы
- Секреты (API ключи): используй Buildkit secrets или передавай в runtime
- Логирование информации: сохраняй в метаданных образа и в файлы внутри контейнера
Это позволит отслеживать какой код и конфигурация используется в каждом деплойменте.