CONTAINER APPS · PANEL GUIDE
Migrating a multi-service Docker project, end to end from the panel
This is the point-and-click companion to the cdnctl command-line guide. It takes the same multi-service docker-compose-style project (web/API services, background workers, a database, a cache and a message bus) and runs it on the CDN.com.tr managed-container platform — entirely from the management panel. Every step below has a command-line equivalent; use whichever you prefer.
Already have a docker-compose.yml? The container tab can import it in one step — open Import from Docker Compose, review the preview plan, and confirm. See the Docker Compose import guide or the cdnctl compose reference. The manual steps below remain for anything compose import does not cover.
1 · Concepts
- Account = project. One account can hold many container apps; your package determines how many apps you may run.
- App = one container image (a service). Each app has a port, a health check, resources, env vars and secrets, and can scale to N replicas.
- Managed addons are stateful backends —
postgres(PostgreSQL/TimescaleDB),mysql,redisandnats(JetStream) — that you attach to an app. The connection (including the generated password) is injected straight into that app; the password is never displayed back. - Service discovery. Apps in your account share a private network and reach each other by app name, exactly like a docker-compose service —
http://<app-name>:<port>. Name an apphot-data-storeon port8082andhttp://hot-data-store:8082resolves automatically. - Public exposure. Any app can be published on a CDN.com.tr subdomain or your own domain. Each exposed service gets its own hostname; workers and databases stay private.
2 · Open the Container Apps tab
Sign in, open CDN Accounts, click the settings icon on the account you want to manage, then choose the Platforms tab. Across the top you'll see the platform types — select Container Apps (and press Activate the first time).
The Container Apps screen opens on an overview (app count, add-ons, edge egress) with Create App and Usage Details, followed by the Your apps list. Each app is a row showing its status, with a Create Test Copy (preprod) action and a Manage → link. Click Manage to open that app's detail page, where you wire up everything for the service.
3 · Create & wire a service
Click Create App and fill the form — one app per service:
- App name — also the in-network hostname other apps use (keep it equal to your compose service name).
- Image + Tag — build each service for
linux/amd64and push it to a registry the platform can pull. - Port, Replicas, Plan and Healthcheck path — leave the port blank for a background worker that doesn't listen.
- Registry credential — pick a saved credential for private images, or add one inline in the Private registry credential row (the token is stored encrypted and never shown again).
- Env values (one
KEY=valueper line) and Secrets — secrets are stored as encrypted Kubernetes secrets and are not shown after saving.
Tick Managed Redis, Managed DB or Object Storage on the form to attach them while creating the app, or add them afterwards from the app's detail page (step 4).
4 · Add managed databases, cache & message bus
Open the app (Manage →), then its Add-ons tab, and use the actions to enable Redis, a database (PostgreSQL/MySQL) or NATS. The addon is provisioned for that app and its connection is injected automatically:
# 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
Sharing a backend across apps. Passwordless backends — NATS, and Redis as configured here — can be reached from your other apps too: set NATS_URL/REDIS_URL as env on each consumer using the addon's host. A password-protected SQL database is only ever injected into the app that owns it (the password is never shown), so don't try to reuse it from a second app — let one app own the database and have the others call it, or run your own database image with a password you set.
5 · Deploy, check status & logs
Saving an app queues a deploy. The status badge moves to running — both in the Your apps list and on the app's detail page — when the container is healthy. On the detail page use the action buttons to view status / runtime, logs and activity, and the Operations menu (top bar) to watch each deploy through to completion. Deploy the service that initialises your database schema first if your apps run migrations on boot.
The overview's running / replicas count and the Your apps header reflect live state — an app flips to running there as soon as its pod is ready.
6 · Expose services publicly
On the app's detail page, click Expose on cdn.com.tr to mint the app's own immutable <uid>.cdn.com.tr subdomain (HTTPS is handled for you). The app's route then shows the live address. Expose as many services as you need — one account, many public hostnames. To use your own domain instead, add it via DNS Management and point it at the app.
Expose only services that should be public. Background workers and databases stay private. Add authentication to any HTTP service you publish.
7 · Observability (single pane of glass)
Run your monitoring stack as ordinary apps: a metrics collector that scrapes your services (built with your scrape config baked in, kept internal) and a dashboard you expose publicly. Create both like any other app (step 3), wire the dashboard to the collector by its app name (http://<collector-name>:<port>), then Expose only the dashboard. It queries the collector over the private network and is reachable at its cdn.com.tr subdomain.
8 · Edit, scale, restart & delete
Open an app (Manage →); its detail page carries these actions:
- Edit () — change image/tag, port, replicas, health check, env and secrets, then redeploy.
- Restart and scale — set replicas to
0to stop a service and back to1+to start it. - Delete () — removes the app and its public subdomain. Disabling a data addon keeps its volume by default; deleting the data requires an explicit confirmation.
Prefer the terminal? Every action here maps one-to-one to a cdnctl command.