Настройка Docker-контейнеризации бэкенда мобильного приложения
Бэкенд мобильного приложения — это не просто REST API. Это push-уведомления через FCM/APNs, WebSocket для чата, фоновые задачи по обработке медиа, Redis для кэширования сессий. На одном сервере всё это запускается как попало, версии библиотек конфликтуют, деплой превращается в «надеюсь, не сломается». Docker решает предсказуемость среды: то, что работает у разработчика, работает в CI и продакшне.
Структура для типичного мобильного бэкенда
Стек, встречающийся чаще всего: Node.js / Go / Python + PostgreSQL + Redis + Nginx. docker-compose.yml для локальной разработки:
version: '3.9'
services:
api:
build:
context: .
dockerfile: Dockerfile
target: development
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://app:password@postgres:5432/mobile_app
- REDIS_URL=redis://redis:6379
- FCM_SERVER_KEY=${FCM_SERVER_KEY}
volumes:
- .:/app
- /app/node_modules
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: mobile_app
POSTGRES_USER: app
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./ssl:/etc/nginx/ssl
depends_on:
- api
volumes:
postgres_data:
redis_data:
Multi-stage Dockerfile
Один Dockerfile для development и production через multi-stage build:
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Stage 2: Development
FROM node:20-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "run", "dev"]
# Stage 3: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 4: Production
FROM node:20-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
# Запускаем не как root
RUN addgroup -g 1001 -S nodejs && adduser -S nodeuser -u 1001
USER nodeuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
Production-образ не содержит dev-зависимостей, исходников и запускается от непривилегированного пользователя. Размер образа уменьшается в 2–3 раза по сравнению с наивным подходом.
Push-уведомления в контейнере
Для APNs (Apple Push Notification service) нужен .p8 ключ. В контейнере он передаётся через переменную окружения (base64-encoded) или через Docker Secret (в Swarm/Kubernetes). Никаких ключей в Dockerfile и образах.
# Encoding
APNS_KEY_BASE64=$(base64 -w 0 AuthKey_XXXXXX.p8)
# В docker-compose через secrets или env:
APNS_KEY_BASE64=${APNS_KEY_BASE64}
APNS_KEY_ID=XXXXXXXXXX
APNS_TEAM_ID=YYYYYYYYYY
Healthcheck и graceful shutdown
Мобильные клиенты плохо переносят внезапные обрывы соединения. Контейнер должен корректно завершать активные WebSocket-соединения и HTTP-запросы перед остановкой. Node.js:
process.on('SIGTERM', () => {
server.close(() => {
mongoose.connection.close();
process.exit(0);
});
});
В Docker Compose/Kubernetes stop_grace_period: 30s даёт контейнеру время на shutdown.
CI/CD интеграция
# .github/workflows/deploy.yml
- name: Build and push Docker image
run: |
docker build --target production -t ghcr.io/myorg/mobile-api:${{ github.sha }} .
docker push ghcr.io/myorg/mobile-api:${{ github.sha }}
- name: Deploy
run: |
ssh deploy@server "
docker pull ghcr.io/myorg/mobile-api:${{ github.sha }}
docker-compose up -d --no-deps api
"
Процесс
Аудит текущего деплоя → написание Dockerfile (multi-stage) → написание docker-compose.yml для dev и prod → настройка healthcheck → интеграция с CI → настройка registry → тест деплоя → документация.
Срок: 2–3 дня для стандартного Node.js/Go бэкенда. Стоимость рассчитывается индивидуально после изучения стека и инфраструктуры.







