Loading...

CONTAINER APPS · РУКОВОДСТВО CDNCTL

Миграция многосервисного Docker-проекта, от начала до конца, с cdnctl

Это руководство шаг за шагом показывает, как взять многосервисный проект в стиле docker-compose (веб/API-сервисы, фоновые воркеры, база данных, кеш и шина сообщений) и запустить его на управляемой контейнерной платформе CDN.com.tr — целиком из командной строки cdnctl. Замените значения-заполнители (<account-uuid>, имена образов, порты) на свои собственные.

Быстрый путь: импортируйте docker-compose.yml напрямую

Если у вас уже есть docker-compose.yml, вы можете пропустить ручные шаги создания и связывания ниже: платформа разбирает ваш compose-файл и предлагает готовый к подтверждению план. См. руководство по импорту Docker Compose или справочник cdnctl compose. Пошаговые инструкции здесь остаются способом тонкой настройки или переноса всего, что не покрывает импорт compose.

1 · Концепции

  • Аккаунт = проект. Один аккаунт может содержать множество container app; сколько приложений вы можете запускать, определяет ваш пакет.
  • App = один образ контейнера (сервис). У каждого app есть порт, health check, ресурсы, переменные env и секреты; он может масштабироваться до N реплик.
  • Управляемые аддоны — это stateful-бэкенды — postgres (PostgreSQL/TimescaleDB), mysql, redis и nats (JetStream) — которые вы подключаете к app. Каждый аддон предоставляется для того app, на котором вы его включаете, и предоставляет стабильное имя хоста внутри кластера. Его данные подключения — хост, порт, пользователь, база данных и сгенерированный пароль — внедряются напрямую в это app как env-переменные и секреты (напр. DATABASE_URL, REDIS_URL, NATS_URL), готовые к использованию. Пароль генерируется за вас и никогда не отображается снова, так что вы не собираете строку подключения вручную для владеющего app.
  • Приватная сеть и service discovery. Приложения в вашем аккаунте разделяют приватную сеть. Каждое app доступно из ваших других app по его имени app — точно как имя сервиса docker-compose — по адресу http://<имя-app>:<порт> (мы публикуем внутренний псевдоним DNS = имя вашего app). Так что если ваш compose-файл обращается к http://hot-data-store:8082, назовите это app hot-data-store с портом 8082, и оно просто заработает. App могут выходить в интернет, но не к приватным сервисам других клиентов.
  • Хосты аддонов возвращаются вам. Когда вы включаете аддон, его стабильный хост внутри кластера сообщается командой cdnctl container addons list (поле host). Это и есть <db-host>/<redis-host>/<nats-host>, используемые в строках подключения ниже — вам не нужно их угадывать.
  • Публичный доступ. Любое app можно опубликовать на субдомене CDN.com.tr или на вашем собственном домене. Каждый опубликованный сервис получает собственное имя хоста.

2 · Настройте cdnctl

Аутентифицируйтесь один раз своим токеном API панели (или выполните login со своими учётными данными):

cdnctl configure --endpoint https://cdn.com.tr --token <your-api-token>
# verify
cdnctl accounts list
cdnctl container apps list --account <account-uuid>

3 · Соберите и опубликуйте образы, зарегистрируйте учётные данные для загрузки

Соберите каждый сервис под linux/amd64 и запушьте в registry, который платформа сможет забрать. Если репозитории приватные, зарегистрируйте учётные данные для загрузки в аккаунте:

# build & push (one image per service)
docker buildx build --platform linux/amd64 -t your-registry/app-web:1.0.0 --push .
docker buildx build --platform linux/amd64 -t your-registry/app-worker:1.0.0 --push .

# register pull credentials (token is stored encrypted, never returned)
cdnctl container registry-credentials create --account <account-uuid> \
  --name registry --registry-url https://index.docker.io/v1/ \
  --username <user> --password <token>
cdnctl container registry-credentials list --account <account-uuid>

Никогда не встраивайте секреты в образы. Используйте .dockerignore, чтобы исключить .env, артефакты сборки и данные VCS.

4 · Предоставьте управляемые аддоны (БД, кеш, шина сообщений)

Каждый аддон подключается к app, поэтому сначала вы создаёте это app (шаг 5), а затем включаете на нём аддоны. Аддон предоставляется для этого app, и его подключение внедряется в него автоматически — вы не собираете URL и не копируете пароль:

# enable the backends your owner app needs (app created in step 5):
cdnctl container addons enable-postgres --account <account-uuid> --app <app-uuid> --storage-mb 10240
cdnctl container addons enable-redis    --account <account-uuid> --app <app-uuid>
cdnctl container addons enable-nats     --account <account-uuid> --app <app-uuid> --storage-mb 5120
cdnctl container addons list            --account <account-uuid> --app <app-uuid>

С этого момента окружение этого app уже содержит готовые к использованию значения — вы ссылаетесь на них, а не собираете их:

# auto-injected into the app the addon is enabled on:
DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER   # env
DATABASE_PASSWORD, DATABASE_URL                              # secrets (full postgres:// URL)
REDIS_URL        # redis://<redis-host>:6379/0
NATS_URL         # nats://<nats-host>:4222

cdnctl container addons list сообщает стабильный host, порт, пользователя и имя базы данных каждого аддона (напр. host: ca-…-postgres) для справки — сгенерированный пароль никогда не возвращается. Так что вам не нужно вручную писать DATABASE_URL для владеющего app — он уже является секретом на нём.

Общий доступ к бэкенду между приложениями. Бэкенды без пароля — NATS и Redis в этой конфигурации — доступны и из ваших других app: возьмите host из addons list и задайте env NATS_URL/REDIS_URL на каждом потребителе (шаг 5). SQL-база данных, защищённая паролем, отличается: поскольку пароль внедряется только в то app, которое владеет аддоном (и никогда не показывается), не пытайтесь повторно использовать её из второго app. Вместо этого либо пусть одно app владеет базой данных, а остальные обращаются к нему через ваш API, либо запустите собственный образ базы данных с паролем, который вы сами задаёте. Хосты между app — это просто ваши имена app (псевдоним в стиле docker-compose из шага 1), так что URL вроде http://hot-data-store:8082 разрешаются без загрузки docker-compose.yml.

5 · Создайте и свяжите каждый сервис

Создайте одно app на сервис. Порядок такой: создать app → включить его аддоны (шаг 4) → задеплоить (шаг 6). Включение аддона передеплоивает app с внедрённым подключением, поэтому сначала создайте здесь app-владельца аддона, а затем выполните команды шага 4 для него. Выберите правильный health check для каждого типа сервиса:

  • --healthcheck-type http (по умолчанию) для HTTP-сервисов — задайте --healthcheck /ваш/путь.
  • --healthcheck-type tcp для TCP-сервисов без HTTP-эндпоинта.
  • --healthcheck-type none для фоновых воркеров, которые ничего не слушают.
# app-web OWNS the postgres/redis/nats addons you enable in step 4, so DATABASE_URL,
# REDIS_URL and NATS_URL are injected for you — you only add your own secrets here:
cdnctl container apps create --account <account-uuid> \
  --name app-web --image your-registry/app-web --tag 1.0.0 \
  --port 8080 --healthcheck-type http --healthcheck /health \
  --metrics-port 9090 --metrics-path /metrics \
  --registry-credential <cred-uuid> \
  --secrets-json '{"API_KEY":"<secret>"}'

# a background worker that shares the message bus. It does NOT own the addons, so point it
# at the passwordless NATS host from `addons list` (there is no DB password to copy):
cdnctl container apps create --account <account-uuid> \
  --name app-worker --image your-registry/app-worker --tag 1.0.0 \
  --healthcheck-type none --registry-credential <cred-uuid> \
  --env-json '{"NATS_URL":"nats://<nats-host>:4222"}' \
  --secrets-json '{"API_KEY":"<secret>"}'

Секреты, переданные через --secrets-json, хранятся как зашифрованные секреты Kubernetes и никогда не попадают в открытую конфигурацию или логи. Обновляйте env/секреты позже с помощью cdnctl container apps update --account <account-uuid> --app <app-uuid> --env-json ... --secrets-json ...

6 · Задеплойте, проверьте статус и логи

Задеплойте каждое app (сначала задеплойте сервис, инициализирующий схему базы данных, если ваши app выполняют миграции при запуске):

cdnctl container apps deploy --account <account-uuid> --app <app-uuid>
cdnctl container apps status --account <account-uuid> --app <app-uuid>
cdnctl container apps wait   --account <account-uuid> --app <app-uuid> --status running --timeout 300
cdnctl container apps logs   --account <account-uuid> --app <app-uuid> --tail 100
cdnctl container apps diagnose --account <account-uuid> --app <app-uuid>

7 · Опубликуйте сервисы вовне

Дайте сервису собственный субдомен CDN.com.tr (HTTPS настраивается за вас):

cdnctl container apps expose --account <account-uuid> --app <app-uuid>
# returns the app's public_subdomain, e.g. https://<uid>.cdn.com.tr

Каждое app получает один неизменяемый субдомен; публикуйте столько сервисов, сколько нужно — один аккаунт, много публичных имён хостов. Чтобы использовать собственный домен, добавьте его как delivery point и направьте на app (ваш домен → CDN → сервис).

Публикуйте только те сервисы, которые должны быть публичными. Фоновые воркеры и базы данных остаются приватными. Добавляйте аутентификацию к любому публикуемому HTTP-сервису.

8 · Наблюдаемость (единая панель)

Запускайте свой стек мониторинга как обычные app: сборщик метрик, который опрашивает ваши сервисы, плюс дашборд, который вы публикуете вовне. Держите сборщик внутренним и публикуйте только дашборд:

# collector (internal): build an image with your scrape config baked in
cdnctl container apps create --account <account-uuid> --name metrics \
  --image your-registry/metrics --tag 1.0.0 --port 9090 --healthcheck-type http --healthcheck /-/healthy \
  --registry-credential <cred-uuid>
cdnctl container apps deploy --account <account-uuid> --app <metrics-app-uuid>

# dashboard: wire it to the collector via env, then expose it
cdnctl container apps create --account <account-uuid> --name dashboard \
  --image your-registry/dashboard --tag 1.0.0 --port 3000 --healthcheck-type http --healthcheck /api/health \
  --registry-credential <cred-uuid> \
  --env-json '{"METRICS_URL":"http://<metrics-host>:80"}' --secrets-json '{"ADMIN_PASSWORD":"<secret>"}'
cdnctl container apps deploy --account <account-uuid> --app <dashboard-app-uuid>
cdnctl container apps expose --account <account-uuid> --app <dashboard-app-uuid>

9 · Жизненный цикл и откат

cdnctl container apps scale   --account <account-uuid> --app <app-uuid> --replicas 0   # stop
cdnctl container apps restart --account <account-uuid> --app <app-uuid>
cdnctl container apps delete  --account <account-uuid> --app <app-uuid>                 # removes app + its subdomain
cdnctl container addons disable-postgres --account <account-uuid> --app <app-uuid>       # keeps data
cdnctl container addons disable-postgres --account <account-uuid> --app <app-uuid> --delete-data --confirmation <app-name>

Отключение аддона данных по умолчанию сохраняет его том; удаление данных требует явного подтверждения. Удаление app также удаляет его публичный субдомен.