Skip to content

Build Images in Notebook

In this section, we will build and deploy container images using Kaniko from within a Jupyter notebook. This follows a GCC official implementation of Kaniko. More information on Kaniko can be found here

This functionality can be used to compile Kubernettes KSP IR Dockerfiles, like those for Kubeflow Pipelines.


Notebook

from kfp import dsl

from kubernetes import client, config
from kubernetes.client.rest import ApiException
import time

dockerfile_path = "/Dockerfile"  # Specify
image_name = "" # Specify
namespace = "default" #Specify

def create_kaniko_pod(dockerfile_path, image_name, context_path=None):
    api = client.CoreV1Api()
    # Load the in-cluster configuration
    config.load_incluster_config()

    pod_manifest = {
      "apiVersion": "v1",
      "kind": "Pod",
      "metadata": {"name": "kaniko"},
      "spec": {
        "restartPolicy": "OnFailure",
        "containers": [{
          "name": "kaniko",
          "image": "gcr.io/kaniko-project/executor:latest",
          "args": [
            "--dockerfile=/workspace/Dockerfile",
            "--context=dir:///workspace",
            f"--destination={image_name}",
            "--verbosity=trace"
          ],
          "env": [{
            "name": "GOOGLE_APPLICATION_CREDENTIALS",
            "value": "/secrets/kaniko-secret.json"
          }],
          "volumeMounts": [
            {
              "name": "workspace",
              "mountPath": "/workspace"
            },
            {
              "name": "kaniko-secret",
              "mountPath": "/secrets",
              "readOnly": True
            }
          ]
        }],
        "volumes": [
          {
            "name": "workspace",
            "persistentVolumeClaim": {
              "claimName": "kaniko-pvc"
            }
          },
          {
            "name": "kaniko-secret",
            "secret": {
              "secretName": "kaniko-secret",
            }
          }
        ]
      }
    }

    try:
        api.create_namespaced_pod(namespace=namespace, body=pod_manifest)
        print("Kaniko build pod created.")
        return api.read_namespaced_pod(name="kaniko", namespace=namespace)
    except ApiException as e:
        print("ERROR: API Exception: " + str(e))
        return

try:
    pod = create_kaniko_pod(dockerfile_path, image_name)
    if not pod:
        raise Exception
    while True:
        if pod.status.phase == 'Succeeded':
            print("Build completed successfully.")
            break
        elif pod.status.phase in ['Failed', 'Unknown']:
            print(f"Build failed with status: {pod.status.phase}")
            break
        else:
            print(f"Current pod phase: {pod.status.phase}, waiting for completion...")
        if input("Enter to update status, d to break and delete pod").upper() == 'D':
            break
except ApiException as e:
    print("ERROR: API Exception: " + str(e))
finally:
        try:
            api = client.CoreV1Api()
            api.delete_namespaced_pod(name="kaniko", namespace=namespace)
            print("Kaniko build pod deleted.")
        except ApiException as e:
            print(f"Exception when calling delete_namespaced_pod: {e}")

print("Done")

Environment

Configure Secrets

GCC Service Account Key

Create a .json GCC Key for your project in a GCC service account in the project that your image is going to be pushed to.

Import Secret

Load the .json supplied by the GCC key into the notebook. This can be done by uploading the json, or when not available, pasting the key into a txt file, and renaming it to .json.

Declare Secret

Because the kaniko-secret is mounted from a directory '/secrets', we create a subdirectory '/secrets' and add kaniko-secret.json to it.

kubectl create secret generic kaniko-secret --from-file=kaniko-secret.json=secrets/kaniko-secret.json

Test using:

kubectl get secret kaniko-secret

Create Persistent Volume Claim

Create a Yaml file called 'kaniko-pvc.yaml'. An example file is provided below

kaniko-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: kaniko-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: standard

Set build image name and location

Kaniko requires a place to build a cloud image to. Recommended approach uses a GCR.io bucket image location, but other options can be found of the kaniko github readme: https://github.com/GoogleContainerTools/kaniko

Dockerfile

Define the dockerfile to build. The default is a file 'Dockerfile' within the same directory this can be configured in the pod manifest. For other options like tarball, refer to the kaniko github readme.


Run Create Kaniko Pod

Run the cell to create the kaniko pod. The cell should run and terminate when the user enters 'd'. The dockerfile will be built and pushed. This enables the user to build using kaniko from within a notebook. This thus allows docker-like runs from a notebook. We should see images built and pushed to the destination.


Demo Video

Shown below is a brief video showcasing the steps below. Please follow the steps here if required.