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

Ответ

Для передачи динамических параметров из CI/CD в Docker используется механизм ARG (аргументов сборки).

1. Объявление аргумента в Dockerfile:

# Объявляем аргумент сборки
ARG APP_VERSION
ARG BUILD_ENV

# Используем его для установки переменной окружения
ENV APP_VERSION=${APP_VERSION}
ENV NODE_ENV=${BUILD_ENV}

# Или непосредственно в инструкциях
RUN echo "Building version ${APP_VERSION} for ${BUILD_ENV}"

2. Передача аргументов из CI/CD:

В GitLab CI (.gitlab-ci.yml):

build_image:
  script:
    - docker build 
      --build-arg APP_VERSION="$CI_COMMIT_TAG"
      --build-arg BUILD_ENV="$CI_ENVIRONMENT_SLUG"
      -t my-app:$CI_COMMIT_SHA .

В GitHub Actions:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build Docker image
        run: |
          docker build 
            --build-arg VERSION=${{ github.sha }} 
            --build-arg COMMIT_DATE="$(date -u)" 
            -t my-app:${{ github.sha }} .

3. Важные ограничения и best practices:

  • Жизненный цикл: Значения ARG доступны только на этапе docker build. Чтобы они были доступны в запущенном контейнере, их нужно явно скопировать в ENV.
  • Безопасность: Не используйте --build-arg для передачи секретов (паролей, токенов). Для этого предназначены docker build --secret (Docker BuildKit) или multi-stage сборка с временными файлами.
  • Кэширование: Изменение значения ARG инвалидирует кэш Docker для всех последующих инструкций.

Пример с условной логикой в Dockerfile:

ARG TARGET_ENV=development

# Устанавливаем разные пакеты в зависимости от окружения
RUN if [ "$TARGET_ENV" = "production" ]; then 
    apt-get install -y --no-install-recommends production-packages; 
    else 
    apt-get install -y development-tools; 
    fi

Ответ 18+ 🔞

А, слушай, тут простая, но хитрая тема — как из CI/CD пихать параметры в Docker. Ну, типа, версию сборки или окружение передать. Ёпта, без этого сейчас никуда.

1. Объявляем эти самые аргументы в Dockerfile: Смотри, в самом начале файла пишешь ARG. Это как объявить переменную, которую потом можно будет подменить при сборке.

# Объявляем аргумент сборки
ARG APP_VERSION
ARG BUILD_ENV

# Используем его для установки переменной окружения
ENV APP_VERSION=${APP_VERSION}
ENV NODE_ENV=${BUILD_ENV}

# Или непосредственно в инструкциях
RUN echo "Building version ${APP_VERSION} for ${BUILD_ENV}"

Зачем копировать в ENV? А потому что ARG — это только для этапа сборки, чувак. Как только контейнер запустился — всё, значения испарились. А ENV — это уже внутрь контейнера, для рантайма. Без этого нихуя не заработает.

2. А теперь самое интересное — как это всё передать из CI/CD: Тут уже зависит от твоего пайплайна.

Вот как в GitLab CI (.gitlab-ci.yml) это выглядит:

build_image:
  script:
    - docker build 
      --build-arg APP_VERSION="$CI_COMMIT_TAG"
      --build-arg BUILD_ENV="$CI_ENVIRONMENT_SLUG"
      -t my-app:$CI_COMMIT_SHA .

Видишь эти --build-arg? Вот ими и пихаем. GitLab сам подставляет свои переменные окружения, типа номера коммита или тега. Удобно, бля.

А в GitHub Actions примерно так же, только синтаксис другой:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build Docker image
        run: |
          docker build 
            --build-arg VERSION=${{ github.sha }} 
            --build-arg COMMIT_DATE="$(date -u)" 
            -t my-app:${{ github.sha }} .

В общем, принцип один — накатываешь флаги при вызове docker build, и всё.

3. Но есть важные подводные камни, ёбана!

  • Про жизнь аргументов: Я уже говорил — ARG живёт только пока docker build идёт. Хочешь, чтобы в запущенном контейнере было — копируй в ENV. Иначе будешь охуевать, почему переменная пустая.
  • Про безопасность — это пиздец важно: Никогда, блядь, не используй --build-arg для передачи секретов! Ни паролей, ни токенов, нихуя. Они останутся в истории сборки образа, любой, кто скачает образ, сможет их вытащить. Доверия к такому подходу — ебать ноль. Для секретов есть docker build --secret (если BuildKit включён) или многостадийная сборка с временными файлами.
  • Про кэширование: Если ты меняешь значение ARG — Docker сносит кэш нахуй для всех инструкций, которые идут после этого аргумента. Имей в виду, а то сборка будет вечность.

Вот ещё пример, если нужно по-разному собирать для dev и prod:

ARG TARGET_ENV=development

# Устанавливаем разные пакеты в зависимости от окружения
RUN if [ "$TARGET_ENV" = "production" ]; then 
    apt-get install -y --no-install-recommends production-packages; 
    else 
    apt-get install -y development-tools; 
    fi

Тут логика простая: если передали production — ставим одно, если нет (или передали development) — другое. Условные конструкции в RUN — твой друг, но не переусердствуй, а то Dockerfile превратится в пиздопроебибну.