Veröffentlicht am

Image Pull Policies und Private Registry einrichten

Teilen:
Authors

TL;DR

  • Kubernetes kennt drei Image Pull Policies: Always (immer vom Registry laden), IfNotPresent (nur wenn lokal nicht vorhanden) und Never (nur lokale Images)
  • Private Registries erfordern imagePullSecrets als Docker-Registry-Secret im jeweiligen Namespace
  • Harbor ist eine beliebte self-hosted Registry mit Vulnerability Scanning, RBAC und Replication
  • ServiceAccounts können Default-Pull-Secrets erhalten, sodass nicht jedes Deployment einzeln konfiguriert werden muss

Image Pull Policies und Private Registries

Wenn Kubernetes einen Pod startet, muss es das Container-Image von einer Registry laden. Die Image Pull Policy bestimmt, wann ein neues Image gezogen wird - und bei privaten Registries braucht der Kubelet gültige Zugangsdaten.

Die drei Image Pull Policies

# Vergleich der Image Pull Policies
apiVersion: v1
kind: Pod
metadata:
  name: policy-demo
spec:
  containers:
    # Always: Immer vom Registry laden (Default bei :latest)
    - name: always
      image: nginx:latest
      imagePullPolicy: Always

    # IfNotPresent: Nur laden wenn lokal nicht vorhanden (Default bei Tags)
    - name: ifnotpresent
      image: nginx:1.27.0
      imagePullPolicy: IfNotPresent

    # Never: Nur lokale Images, kein Registry-Zugriff
    - name: never
      image: my-local-app:dev
      imagePullPolicy: Never

Die Default-Policy hängt vom Tag ab:

Image-TagDefault PolicyVerhalten
:latest oder kein TagAlwaysJeder Pod-Start prüft das Registry
Spezifischer Tag (z.B. :1.27.0)IfNotPresentEinmal laden, dann aus dem Cache
SHA-Digest (@sha256:...)IfNotPresentUnveränderlich, Cache sicher

Wichtig: Verwenden Sie in Production niemals :latest. Ein spezifischer Tag oder SHA-Digest macht Deployments reproduzierbar und Rollbacks zuverlässig.


Private Registry mit imagePullSecrets

Für private Registries benötigt Kubernetes Zugangsdaten. Diese werden als docker-registry Secret gespeichert.

Registry-Secret erstellen

# Secret für private Registry erstellen
kubectl create secret docker-registry registry-creds \
  --docker-server=registry.firma.de \
  --docker-username=k8s-deployer \
  --docker-password='sicheres-passwort' \
  --docker-email=deployer@firma.de \
  --namespace=production

Secret im Deployment verwenden

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-api
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend-api
  template:
    metadata:
      labels:
        app: backend-api
    spec:
      containers:
        - name: api
          image: registry.firma.de/backend/api:2.4.1
          ports:
            - containerPort: 8080
      imagePullSecrets:
        - name: registry-creds

Das Secret muss im gleichen Namespace wie das Deployment existieren. Bei mehreren Namespaces müssen Sie das Secret in jedem Namespace anlegen.

Default Pull Secrets per ServiceAccount

Statt jedes Deployment einzeln mit imagePullSecrets zu versehen, können Sie das Secret am Default-ServiceAccount hinterlegen:

# Secret zum Default-ServiceAccount hinzufügen
kubectl patch serviceaccount default \
  -n production \
  -p '{"imagePullSecrets": [{"name": "registry-creds"}]}'

# Prüfen ob das Secret hinterlegt ist
kubectl get serviceaccount default -n production -o yaml

Danach verwenden alle Pods im Namespace production, die den Default-ServiceAccount nutzen, automatisch dieses Pull-Secret. Das reduziert Konfigurationsaufwand erheblich.

Für dedizierte ServiceAccounts:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-deployer
  namespace: production
imagePullSecrets:
  - name: registry-creds
  - name: backup-registry-creds

Harbor als Private Registry

Harbor ist eine Open-Source-Registry mit Enterprise-Features: Vulnerability Scanning, RBAC, Image Replication und Audit Logging.

Harbor im Kubernetes installieren

# Harbor via Helm installieren
helm repo add harbor https://helm.goharbor.io
helm repo update

helm install harbor harbor/harbor \
  --namespace harbor \
  --create-namespace \
  --set expose.type=ingress \
  --set expose.ingress.hosts.core=registry.firma.de \
  --set expose.tls.certSource=secret \
  --set expose.tls.secret.secretName=harbor-tls \
  --set persistence.persistentVolumeClaim.registry.size=50Gi \
  --set harborAdminPassword='admin-passwort-aendern'

Image in Harbor pushen

# Bei Harbor anmelden
docker login registry.firma.de -u admin

# Image taggen und pushen
docker tag my-app:1.0 registry.firma.de/project/my-app:1.0
docker push registry.firma.de/project/my-app:1.0

Harbor-Secret für Kubernetes erstellen

# Robot-Account in Harbor erstellen (Web-UI oder API)
# Dann Secret mit Robot-Credentials anlegen
kubectl create secret docker-registry harbor-creds \
  --docker-server=registry.firma.de \
  --docker-username='robot$k8s-deployer' \
  --docker-password='robot-token-hier' \
  --namespace=production

Harbor Robot-Accounts haben eingeschränkte Rechte und sind für CI/CD-Pipelines und Kubernetes besser geeignet als persönliche Accounts.


Fehlerbehebung bei Image Pull Errors

Die häufigsten Fehler und ihre Ursachen:

FehlerUrsacheLösung
ErrImagePullRegistry nicht erreichbar oder falscher Image-NameRegistry-URL und Image-Tag prüfen
ImagePullBackOffWiederholte Fehlversuche nach ErrImagePullSecret prüfen, Registry-Zugang testen
ErrImageNeverPullPolicy Never, Image lokal nicht vorhandenImage auf den Node laden oder Policy ändern

Nützliche Debug-Befehle:

# Pod-Events anzeigen (zeigt Pull-Fehler)
kubectl describe pod backend-api-xyz -n production

# Secret-Inhalt prüfen (base64-decoded)
kubectl get secret registry-creds -n production \
  -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .

# Manueller Pull-Test auf dem Node
crictl pull --creds 'user:pass' registry.firma.de/project/my-app:1.0

Multi-Registry Setup

In größeren Umgebungen nutzen Sie oft mehrere Registries - zum Beispiel eine interne Harbor-Instanz und eine Cloud-Registry als Mirror:

apiVersion: v1
kind: Pod
metadata:
  name: multi-registry
spec:
  containers:
    - name: app
      image: registry.firma.de/project/app:1.0
    - name: sidecar
      image: europe-west3-docker.pkg.dev/my-project/repo/sidecar:2.1
  imagePullSecrets:
    - name: harbor-creds
    - name: gcr-creds

Kubernetes probiert die Secrets der Reihe nach durch, bis eines passt. Ordnen Sie die Secrets nach Häufigkeit der Nutzung.


FAQ

Wann sollte ich Always statt IfNotPresent verwenden?

Verwenden Sie Always nur in Entwicklungsumgebungen, wo Sie häufig das gleiche Tag überschreiben. In Production nutzen Sie spezifische Tags mit IfNotPresent - das spart Netzwerk-Traffic und beschleunigt Pod-Starts.

Kann ich imagePullSecrets cluster-weit konfigurieren?

Nicht nativ. Die sauberste Lösung ist ein Admission Webhook oder ein Tool wie Kyverno, das automatisch Pull-Secrets in neue Namespaces injiziert. Alternativ nutzen Sie den ServiceAccount-Ansatz pro Namespace.

Was passiert bei abgelaufenen Registry-Credentials?

Laufende Pods sind nicht betroffen - das Image ist bereits geladen. Neue Pods oder Restarts schlagen mit ImagePullBackOff fehl. Erneuern Sie das Secret und die Pods starten automatisch beim nächsten Retry.

Wie sichere ich Harbor für Production ab?

Aktivieren Sie TLS, nutzen Sie Robot-Accounts statt persönliche Logins, aktivieren Sie Trivy Vulnerability Scanning und konfigurieren Sie Replication zu einer Backup-Registry. Beschränken Sie den Zugriff per RBAC auf Projekt-Ebene.

Kann ich Images vorab auf alle Nodes laden?

Ja, mit einem DaemonSet das imagePullPolicy: Always nutzt und danach gelöscht wird. Tools wie warm-image oder kube-fledged automatisieren diesen Prozess für häufig genutzte Base-Images.

Kubernetes-Security & Compliance?

Security-Audits, Penetration Tests und Compliance-Beratung für Ihre Container-Infrastruktur. BSI-Grundschutz, DSGVO, ISO 27001.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen