Skip to main content

Container images (Compute API)

Registering an image saves its URL under your account, and — for a private registry — stores the credentials we pull it with. You launch by passing the same URL as container_image; the credential is found and used automatically.

A public image needs none of this. Pass its URL straight to POST /gpu-instances and skip this page.

Before you start​

Compute access on the account and a key with Compute access — see the Compute API overview.

https://api.ecohash.com
Authorization: Bearer eco_YOUR_KEY

What a credential is​

Every registry that speaks the Docker Registry v2 protocol authenticates with a username and a secret. A token is not a different kind of credential — it is what goes in the secret field.

RegistryUsernamePassword or access token
Docker Hubyour account namea personal access token
GitHub Container Registry (ghcr.io)your GitHub usernamea classic PAT with read:packages
GitLab registrya deploy-token usernamethat deploy token
Quay.iorobot account name (org+robot)the robot's token
Harbor and most self-hostedrobot account namethe robot's secret
Azure Container Registryservice principal app idits password (or the admin user)
Google Artifact Registry_json_keythe service-account JSON key, as one line

AWS ECR is not supported, and registering a credential for it is refused rather than accepted and left to break. aws ecr get-login-password mints a token that expires after 12 hours, so a stored one stops working within a day — long after you would connect the failure to this step. Two things do work: make the repository public, or grant our account pull access in the repository's policy and register the image with no credential at all.

Register a private image​

curl -s -X POST https://api.ecohash.com/container-images \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{
"name": "trainer",
"registry_url": "ghcr.io/acme/trainer:v3",
"registry_username": "acme-bot",
"registry_secret": "ghp_xxxxxxxxxxxxxxxxxxxx"
}'
{
"id": 42,
"name": "trainer",
"registry_url": "ghcr.io/acme/trainer:v3",
"registry_username": "acme-bot",
"has_credentials": true,
"created_at": "2026-09-24T09:12:03Z"
}

has_credentials is how you confirm the secret landed. The secret is never returned by any endpoint — there is no way to read it back, and a lost credential is re-entered rather than recovered.

Launch from it​

Nothing special: pass the same registry_url as container_image.

curl -s -X POST https://api.ecohash.com/gpu-instances \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{
"name": "train-run",
"region_id": "atl",
"gpu_type": "NVIDIA-RTX-PRO-6000-Blackwell-Server-Edition",
"gpu_count": 1,
"container_image": "ghcr.io/acme/trainer:v3",
"estimated_duration_hours": 0
}'

The match is on the exact registry_url string. ghcr.io/acme/trainer:v3 and ghcr.io/acme/trainer:v4 are two different images: register each tag you launch, or register the tag you actually use.

If the stored credential is wrong, the launch is refused with 400 before anything is created — no instance, no credit hold:

{"error":"the stored credential for ghcr.io/acme/trainer:v3 was rejected by ghcr.io — check the username and token on the image in Registry → Images"}

Endpoints​

MethodPathWhat it does
GET/container-imagesYour registered images
GET/container-images/{id}One image
POST/container-imagesRegister one
PUT/container-images/{id}Change name, URL or credentials
DELETE/container-images/{id}Remove the registration (and its credential)

Fields​

FieldTypeRequiredNotes
namestringyesA label for your own use
registry_urlstringyesThe full pullable reference including tag
registry_usernamestringnoRequired together with registry_secret
registry_secretstringnoPassword or access token. Write-only

registry_username and registry_secret must be sent together. Half a credential authenticates nothing, so sending one without the other is a 400 rather than a registration that silently cannot pull.

Responses​

FieldMeaning
id, name, registry_url, created_at
registry_usernamePresent when a credential is stored. Not a secret — it is the identity the pull uses
has_credentialstrue when a secret is stored

Update or remove a credential​

Change it by sending a new pair:

curl -s -X PUT https://api.ecohash.com/container-images/42 \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"registry_username": "acme-bot", "registry_secret": "ghp_new_token"}'

Remove it — the image stays registered and pulls anonymously afterwards:

curl -s -X PUT https://api.ecohash.com/container-images/42 \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"registry_username": "", "registry_secret": ""}'

Omitting both fields leaves whatever is stored untouched, so you can rename an image without re-entering its token.

How the credential is handled​

  • Stored encrypted, under a key held only by the API. It is never written to a log, never returned by an endpoint, and never sent to your pod.
  • Used at launch to create a pull secret in your account's namespace in the region you launched into. It is scoped to the registry it belongs to, so a credential for ghcr.io is never offered to any other registry.
  • Deleted with the image registration.

Rotating a token​

Registries expire tokens. When yours changes, PUT the new one — running instances are unaffected, because the image was already pulled. The new credential applies to the next launch.

A launch that fails on a rotated-out token gives you the 400 above rather than a failed instance, so the fix is visible at the moment you hit it.

GPU instances · Container images in the console · Compute API overview

Your privacy choices

Essential cookies are always on. You can change these choices at any time.