Cosmoner Docs
Guides

Container Registry

Push and pull private images from a managed Cosmoner registry, choose a region and retention policy, and understand storage and egress pricing.

Overview

A container registry stores the images your apps are deployed from. A Cosmoner registry is a managed registry backed by Amazon ECR: you pick a region and a retention policy, Cosmoner handles the infrastructure, and you authenticate with a Cosmoner API key instead of cloud credentials.

You get a normal registry: docker push and docker pull from your laptop or CI with a Cosmoner API key, and AWS credentials on request for tooling that insists on speaking to ECR directly.

Deploying an app from your registry

When you create an app from a container image, the repositories in your project's registries are listed alongside Docker Hub and the GitHub Container Registry. Pick one and choose a tag — there are no credentials to enter, because an app deployed from your own registry is authenticated for you.

By default an app deploys the tag it was given, and follows it: pushing a new image over that same tag automatically redeploys every app deployed from that repository and tag, and the rollout appears in each app's activity feed. Pushes to other tags leave the app alone, so a push to v3 never moves an app deployed from v2. An app you have stopped is never restarted by a push.

Each app's Deploy on push setting changes that. Choose it when you create the app, or later under the app's General tab:

  • Same tag — the default described above.
  • Newest image — every push to the repository deploys, whatever its tag, and the app switches to the tag that was pushed. Pushing one image under two tags at once, such as latest and a commit SHA, deploys it once.
  • Off — pushes never move the app. Deploy it yourself from CI with the Deploy Image endpoint, naming the tag or digest you just pushed.

An app deployed this way is otherwise an ordinary app: it runs on the platform's infrastructure alongside apps built from git, and it can scale out to multiple instances (autoscaling is not available). The one difference is build logs — there are none, because the image is already built, so the logs you see are your container's own output.

Pricing

A Cosmoner registry is billed on a flat monthly fee plus what you store and what you pull. There is no charge for the number of repositories you create inside a registry.

WhatRateNotes
Registry feeUSD 1 per monthCharged per registry, prorated from the day you create it.
StorageUSD 0.25/GB per monthMeasured across every repository in your organization.
EgressFirst 10 GB free, then USD 0.15/GBData pulled from your repositories. The allowance covers your whole organization each billing period.
PushesUSD 0Uploading images is never charged.

How storage is measured

Cosmoner measures the size of your images once a day, at 02:00 UTC, and totals them across all repositories in your organization. Your invoice reflects the most recent daily measurement in the billing period, so the amount you pay tracks what you were actually storing near the end of the cycle rather than a peak earlier in the month.

Two practical consequences:

  • Deleting large images — or letting a retention policy expire them — lowers your bill from the next measurement onward.
  • Images pushed and deleted between two daily measurements are never measured, and so are never billed.

How egress is measured

Egress is the compressed size of the image layers your clients download, counted as each pull happens rather than once a day.

Only the layers actually transferred are counted. Docker and Kubernetes skip layers they already have on the machine, so pulling the same image again on a host that already has most of it costs a fraction of the image's full size. Pushes, layers a client already holds, and requests that only check whether an image exists are not counted.

The first 10 GB in each billing period are included across your whole organization, however many registries you have. Beyond that, egress is billed at USD 0.15/GB.

A few ways to stay inside the allowance:

  • Set imagePullPolicy: IfNotPresent rather than Always where a rebuild isn't expected on every start.
  • Keep base layers stable between builds, so only the layers that changed are pulled.
  • Build smaller images — a multi-stage build that ships only the runtime artefacts is cheaper to pull as well as faster.

All three charges appear as separate line items on the project's subscription. See Billing & Payments for how invoicing and proration work in general.

Estimating a cost

Before creating a registry you can preview the registry fee, including proration, tax, and any credit applied. Storage and egress are metered after the fact and are not part of the preview:

GET /v1/projects/:projectId/storage/container-registry/preview

Creating a Registry

POST /v1/projects/:projectId/storage/container-registry
{
  "name": "my-registry",
  "region": "eu-north-1",
  "imageTagMutability": "MUTABLE",
  "scanOnPush": true,
  "encryptionType": "AES256",
  "lifecycleEnabled": true,
  "lifecycleKeepLastN": 10,
  "lifecycleUntaggedAfterDays": 7
}
OptionDefaultWhat it does
region—Where your images are stored. Fixed once the registry exists.
imageTagMutabilityMUTABLEIMMUTABLE rejects a second push to a tag that already exists.
scanOnPushtrueScans each pushed image against known vulnerabilities.
encryptionTypeAES256Cosmoner-managed encryption. KMS uses your own key and requires kmsKeyArn.
lifecycleEnabledtrueExpires old images automatically.
lifecycleKeepLastN10Keeps this many recent images (1–1000); older ones expire.
lifecycleUntaggedAfterDays7Untagged images expire after this many days (1–365).

Tag mutability and scanning can be changed later and are re-applied to every existing repository. Encryption applies only to repositories created afterwards, because it is fixed when a repository is created — and the region cannot be changed at all.

The registry fee is charged to the project's payment method as soon as the registry is created, prorated for the rest of the billing period. If the project has no payment method, the request returns 402 — see Billing → Deploy Payment Errors.

Creating a registry does not create anything to push to yet. It reserves the name, stores the settings above as the defaults for the repositories you add under it, and starts the fee. Add at least one repository before your first push.

Regions

GET /v1/projects/:projectId/storage/container-registry/regions
RegionLocation
us-east-1US East — N. Virginia
us-east-2US East — Ohio
us-west-2US West — Oregon
eu-west-1Europe — Ireland
eu-central-1Europe — Frankfurt
eu-north-1Europe — Stockholm
ap-southeast-1Asia Pacific — Singapore
ap-southeast-2Asia Pacific — Sydney
ap-northeast-1Asia Pacific — Tokyo

Choose a region close to where your apps run, so deployments pull images over the shortest path. The regions endpoint is the source of truth — not every region above is open in every environment.

Repositories

A registry holds repositories, one per image:

POST /v1/projects/:projectId/storage/container-registry/:id/repositories
{
  "name": "my-app"
}

Names must be lowercase and may contain dots, hyphens, and underscores. Creating a repository costs nothing on its own — you are billed only for what you push into it.

A repository name is unique across the whole project, not just within its registry. The path you push to is your project and the repository name — it does not say which registry — so the same name in two registries would leave a docker push with nowhere definite to go. Creating a repository whose name is already used in another registry of the project is refused, and the response names that registry.

A repository is where images actually live: the registry above it is a namespace and a set of defaults, and the repository is what a docker push addresses.

Public Repositories

A repository is private by default — pulling it needs a Cosmoner API key belonging to a member of your project. Making it public lets anyone pull it with no credentials at all, which is what you want for a base image, a CLI, or anything else you publish:

PATCH /v1/projects/:projectId/storage/container-registry/:id/repositories/:repoId
{
  "visibility": "PUBLIC",
  "publicEgressCapGb": 50
}

Pushing is never anonymous. Public affects pulls only, and a push still needs an API key.

The egress cap

Anonymous pulls are billed to you, at the same USD 0.15/GB as your own, once your organization's 10 GB monthly allowance is spent. A repository that gets popular — or scraped — can move a lot of data without anyone on your team doing anything, so a public repository must carry a monthly egress cap.

When public egress reaches the cap, the repository is made private again. Pulls from your own project keep working with an API key; anonymous pulls stop. That is deliberate: the cap is a spending limit, and the safe thing to do at the limit is stop serving strangers rather than keep billing you.

  • The cap counts only anonymous egress. Pulls made with an API key are billed as usual but do not count against it.
  • The counter resets at the start of each billing period, on the 25th.
  • Making the repository public again — or raising the cap after it was reached — starts a fresh allowance.
  • Set the cap to what you are willing to spend in a bad month, not to what you expect: 50 GB is roughly USD 6 of egress once the free allowance is gone.

Pushing & Pulling

Log in with a Cosmoner API key. There are no cloud credentials to create or rotate:

docker login registry.cosmoner.com -u _token -p <your-api-key>
docker push registry.cosmoner.com/<org-id>/<repo>:<tag>
docker pull registry.cosmoner.com/<org-id>/<repo>:<tag>

The path is always your organization ID, lowercased, followed by the repository name — the control panel shows the exact line to copy on each repository's page. The username in docker login is ignored — _token is a placeholder saying "this is not an account name", and any value works. Your Cosmoner API key goes in the password field, and there is no separate key id and secret.

The key has to carry the registry scope, and it has to belong to a member of the organization that owns the repository: registry:read to pull, registry:write to push. A key without it is refused at docker login rather than at push time. See API Keys for creating one and granting scopes.

The registry answered on api.cosmoner.com before it moved to its own hostname, and still does, so nothing already pushing needs changing today. Move to registry.cosmoner.com when convenient: it is the hostname that accepts large image layers, and the API hostname will stop serving the registry eventually.

Browsing Images

Open a repository from its registry in the control panel to see what is actually stored in it: every image with its tags, size, digest, when it was pushed, and when it was last pulled. Untagged images — the ones left behind when a tag is moved to a newer push — are listed too, because they still take up storage you are billed for.

The same list is available over the API:

GET /v1/projects/:projectId/storage/container-registry/:id/repositories/:repoId/images

An individual image can be deleted by digest, which also removes every tag pointing at it:

DELETE /v1/projects/:projectId/storage/container-registry/:id/repositories/:repoId/images/:digest

Deleting an image is immediate and permanent — anything pulling that tag, or pinning that digest, starts failing. For routine cleanup, prefer a retention policy over deleting by hand where retention runs automatically — see Retention.

AWS Credentials

docker push and docker pull from your laptop or CI only need an API key. You only need this section if something insists on talking to ECR natively — aws ecr get-login-password, a Kubernetes image pull secret, or a build system that wants a registry ARN.

Creating them, step by step

1. Open IAM in the control panel. It lives under your project, and it is the only place registry credentials are created. Each repository's page also links straight here, filtered to that repository.

2. Choose a label and a scope.

The create registry credentials dialog, with a label, a scope set to one repository, and the access choice

The label is how you will recognise these credentials later — name them after the thing that uses them (ci-pipeline, staging-cluster), not after yourself.

The scope decides which repositories the credentials reach. Pick the single repository whenever you can: a build that pushes one image has no reason to reach the others, and if the key leaks, the blast radius is one repository instead of every image your project owns. Every repository in this project exists for the cases where one credential genuinely serves many images.

3. Choose the access level.

  • Push & pull — the right default for a CI pipeline that builds and uploads the image. It can do everything pull-only can.
  • Pull only — use this when something else does the pushing: a Kubernetes cluster, a deploy runner, a partner who consumes your image. If the credential never needs to upload, do not let it.

The rule of thumb: give push access to the one place images are built, and pull-only access to everything that merely runs them. A leaked pull-only key exposes your images; a leaked push key lets someone replace them.

4. Save the secret. This is your only chance.

The save these credentials dialog, showing the access key ID, the secret access key, and the docker login command

AWS returns the secret access key once and Cosmoner never stores it. Copy it into your CI secret store or password manager before closing the dialog — if you lose it, delete the credentials and create a new set.

The dialog also shows the docker login line for these credentials, with the region and the registry endpoint already filled in. Copy it as it stands: these credentials authenticate against that endpoint, not against registry.cosmoner.com, and a docker login with no registry argument logs in to Docker Hub instead and only fails later, at push time.

The same API is available directly:

POST /v1/projects/:projectId/iam/container-registry
{
  "label": "ci-pipeline",
  "access": "push",
  "repositoryId": "cmsh95uld0000ce9kkchanq4y"
}

access is pull (read-only) or push (push and pull). repositoryId scopes the credentials to one repository; omit it and they reach every repository in the project.

What to know before using them

Each repository's page shows how many credentials can reach it and links straight to IAM filtered to that repository, so you can answer "what outside Cosmoner has access to this image?" without walking the whole list.

  • Scoping stops at the repository. A repository is named <org>/<repo> inside ECR, with no registry in the path, so credentials can cover one repository or the whole project — there is no way to scope them to a single registry.
  • Pulls made with them are not metered as egress. The traffic goes straight from AWS to your client instead of through Cosmoner, so those pulls do not count toward your egress bill. Storage is billed as usual.

Delete credentials you no longer need — anything using the key stops working immediately:

DELETE /v1/projects/:projectId/iam/container-registry/:iamUserName

Retention

Whether retention runs on its own depends on the provider your registry was created on.

On an Amazon Web Services registry, retention is enforced by the registry itself rather than at push time, so images are cleaned up on a schedule — expect expiry to happen within a day of an image becoming eligible, not the moment it does.

On a Cosmoner registry — one running on Cosmoner's own infrastructure — automatic cleanup is not available yet. Retention settings are saved with each repository and will take effect once it is; until then, delete images you no longer need from the panel or the API to reclaim storage.

The registry's retention settings apply to every new repository, and each repository can override them:

PATCH /v1/projects/:projectId/storage/container-registry/:id/repositories/:repoId

Because storage is what you pay for, keeping old images from accumulating — by policy where retention runs automatically, by deleting them where it does not yet — is the most direct way to control the cost of a registry.

Deleting a Registry

DELETE /v1/projects/:projectId/storage/container-registry/:id

Deleting a Cosmoner registry removes its repositories and all images in them permanently, and stops all three of its charges — the monthly fee, storage, and egress. Metered usage already recorded in the current period is still invoiced.

Deleting a single repository works the same way, without touching the rest of the registry:

DELETE /v1/projects/:projectId/storage/container-registry/:id/repositories/:repoId

Full endpoint details are in the storage API reference.

On this page