When you want Kubernetes to pull images from Alibaba Cloud ACR, the main workflow is straightforward: build an image, push it to ACR, configure pull credentials in K8S, and then verify whether the Pod can start correctly. If image pulling fails, kubectl describe usually tells you exactly where the problem is. Once the container is running, you can also enter it directly to inspect files or service state.
Build a minimal Alpine + Supervisor base image
A simple base image can be created with Alpine and Supervisor:
Dockerfile
FROM alpine:3.18
RUN apk add --update supervisor && rm -rf /tmp/* /var/cache/apk/*
ENTRYPOINT ["supervisord", "--nodaemon", "--configuration", "/etc/supervisord.conf"]
Build it locally:
$ docker build -t supine .
Push the image to Alibaba Cloud ACR
After building the image, log in to the registry, tag the image, and push it:
# 登录
$ docker login --username=your-name instance7-registry.cn-beijing.cr.aliyuncs.com
# 打 Tag
$ docker tag supine:latest instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/supine:1.0.0
# 推送
$ docker push instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/supine:1.0.0
A few details matter here:
- The password requested by
docker loginis not your Alibaba Cloud account password. It needs to be configured under Instance Management → Access Credentials. - If the image is being accessed from an Alibaba Cloud ECS instance, you can use the internal network address. Also, if immutable image settings are enabled, pushing the same tag again will fail.
Pull the image from the command line
Before involving Kubernetes, it is often useful to confirm that the image can be pulled directly:
$ docker pull instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/supine:1.0.0
If this works but Kubernetes still cannot pull the image, the issue is usually with image pull credentials inside the cluster.
Let Kubernetes pull from ACR
Kubernetes needs a registry secret for private images. There are two common ways to use it:
- create the secret and reference it explicitly in a Pod or Deployment
- bind the secret at the namespace level so it does not need to be repeated in each manifest
Create the secret like this:
$ kubectl create secret docker-registry registry-secret --docker-server=instance7-registry.cn-beijing.cr.aliyuncs.com --docker-username=your-name --docker-password=your-passwd
Or create it directly in a namespace such as default:
$ kubectl create secret docker-registry registry-secret --docker-server=instance7-registry.cn-beijing.cr.aliyuncs.com --docker-username=your-name --docker-password=your-passwd -n default
Generate a test Pod manifest
A quick way to test image pulling is to generate a Pod YAML from the command line:
$ kubectl run test --image=instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.1 --restart=Never --dry-run=client -o yaml > pod.yaml
If you are using the first secret approach and did not bind it to the entire namespace, add the secret reference to the Pod spec:
spec:
imagePullSecrets:
- name: registry-secret
Then apply the manifest:
$ kubectl apply -f pod.yaml
Check whether the Pod pulled successfully
You can inspect the basic Pod state with:
kubectl get pod test
If the image was pulled and the Pod completed normally, the status will show Complated. If not, use the detailed view:
kubectl describe pod test
A typical error when the secret was not configured looks like this:
Warning Failed 12s (x2 over 25s) kubelet Failed to pull image "instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.1": rpc error: code = Unknown desc = failed to pull and unpack image "instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.1": failed to resolve reference "instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.1": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
This is the failure you see when the Pod does not have valid pull credentials. After fixing the secret configuration, apply the manifest again.
One more thing to watch during testing: if you keep reusing the same tag for rebuilt images, Kubernetes may continue using the cached local image instead of the newly built one. In that case, you may see output like this:
Normal Pulled 76s kubelet Container image "instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.1" already present on machine
So if a change does not seem to take effect, image caching may be the real reason.
Example: a Pod with two containers
The following configuration is a reference example. The pattern here is that an initContainer runs first and pulls configuration using the config-sidecar image. After it finishes successfully and exits, the main diamond container starts. Resources can be shared between containers in the same Pod through volumeMounts.
apiVersion: apps/v1
kind: Deployment
metadata:
name: diamond-sidecar
spec:
replicas: 1
selector:
matchLabels:
app: diamond-sidecar
template:
metadata:
labels:
app: diamond-sidecar
spec:
imagePullSecrets:
- name: registry-secret
initContainers:
- name: config-sidecar
image: instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/sidecar:0.0.2
command: ["./config_sidecar.sh"]
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: config-volume
mountPath: /config
containers:
- name: diamond
image: instance7-registry.cn-beijing.cr.aliyuncs.com/appserver/diamond:1.5.27
volumeMounts:
- name: config-volume
mountPath: /config
resources:
limits:
cpu: "256m"
memory: "256Mi"
volumes:
- name: config-volume
emptyDir: {}
In this setup, the shared emptyDir volume is mounted at /config in both containers, allowing the init container to place configuration files there before the main service starts.
Exec into the container for inspection
If you need to verify whether the service is running properly or whether the configuration files were placed in the expected location, you can enter the container directly:
# kubectl exec -it <pod_name> -c <container_name> -- bash
# 如果使用的 alpine 基础镜像,那么应用 sh 而非 bash
$ kubectl exec -it diamond-sidecar-689d756489-tjsdk -c diamond -- sh
For Alpine-based images, use sh rather than bash. This is often the quickest way to confirm what is actually present inside the container at runtime.