Skip to main content

Registry access

The registry is yours. AstroPulse never stores registry logins and never pushes images, by design: we want every cluster to pull keyless, with the identity it already has in its cloud. A pull Secret is the fully supported fallback for any registry or cluster with no keyless path.

Where your cluster runs decides how it pulls. Find yours below. How keyless access works, and access for your app to buckets and queues, is on Keyless cloud access.

The node pulls the image, not your application​

Kubernetes pulls an image with the node's identity, or with a pull Secret named on the pod or its service account. Your application's own cloud identity, bound to its ServiceAccount, lets the running app call your cloud, but it never pulls the app's image. So for a private registry, give the nodes read access, or use a pull Secret.

Vulnerability Scanning is the exception: it reads images through the registry's API as its own ServiceAccount, so it needs its own grant (EKS, GKE, AKS).

When you need it​

  • Your images live in your cloud's registry and you want to know whether the cluster can already pull them.
  • Your images live in a registry the cluster can't reach on its own: Docker Hub, GitHub (ghcr.io), Quay, Harbor, or a registry in another account or cloud.
  • An application is stuck pulling its image and you want to know which way of pulling applies.

Local kind cluster​

Three ways, simplest first.

Load the image, no registry​

Load the image you built straight into the kind nodes, then deploy it with an Image source and a pinned tag:

Terminal
kind load docker-image acme/latency-local:v1.0.0 --name <kind-cluster-name>

Use a fixed tag, never latest. With a fixed tag the node uses the image it already has. With latest, Kubernetes always tries to pull it from a registry. The pod's events show it:

Output
Container image "acme/latency-local:v1.0.0" already present on machine and can be accessed by the pod
tip

If kind load fails with content digest ... not found, the image is a multi-platform image pulled from a registry. Build it locally, or rebuild it FROM that image, and load the result.

A registry login on the nodes​

To pull a private registry from every namespace, give the kind nodes a registry login once, when you create the cluster. Mount a Docker config.json into the kubelet:

kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- containerPath: /var/lib/kubelet/config.json
hostPath: /path/to/config.json

The file needs the login itself, base64 in auths. A config.json that uses credsStore or credHelpers doesn't work inside the node. The kind guide shows how to make a plain one: Private registries.

With the login on the node, a new namespace with no Secret pulls the image on the first try:

Output
Successfully pulled image "localhost:31500/acme/latency:v1.0.0" in 796ms (796ms including waiting). Image size: 4772337 bytes.

A pull Secret​

Works on an existing kind cluster too. See Any registry, any cluster: a pull Secret.

A cluster AstroPulse creates​

It pulls keyless from its own cloud's registry, with nothing to connect:

Any other registry, such as Docker Hub or GitHub: a pull Secret, with the namespace named first.

On a cluster with private nodes, every new node pulls its images through the NAT gateway, which the cloud bills per GB. Docker Hub, GitHub (ghcr.io) and any registry outside your account go that way. On an EKS cluster AstroPulse creates, ECR in the cluster's region skips the NAT gateway through the S3 gateway endpoint. The numbers are in Cut model download cost.

Your own cluster, registered with the agent​

  • On a cloud: pull keyless with the identity its nodes already have. Give it read access to your registry: the node role on ECR, the node service account on Artifact Registry, or the kubelet identity with AcrPull on ACR.
  • Anywhere else, such as on-premises or self-managed Kubernetes, or any registry outside your cloud: a pull Secret.

Any registry, any cluster: a pull Secret​

Put the Secret on the namespace's service account, so every pod there pulls with it and no chart has to name it.

Name the namespace first. If you leave the application's Namespace empty, AstroPulse creates one named after the application with a generated suffix, so you only learn its name after the first pull has already failed.

  1. In Deploy application, set Namespace (or namespace in the application YAML), for example team-a.

  2. Create that namespace and a Secret in it, with a token from your registry that can only read, and put the Secret on the namespace's default service account:

    Terminal
    kubectl create namespace team-a
    kubectl create secret docker-registry regcred \
    --docker-server=<registry> \
    --docker-username=<username> \
    --docker-password=<read-only-token> \
    --namespace=team-a
    kubectl patch serviceaccount default -n team-a \
    -p '{"imagePullSecrets":[{"name":"regcred"}]}'
  3. Deploy. AstroPulse deploys into the namespace you named, beside what is already there, and never deletes it.

Kubernetes copies the service account's pull Secrets into each new pod, so the first pull succeeds:

Terminal
kubectl get pod <pod> -n team-a -o jsonpath='{.spec.imagePullSecrets}'
Output
[{"name":"regcred"}]
tip

The default service account covers only pods that run as default. Many Helm charts create their own service account: for those, name the Secret in the chart's values instead.

values.yaml
imagePullSecrets:
- name: regcred

If the first pull already failed​

With no namespace named and no Secret, the deploy stops at the pull. astroctl app get <name> says so, and shows the namespace AstroPulse created as targetNamespace:

Output
status: Provisioning
statusReason: The image localhost:31500/acme/latency:v1.0.0 could not be pulled. Check
the image name and tag, and that the cluster can reach the registry. Its events
say why.
targetNamespace: registry-docs-b-987575
Warning: The application isn't serving
Nothing serves yet because container astropulse-app cannot pull image localhost:31500/acme/latency:v1.0.0 (ErrImagePull): no basic auth credentials.
  1. Create the Secret in that targetNamespace and put it on its default service account, as in step 2 above.

  2. Restart the pods, because a pod takes its service account's Secrets only when it's created:

    Terminal
    kubectl delete pods --all -n <targetNamespace>

The new pods pull with the Secret and the application reaches Running.

NovaNova
Why can't my app on eks-prod pull ghcr.io/acme/latency:v1.0.0, and what do I set up so it can?

Nova reads the app's events and the cluster, tells you which way of pulling applies, and writes the steps.

Push images from a build in the cluster​

AstroPulse never pushes images. A build that runs in your cluster, such as kpack, pushes with access you give it. That holds on every cluster, whether AstroPulse created it on AWS, Google Cloud or Azure, or you registered it with the agent.

There are many ways to give that access. Use the one your team already uses:

  • The cluster's cloud identity (recommended, keyless). Give the service account the build runs as push rights on your registry, the same way your cloud's page gives an app access to a bucket: an IAM role for Amazon ECR, a Google principal for Artifact Registry, or a managed identity for Azure Container Registry (AWS, Google Cloud, Azure). Clusters AstroPulse creates can pull only, so push rights are always yours to grant.
  • A registry Secret. Works for any registry on any cluster, including Docker Hub and GitHub (ghcr.io), and on a cluster with no cloud identity, such as on-premises. Create it in the build's namespace with a token that can push, and name it on the build's service account. For kpack:
Terminal
kubectl create secret docker-registry registry-credentials \
--docker-server=ghcr.io \
--docker-username=<username> \
--docker-password=<token-with-push-access> \
--namespace=kpack
tip

Grant push only to the build's service account, never to the nodes, so the apps running on the cluster keep read-only access.

How the credential is kept safe​

AstroPulse stores no registry credential. A pull secret you create is a Kubernetes Secret in that namespace of that cluster, and only pods whose spec or service account names it use it. Use a read-only token for pulls and a push token only in the build's namespace, and delete the Secret to stop it.

Pulling from your cloud's registry uses the cluster's own identity, so no registry password exists to leak.

Other ways in​

  • astroctl: none for registries. Registries a cluster pulls from in other AWS accounts, or from Azure, are part of the cluster's spec: ecrAccountIds on EKS and acrResourceIds on AKS. See Amazon EKS and Azure AKS.

If it's refused​

"<entry>" is not a 12-digit AWS account ID
Cause
An entry under Image registries in other AWS accounts (ECR) is not an AWS account ID.
Fix
Enter the 12-digit ID of the account that holds the registry.
"<entry>" is not an Azure Container Registry resource ID
Cause
An entry under Container registries (ACR) is not a registry's full resource ID.
Fix
Run az acr show --name <registry-name> --query id --output tsv and paste what it prints.

A pod stuck in ImagePullBackOff with pull access denied or unauthorized is covered under If the first pull already failed.

Next​

  • Keyless cloud access: how your apps and add-ons reach the rest of your cloud.
  • Image: deploy an application from a container image.
  • Vault: every credential your organization has given AstroPulse.