In this tutorial, I’m going to show you how to build a source into a container image from a Dockerfile, by using Google’s kaniko. Finally, we’ll run this container on a private cloud. As many of us in the developer world already know, the private cloud has higher security because a single company or organization is the only designated entity that can access it. For the purposes of this tutorial, I’ll be using IBM Cloud™ Private (ICP) as an example. ICP can satisfy the customization requirements for the users. In this tutorial, we see that the Istio and Knative deployments have already deployed on the IBM Cloud Private system so that users can use kaniko to orchestrate from the source code to the application directly.
So what is kaniko and how does it work? kaniko is a tool that you can use to build container images from a Dockerfile inside a container or Kubernetes cluster.
Prerequisites
Make sure to have the following before beginning this tutorial:
- Prepare your IBM Cloud Private environment, which should deploy both Istio and Knative on it.
- Install Knative on IBM Cloud Private.(The Knative build uses kaniko as the BuildTemplate to build our image and Knative serving will use the image to start its container.)
Steps
As shown in the workflow image above, we can see kaniko as an image in the Knative build template. After you build your image, the build source will be in the container and executes by using the kaniko executor to build the image. Then it pushes the image to the Dockerhub that you specify.
We can also see a major advantage where the whole process from source code to application runs normally. This can simplify the compilation and deployment environment for the developers. The temporary file, such as the original code, dockerfile, and the compiled images won’t leave anything over in the cluster.
Deploy kaniko
kaniko is meant to be run as an image, so in your container execute the binary:
gcr.io/kaniko-project/executor
Deploy kaniko’s build template onto IBM Cloud Private.
cat <<EOF | kubectl apply -f - apiVersion: build.knative.dev/v1alpha1 kind: BuildTemplate metadata: name: kaniko spec: parameters: - name: IMAGE description: The name of the image to push - name: DOCKERFILE description: Path to the Dockerfile to build. default: /workspace/Dockerfile steps: - name: build-and-push image: gcr.io/kaniko-project/executor args: - --dockerfile=${DOCKERFILE} - --destination=${IMAGE} env: - name: DOCKER_CONFIG value: /builder/home/.docker EOF
Orchestrate a source-to-URL deployment on IBM Cloud Private
Create a new Secret manifest, which is used to store your DockerHub credentials.
apiVersion: v1 kind: Secret metadata: name: basic-user-pass annotations: build.knative.dev/docker-0: https://index.docker.io/v1/ type: kubernetes.io/basic-auth data: # Use 'echo -n "username" | base64' to generate this string username: BASE64_ENCODED_USERNAME # Use 'echo -n "password" | base64' to generate this string password: BASE64_ENCODED_PASSWORD
Use the following command to generate the
base64
-encoded values required for the manifest:$ echo -n "username" | base64 -w 0 dXNlcm5hbWU= $ echo -n "password" | base64 -w 0 cGFzc3dvcmQ=
Create a new Service Account manifest which is used to link the build process to the secret.
cat <<EOF |kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: build-bot secrets: - name: basic-user-pass EOF
Deploy the sample. This sample uses https://github.com/zxDiscovery/helloworld as a basic Go application, but you could replace this GitHub repo with your own. The only requirements are that the repo must contain a Dockerfile with the instructions for how to build a container for the application.
You need to create a service manifest that defines the service to deploy, including where the source code is and which build template to use. Make sure to replace {DOCKER_USERNAME} with your own DockerHub username:
cat <<EOF | kubectl apply -f - apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: app-from-source namespace: default spec: runLatest: configuration: build: apiVersion: build.knative.dev/v1alpha1 kind: Build spec: serviceAccountName: build-bot source: git: url: https://github.com/zxDiscovery/helloworld.git revision: master template: name: kaniko arguments: - name: IMAGE value: docker.io/{DOCKER_USERNAME}/app-from-source:latest timeout: 10m revisionTemplate: spec: container: image: docker.io/{DOCKER_USERNAME}/app-from-source:latest imagePullPolicy: Always env: - name: SIMPLE_MSG value: "Hello from the sample app!" EOF
Apply this manifest by using
kubectl
and watch the results. Wait for the pod statusRunning
:$ kubectl get pods --watch NAME READY STATUS RESTARTS AGE app-from-source-00001-zhddx 0/1 Init:2/3 0 7s app-from-source-00001-zhddx 0/1 PodInitializing 0 37s app-from-source-00001-zhddx 0/1 Completed 0 38s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Pending 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Pending 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Init:0/1 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Init:0/1 0 2s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 PodInitializing 0 3s app-from-source-00001-deployment-6d6ff665f9-xfhm5 2/3 Running 0 6s app-from-source-00001-deployment-6d6ff665f9-xfhm5 3/3 Running 0 11s
To check on the state of the service, get the service object and examine the status block:
$ kubectl get ksvc app-from-source --output yaml [...] status: conditions: - lastTransitionTime: 2018-07-11T20:50:18Z status: "True" type: ConfigurationsReady - lastTransitionTime: 2018-07-11T20:50:56Z status: "True" type: RoutesReady - lastTransitionTime: 2018-07-11T20:50:56Z status: "True" type: Ready domain: app-from-source.default.example.com latestCreatedRevisionName: app-from-source-00007 latestReadyRevisionName: app-from-source-00007 observedGeneration: 10 traffic: - configurationName: app-from-source percent: 100 revisionName: app-from-source-00007
Verify the pod that you created by checking that the service is running normally:
$ kubectl get svc istio-ingressgateway --namespace istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.0.238.42 9.30.212.10 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:31007/TCP,15030:31211/TCP,15031:32043/TCP,15032:31139/TCP,15443:30390/TCP,15020:30332/TCP 6d $ kubectl get ksvc app-from-source --output=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain NAME DOMAIN app-from-source app-from-source.default.example.com $ curl -H "Host: app-from-source.default.example.com" http://9.30.212.10 Hello from the sample app!"
Now that your service is created, Knative will perform the following steps:
- Fetch the revision specified from GitHub and use kaniko build it into a container.
- Push the container to DockerHub.
- Create a new immutable revision for this version of the app.
- Network programs to create a route, ingress, service, and load balancer for your app.
- Automatically scale your pods up and down (including zero active pods).
What’s next
Congratulations, you successfully built a container image onto a private cloud through our example using kaniko and ICP. For more on DockerHub, check out the tutorial “Gain access to your DockerHub public and private repos”. If you’re interested in reading up on Knative, check out the Knative page for more tutorials.