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.
If your images already live somewhere else — Docker Hub, GitHub Container Registry, or your own registry — you can deploy from there instead by connecting that provider as a project integration. Those images are pulled with the integration's credentials, and the registry stays billed by whoever hosts it.
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.
| What | Rate | Notes |
|---|---|---|
| Registry fee | $1 per month | Charged per registry, prorated from the day you create it. |
| Storage | $0.25/GB per month | Measured across every repository in your organization. |
| Egress | First 10 GB free, then $0.15/GB | Data pulled from your repositories. The allowance covers your whole organization each billing period. |
| Pushes | $0 | Uploading 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 $0.15/GB.
A few ways to stay inside the allowance:
- Set
imagePullPolicy: IfNotPresentrather thanAlwayswhere 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/previewCreating 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
}| Option | Default | What it does |
|---|---|---|
region | — | Where your images are stored. Fixed once the registry exists. |
imageTagMutability | MUTABLE | IMMUTABLE rejects a second push to a tag that already exists. |
scanOnPush | true | Scans each pushed image against known vulnerabilities. |
encryptionType | AES256 | Cosmoner-managed encryption. KMS uses your own key and requires kmsKeyArn. |
lifecycleEnabled | true | Expires old images automatically. |
lifecycleKeepLastN | 10 | Keeps this many recent images (1–1000); older ones expire. |
lifecycleUntaggedAfterDays | 7 | Untagged 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| Region | Location |
|---|---|
us-east-1 | US East — N. Virginia |
us-east-2 | US East — Ohio |
us-west-2 | US West — Oregon |
eu-west-1 | Europe — Ireland |
eu-central-1 | Europe — Frankfurt |
eu-north-1 | Europe — Stockholm |
ap-southeast-1 | Asia Pacific — Singapore |
ap-southeast-2 | Asia Pacific — Sydney |
ap-northeast-1 | Asia 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 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 $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:
50GB is roughly $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 api.cosmoner.com -u <api-key-id> -p <api-key-secret>
docker push api.cosmoner.com/<org-id>/<repo>:<tag>
docker pull api.cosmoner.com/<org-id>/<repo>:<tag>The path is always your organization ID followed by the repository name. Any member of the organization with a valid API key can push and pull; see API Keys for creating one.
AWS Credentials
docker login with an API key is the normal path and needs nothing else. Some tooling insists on talking to ECR natively — aws ecr get-login-password, a Kubernetes image pull secret, a build system that wants a registry ARN — and for those you can issue scoped AWS credentials from IAM in the control panel:
POST /v1/projects/:projectId/iam/container-registry{
"label": "ci-pipeline",
"access": "push"
}access is pull (read-only) or push (push and pull). The secret access key is returned once and is never stored — if you lose it, delete the credentials and create new ones.
Two things to know before you use them:
- They cover the whole project. Repository names are scoped per project, not per registry, so a credential reaches every repository in the project — not one registry and not one repository.
- 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/:iamUserNameRetention
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.
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/:repoIdBecause storage is what you pay for, a tighter retention policy is the most direct way to control the cost of a registry.
Deleting a Registry
DELETE /v1/projects/:projectId/storage/container-registry/:idDeleting 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/:repoIdFull endpoint details are in the storage API reference.