3

I have a Django app that uses the official Kubernetes client for python and works fine but it only deploys (rightly) public registries.

Is there a way to execute a login and then let Kubernetes client pull a private image freely? I wouldn't like to execute direct cmd commands for the login and the image pull.. Thanks!

Wytrzymały Wiktor
  • 11,492
  • 5
  • 29
  • 37
  • 1
    Apologies, I don't exactly follow your question; the supported way of pulling private images is to create [a `Secret` of type `dockerconfigjson`](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials) and then reference that in [the `imagePullSecret:` of the PodSpec](https://kubernetes.io/docs/concepts/configuration/secret/#using-imagepullsecrets), both of which I would expect the kubernetes client for python can do easily – mdaniel Aug 12 '21 at 16:08

1 Answers1

1

Actually it's pretty easy to do using official Kubernetes Python Client. You need to do two steps:

  • create a secret of type dockerconfigjson (could be done by command line or using Python client) - you are putting here your credentials
  • add this secret into your deployment / pod definition using imagePullSecrets so Kubernetes client can pull images from private repositories

Create secret of type dockerconfigjson:

Replace <something> with your data.

Command line:

kubectl create secret docker-registry private-registry \
 --docker-server=<your-registry-server> --docker-username=<your-name> \
 --docker-password=<your-pword> --docker-email=<your-email>

Equivalent in Kubernetes Python Client (remember to pass in secure way variable password, for example check this):

import base64
import json
from kubernetes import client, config

config.load_kube_config()
v1 = client.CoreV1Api()

# Credentials
username = <your-name>
password = <your-pword>
mail = <your-email>
secret_name = "private-registry"
namespace = "default"

# Address of Docker repository - in case of Docker Hub just use https://index.docker.io/v1/
docker_server = <your-registry-server>

# Create auth token
auth_decoded = username + ":" + password
auth_decoded_bytes = auth_decoded.encode('ascii')
base64_auth_message_bytes = base64.b64encode(auth_decoded_bytes)
base64_auth_message = base64_auth_message_bytes.decode('ascii')

cred_payload = {
    "auths": {
        docker_server: {
            "username": username,
            "password": password,
            "email": mail,
            "auth": base64_auth_message
        }
    }
}

data = {
    ".dockerconfigjson": base64.b64encode(
        json.dumps(cred_payload).encode()
    ).decode()
}

secret = client.V1Secret(
    api_version="v1",
    data=data,
    kind="Secret",
    metadata=dict(name=secret_name, namespace=namespace),
    type="kubernetes.io/dockerconfigjson",
)

v1.create_namespaced_secret(namespace, body=secret)

Add this secret into your deployment / pod definition using imagePullSecrets: option

Now, let's move to using newly created secret - depends how you want to deploy pod / deployment in Python code there are two ways: apply yaml file or create pod / deployment manifest directly in the code. I will show both ways. As before, replace <something> with your data.

Example yaml file:

apiVersion: v1
kind: Pod
metadata:
  name: private-registry-pod
spec:
  containers:
  - name: private-registry-container
    image: <your-private-image>
  imagePullSecrets:
  - name: private-registry

In last line we are referring to secret docker-registry created in previous step.

Let's apply this yaml file using Kubernetes Python client:

from os import path
import yaml
from kubernetes import client, config

config.load_kube_config()
v1 = client.CoreV1Api()

config_yaml = "pod.yaml"

with open(path.join(path.dirname(__file__), config_yaml)) as f:
        dep = yaml.safe_load(f)
        resp = v1.create_namespaced_pod(body=dep, namespace="default")
        print("Deployment created. status='%s'" % str(resp.status))

All in Python code - both pod definition and applying process:

from kubernetes import client, config
import time

config.load_kube_config()
v1 = client.CoreV1Api()

pod_name = "private-registry-pod"
secret_name = "private-registry"
namespace = "default"
container_name = "private-registry-container"
image = <your-private-image>

# Create a pod
print("Creating pod...")

pod_manifest= {
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": pod_name
  },
  "spec": {
    "containers": [
      {
        "name": container_name,
        "image": image
      }
    ],
    "imagePullSecrets": [
      {
        "name": secret_name
      }
    ]
  }
}

resp = v1.create_namespaced_pod(body=pod_manifest, namespace=namespace)

# Wait for a pod
while True:
    resp = v1.read_namespaced_pod(name=pod_name, namespace=namespace)
    if resp.status.phase != 'Pending':
        break
    time.sleep(1)
    
print("Done.")

Sources:

Mikolaj S.
  • 2,850
  • 1
  • 5
  • 17