Как выполнить донастройку контейнера при запуске

«Как выполнить донастройку контейнера при запуске» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В DevOps-практике донастройка контейнеров при запуске — обычная задача. Я использую несколько проверенных подходов в зависимости от требований.

1. Entrypoint-скрипты (самый частый случай):

# Dockerfile
FROM alpine:3.18
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
#!/bin/sh
# entrypoint.sh
set -e

# Динамическая генерация конфига из переменных окружения
if [ -n "$DB_HOST" ]; then
    sed -i "s/localhost/$DB_HOST/g" /etc/app/config.yaml
fi

# Создание необходимых директорий с правильными правами
mkdir -p /var/log/app && chown app:app /var/log/app

# Запуск основного процесса (важно использовать exec)
exec "$@"

2. Многоступенчатая инициализация через Init-контейнеры (Kubernetes):

# deployment.yaml
spec:
  initContainers:
  - name: init-config
    image: alpine:3.18
    command:
    - sh
    - -c
    - |
      # Скачиваем конфиг из S3 или Vault
      aws s3 cp s3://config-bucket/app-config.yaml /shared-config/
      # Ждем готовности БД
      until nc -z $DB_HOST 5432; do sleep 2; done
    volumeMounts:
    - name: shared-config
      mountPath: /shared-config
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: shared-config
      mountPath: /etc/app/config

3. Динамическая конфигурация через ConfigMap и Volumes:

# configmap-generator.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  config.yaml: |
    database:
      host: ${DB_HOST}
      port: 5432
    logging:
      level: ${LOG_LEVEL:-INFO}
---
# Используем envsubst для подстановки переменных
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: app
        command:
        - sh
        - -c
        - |
          export DB_HOST="$DB_HOST"
          envsubst < /config-templates/config.yaml > /etc/app/config.yaml
          exec /app/start.sh

4. Использование специализированных инструментов:

Для сложных случаев применяю:

  • envsubst (из пакета gettext) для шаблонизации
  • confd для динамического обновления конфигов
  • Consul Template в связке с Service Discovery

Пример из реального проекта (PostgreSQL + wal-g):

# Dockerfile для PostgreSQL с настройкой бэкапов
FROM postgres:15-alpine

COPY docker-entrypoint-initdb.d /docker-entrypoint-initdb.d/
COPY setup-walg.sh /usr/local/bin/

RUN chmod +x /usr/local/bin/setup-walg.sh 
    && echo 'source /usr/local/bin/setup-walg.sh' >> /docker-entrypoint.sh

# setup-walg.sh настраивает WAL-G при старте контейнера
# на основе переменных окружения AWS_ACCESS_KEY_ID и т.д.

Ключевой принцип: Контейнер должен быть идемпотентным — при любом количестве перезапусков конфигурация применяется корректно.