Build a Container Image Inside a Kubernetes Cluster and Push it to IBM Cloud Container Registry

4 min read

Using Kaniko to build a container image in a Kubernetes cluster and push it to IBM Cloud Container Registry

We’re going to show you how to build a source into a container image from a Dockerfile inside a Kubernetes cluster and push the image to IBM Cloud Container Registry—all of this using Google’s Kaniko, a tool to build container images from a Dockerfile inside a container or Kubernetes cluster.

If you don’t have a Kubernetes cluster with Knative and Istio installed, it’s recommended to follow the instructions mentioned in my previous post that also introduces you to the components of Knative —”Install Knative with Istio and deploy an app on IBM Cloud.”

Knative Build and Serving

This tutorial uses the Build and Serving components of Knative to orchestrate an end-to-end deployment.

A Knative Build extends Kubernetes and utilizes existing Kubernetes primitives to provide you with the ability to run on-cluster container builds from source. For example, you can write a build that uses Kubernetes-native resources to obtain your source code from a repository, build it into container image, and then run that image.

Knative Serving builds on Kubernetes and Istio to support deploying and serving of serverless applications and functions. Serving is easy to get started with and scales to support advanced scenarios.

To learn more about Knative and Istio, please see our explainer videos, “What is Knative?” and “What is Istio?

What is a Build template?

BuildTemplate is one of the key features of Knative build used to defined reusable templates, and it encapsulates a shareable build process with some limited parameterization capabilities. A set of curated and supported build templates is available in the build-templates repo. We will be using the Kaniko BuildTemplate in this tutorial.

Kaniko doesn’t depend on a Docker daemon and executes each command within a Dockerfile completely in userspace. This enables you to builing container images in environments that can’t easily or securely run a Docker daemon, such as a standard Kubernetes cluster.

Creating a Kaniko BuildTemplate

Let’s start by creating a Kaniko BuildTemplate and saving this as kaniko.yaml:

kind: BuildTemplate
  name: kaniko
  - name: IMAGE
    description: registry.<region><namespace>/knative-node-kaniko #replace <region> and <namespace>
  - name: DOCKERFILE
    description: ./Dockerfile
    default: /workspace/Dockerfile

  - name: build-and-push
    - --dockerfile=${DOCKERFILE}
    - --destination=${IMAGE}


  • IMAGE: The Docker image name to apply to the newly built image (required). Replace <region>and <namespace> with appropriate values. Remember these values because you have to replace these values in the YAMLscripts below.

  • DOCKERFILE: The path to the Dockerfile to execute (default:./Dockerfile)

Note: To check your region, run ibmcloud cr region.

To set up a new namespace, refer to this resource.

If you are looking for a sample with Dockerfile, try

Authenticating to IBM Cloud Container Registry

Kaniko builds an image and pushes it to the destination defined as a parameter. In order to properly authenticate to the remote container registry (IBM Cloud Container Registry), the build needs to have the proper credentials. This is achieved using a build ServiceAccount.

First, let’s define a Secret containing the username and password that the build should use to authenticate (basic) to IBM Cloud Container Registry:

apiVersion: v1
kind: Secret
  name: basic-user-pass
  annotations: registry.<region> # replace the <region>
  username: token # username
  password: <password> # token-value

For <password>, run the below command:

 ibmcloud cr token-add --description “This is a token” --non-expiring --readwrite


Token identifier 58669dd6–3ddd-5c78–99f9-ad0a5aabd9ad 
Token            <token_value>

Use the returned token_value as your password and save the file as secret.yaml . For more details related to token, please refer to this resource.

Now you can create a serviceaccount.yaml file with the ServiceAccount using the secret as shown below:

apiVersion: v1
kind: ServiceAccount
  name: build-bot
- name: basic-user-pass

Let’s use ServiceAccount in our Build and save the file as build.yaml:

kind: Build
  name: kaniko-build
  serviceAccountName: build-bot
      url: # source code from GitHub
      revision: master
    name: kaniko
    - name: IMAGE
      value: registry.<region><namespace>/knative-node-kaniko # replace <region> and <namespace>

Execute the build:

kubectl apply --filename kaniko.yaml
kubectl apply --filename secret.yaml
kubectl apply --filename serviceaccount.yaml
kubectl apply --filename build.yaml

The build should now have been kicked off. Let’s take a look.

Running kubectl get pods, you should see a pod named kaniko-build with a postfix(say XXXXX).

Running kubectl get pods

For logs, run this command:

 kubectl logs kaniko-build-XXXXX -c build-step-build-and-push
run command

If everything runs as expected, you should see the image in the list when you run the following command:

ibmcloud cr images

Deploy and serve the app

Hurray!! you have just created a container image without a Docker Daemon. Let’s deploy and serve the app so that we can access it from anywhere. For this, let’s create a service.yaml file:

apiVersion: # Current version of Knative
kind: Service
  name: knative-node-kaniko # The name of the app
  namespace: default # The namespace the app will use
            image: registry.<region><namespace>/knative-node-kaniko # The URL to the image of the app on IBMCLOUD Registry
            - name: TARGET # The environment variable printed out by the sample app
              value: "Kaniko Node App running on IBM Cloud"

Execute the service:

kubectl apply --filename service.yaml

To find the IP address for your service, use kubectl get svc knative-ingressgateway -n istio-system to get the ingress IP for your cluster. If your cluster is new, it may take some time for the service to get assigned an external IP address:

export IP_ADDRESS=$(kubectl get svc knative-ingressgateway --namespace istio-system --output 'jsonpath={.status.loadBalancer.ingress[0].ip}')

To find the URL for your service, use kubectl get knative-node-app --output jsonpath='{.status.domain}':

export HOST_URL=$(kubectl get knative-node-kaniko  --output jsonpath='{.status.domain}')

Now you can make a request to your app to see the result:

curl -H "Host: ${HOST_URL}" http://${IP_ADDRESS}

Response: Kaniko Node App running on IBM Cloud

Response: Kaniko Node App running on IBM Cloud

For a sample with all these YAML templates and scripts, please refer to this link.

Clean up

Run the below command to remove the sample app from your cluster:

kubectl delete --filename service.yaml

To delete other secret,ServiceAccount and Build:

kubectl delete --filename build.yaml
kubectl delete --filename serviceaccount.yaml
kubectl delete --filename secret.yaml
kubectl delete --filename kaniko.yaml

To delete the cluster (removes everything), enter the following command:

ibmcloud cs cluster-rm $CLUSTER_NAME

More solution tutorials

Please check our solution tutorials concerning Kubernetes for more great information.

Questions or concerns? Feel free to reach out on Twitter @VidyasagarMSC.

Be the first to hear about news, product updates, and innovation from IBM Cloud