Skip to content

Docker

Руководство по работе с Docker для Integ API.

Unified Docker Image

Проект использует единый Docker образ для всех окружений (local/dev/prod). Секреты инжектятся в runtime через Doppler.

Dockerfile

dockerfile
FROM node:20-alpine AS builder
WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app

# Doppler CLI для runtime injection
RUN apk add --no-cache curl && \
    curl -sLf https://cli.doppler.com/install.sh | sh && \
    apk del curl

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

EXPOSE 3000

CMD ["sh", "-c", "doppler run --config ${DOPPLER_CONFIG:-local} -- node ./dist/main.js"]

Преимущества

  • Один образ — билдится один раз, запускается где угодно
  • Безопасность — секреты не в образе, инжектятся в runtime
  • Гибкость — переключение окружения через переменную DOPPLER_CONFIG
  • Консистентность — идентичный образ в CI/CD и локально

Запуск контейнера

С Doppler (рекомендуется)

bash
# Pull образ
docker pull ghcr.io/happ-ai/integ-api:dev

# Запуск с Doppler
docker run -d \
  --name integ-api \
  -p 3000:3000 \
  -e DOPPLER_TOKEN=dp.st.xxxx \
  -e DOPPLER_CONFIG=local \
  ghcr.io/happ-ai/integ-api:dev

С переменными окружения напрямую

Если не хотите использовать Doppler, можно передать переменные напрямую:

bash
docker run -d \
  --name integ-api \
  -p 3000:3000 \
  -e POSTGRES_HOST=localhost \
  -e POSTGRES_PORT=5432 \
  -e POSTGRES_USERNAME=user \
  -e POSTGRES_PASSWORD=password \
  -e POSTGRES_NAME=integ-db \
  -e JWT_SECRET=your-secret \
  ghcr.io/happ-ai/integ-api:dev \
  node ./dist/main.js

ВАЖНО

При запуске без Doppler нужно переопределить CMD, убрав doppler run.

Docker Compose

Для integ-core (полный стек)

yaml
services:
  postgres:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: integ-db
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d integ-db"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - integ-network

  happ-integ-api:
    image: ghcr.io/happ-ai/integ-api:${IMAGE_TAG:-dev}
    ports:
      - "3000:3000"
    environment:
      - DOPPLER_TOKEN=${DOPPLER_TOKEN_API}
      - DOPPLER_CONFIG=${DOPPLER_CONFIG:-local}
      # Override для Docker networking
      - POSTGRES_HOST=postgres
      - INNGEST_URL=http://inngest:8288
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - integ-network

networks:
  integ-network:
    driver: bridge

volumes:
  postgres-data:

.env файл

env
DOPPLER_TOKEN_API=dp.st.xxxx
DOPPLER_CONFIG=local
IMAGE_TAG=dev

Запуск

bash
# Pull и запуск
docker compose pull
docker compose up -d

# Логи
docker compose logs -f happ-integ-api

# Остановка
docker compose down

Локальная разработка

Только PostgreSQL

Для локальной разработки без Docker образа API:

bash
# Запуск только БД
npm run docker:up

# Остановка
npm run docker:down

С Doppler локально

bash
# Запуск приложения с Doppler
doppler run --config local -- npm start

# Или production build
doppler run --config local -- npm run start:prod

Сборка образа локально

bash
# Сборка
docker build -t integ-api:local .

# Запуск с Doppler
docker run -p 3000:3000 \
  -e DOPPLER_TOKEN=dp.st.xxxx \
  -e DOPPLER_CONFIG=local \
  integ-api:local

# Запуск без Doppler (с env переменными)
docker run -p 3000:3000 \
  -e POSTGRES_HOST=host.docker.internal \
  -e POSTGRES_PORT=5432 \
  -e POSTGRES_USERNAME=user \
  -e POSTGRES_PASSWORD=password \
  -e POSTGRES_NAME=integ-db \
  integ-api:local \
  node ./dist/main.js

Переменные окружения

Полный список переменных для runtime:

ПеременнаяОписаниеDefault
PORTПорт сервера3000
MODEРежим (local/dev/prod)local
POSTGRES_HOSTХост БД-
POSTGRES_PORTПорт БД5432
POSTGRES_USERNAMEПользователь БД-
POSTGRES_PASSWORDПароль БД-
POSTGRES_NAMEИмя БД-
POSTGRES_CERTIFICATEИспользовать SSL-
POSTGRES_CERTIFICATE_BASE64CA сертификат в base64-
JWT_SECRETСекрет для JWT-
CRYPTO_KEYКлюч шифрования-
CRYPTO_SALTСоль шифрования-
CLOUDFLARE_ACCOUNT_IDCloudflare Account ID-
CLOUDFLARE_WORKERS_API_TOKENCloudflare API Token-
CLOUDFLARE_INTEG_DB_IDD1 Database ID-
CLOUDFLARE_INTEG_KV_IDKV Namespace ID-
INNGEST_URLURL Inngesthttp://localhost:8288

CI/CD

GitHub Actions

Образ билдится и пушится автоматически:

  • dev branchghcr.io/happ-ai/integ-api:dev
  • main branchghcr.io/happ-ai/integ-api:latest
yaml
- name: Build and push Docker image
  uses: docker/build-push-action@v5
  with:
    context: .
    file: ./Dockerfile
    push: true
    tags: ghcr.io/happ-ai/integ-api:dev
    cache-from: type=gha
    cache-to: type=gha,mode=max

TIP

Doppler не используется на этапе build. Секреты инжектятся только при запуске контейнера.

Health Checks

bash
# Проверка health endpoint
curl http://localhost:3000/health

# Docker health check
docker inspect --format='{{.State.Health.Status}}' integ-api

Troubleshooting

Контейнер не стартует

bash
# Проверка логов
docker logs integ-api

# Проверка Doppler
docker exec integ-api doppler secrets --only-names

Ошибка подключения к БД

bash
# Проверка переменных
docker exec integ-api env | grep POSTGRES

# Проверка сети
docker exec integ-api ping postgres

Doppler не работает

bash
# Проверка токена
docker exec integ-api doppler whoami

# Проверка конфига
docker exec integ-api doppler configs

Best Practices

DO:

  • Используйте Doppler для управления секретами
  • Используйте health checks
  • Используйте named volumes для данных
  • Используйте networks для изоляции

DON'T:

  • Не храните секреты в образе
  • Не используйте latest tag в production
  • Не запускайте как root в production

Следующие шаги