PlanyDocs
Account and platform

Container registry

Push your container images to Plany, and run them on Sandbox and Agones Autopilot.

Plany has its own container registry, at <region>.plany.cr — eu-west-2.plany.cr today. Push images with docker, podman or whatever your CI already uses, and run them on Sandbox and Agones Autopilot without credentials for somebody else's registry.

An image's address is the registry, your project's id and a repository:

text
eu-west-2.plany.cr/{project}/{repository}:{tag}
eu-west-2.plany.cr/{project}/{repository}@sha256:{digest}

Create a repository first

A repository has to exist before you can push to it. Pushing to one that does not exist is refused, so a typo in a tag cannot quietly create something — and a repository is what access is granted on, so it is worth creating on purpose.

Compute → Container registry → New repository → name it → Create repository

A repository id is lower case letters and digits, with ., _ or - between them, and no slashes — it becomes part of every image reference that points at it. Your project's id is the first part of the reference too, so it has to follow the same rule; creating a repository in a project whose id does not is refused with the reason.

Immutable tags

By default a tag can be moved, the way latest usually is. Turn on immutable tags and a push that would move an existing tag is refused, so a tag names one image for good — what a reproducible deploy wants.

Shell
plany registry repositories create api --immutable-tags
plany registry repositories update api --immutable-tags

In Terraform it is immutable_tags = true.

Logging in

The registry accepts two kinds of password, and the username is not checked — any value works.

An API key is the simplest: the one you already have.

Shell
echo "$PLANY_API_KEY" | docker login eu-west-2.plany.cr -u plany --password-stdin

A registry credential is better for a build machine: it reaches the registry and nothing else on Plany, expires on its own, and carries only what you ask for.

# Signed in yourself: prints the docker login command to run
plany registry login
# In CI: the password alone on stdout, so it can be substituted
plany registry get-token --repository api --lifetime 30m \
| docker login eu-west-2.plany.cr -u plany --password-stdin
OptionDoes
--repositoryRestrict it to these repositories. The default is every repository in the project you can reach.
--read-onlyPulling only — right for anything that deploys rather than builds.
--lifetimeHow long it lasts. An hour by default, at most 12 hours.

A credential never carries more than you hold: it is what you asked for, intersected with what your own roles allow, and the CLI prints exactly what it was granted.

Pushing and pulling

Shell
docker build -t eu-west-2.plany.cr//api:v1 .
docker push eu-west-2.plany.cr//api:v1
docker pull eu-west-2.plany.cr//api:v1

Multi-platform images work: an image index holding one image per platform is stored as one, and a pull picks the one that matches.

In GitHub Actions

YAML
- name: Log in to Plany
run: |
plany registry get-token --repository api --lifetime 30m \
| docker login eu-west-2.plany.cr -u plany --password-stdin
env:
PLANY_API_KEY: ${{ secrets.PLANY_API_KEY }}
- name: Build and push
run: |
docker build -t eu-west-2.plany.cr//api:${{ github.sha }} .
docker push eu-west-2.plany.cr//api:${{ github.sha }}

Seeing what is in a repository

Compute → Container registry → open the repository → open an image

For each image you see its digest, every tag pointing at it, its size and the platforms it runs on. The console's image page has ready-to-copy pull and deploy commands pinned to the digest, so what runs is exactly those bytes however the tags move later.

A repository's last_pull_time shows when anything last fetched from it — the way to find a repository nothing uses any more.

Running your images

On Sandbox

Name the repository and a tag or digest; Plany resolves a tag to its digest when it deploys, so a tag moving later does not change what is running.

plany sandbox sandboxes deploy api --image api:v1

The image must be in the sandbox's own project and region. See Deploying a sandbox.

On Agones Autopilot

Use the full reference in your manifest's pod template, as you would any registry:

YAML
containers:
- name: game
image: eu-west-2.plany.cr//lobby:v1

Applying the manifest needs permission to pull from that repository — you cannot run an image you could not pull yourself. See Agones Autopilot.

Who pulls

Neither needs a credential from you. Each sandbox and game server pulls as its own identity, and Plany grants that identity roles/registry.puller on the one repository its image comes from. If you give a sandbox a service account of your own, grant it yourself:

Terraform
resource "plany_registry_repository_iam_member" "backend_pulls" {
repository = plany_registry_repository.api.name
role = "roles/registry.puller"
member = plany_service_account.backend.name
}

roles/registry.puller can pull and nothing else: a workload that is compromised can fetch the image it was already running, and cannot replace the image the next one starts from.

Who can do what

RoleRegistry
roles/project.owner, roles/account.admin, roles/account.ownerEverything, including deleting repositories.
roles/project.editorCreate and update repositories, push, pull and delete images. Cannot delete a repository.
roles/project.viewer, roles/account.viewerSee repositories and images, and pull.
roles/registry.pullerPull from the one repository it is granted on.

A change of role reaches the registry within a few minutes, because a login stays good for a few minutes after it is checked.

Credit and limits

Pushing needs credit on the account. When your balance runs out, pushes are refused within a few minutes and pulls keep working, so what you already run keeps starting.

HobbyPro
Repositories per project, per region550

Ask for more on registry.plany.cloud/repositories.