Tanzu Build Service (beta) – Guide

Tanzu Build Service

Tanzu Build Service uses Cloud Native Buildpacks (CNBs) to turn source code into OCI (Open Container Initiative) compatible container images, no manual compilation or Dockerfiles. This is something developers using CloudFoundry/PAS/TAS loved, and this bring this same experience to application running on Kubernetes.

Build Service also solves some of the biggest operational and security challenges that come with maintaining software over time by removing the need for a human to intervene when there are updates to your software or its dependencies. Automating the maintenance of your containers is especially important because it drastically reduces the risk of critical security vulnerabilities being left unpatched.


We will be doing a lab where we install Tanzu Build Service (beta) version v0.2.0 and deploy a Go application.

You will need to have the following requirements:

  • An Kubernetes cluster (v1.14 or later) with PersistentVolumes. I’m using an Azure AKS cluster (2 nodes) so I have multiple StorageClasses that can be used to provision volumes.
> kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-agentpool-20474252-vmss000000   Ready    agent   8d    v1.16.9
aks-agentpool-20474252-vmss000001   Ready    agent   8d    v1.16.9

> kubectl get sc
NAME                PROVISIONER                AGE
azurefile           kubernetes.io/azure-file   8d
azurefile-premium   kubernetes.io/azure-file   8d
default (default)   kubernetes.io/azure-disk   2d1h
managed-premium     kubernetes.io/azure-disk   2d1h

  • An OCI container registry. This can be public or private registry. I will be using Docker hub
  • Download the duffle executable for your operating system from the Tanzu Build Service page on Tanzu Network.
  • Download the kp binary from the Tanzu Build Service page on Tanzu Network.
  • Download the Build Service Bundle from the Tanzu Build Service page on Tanzu Network.

Create the Tanzu Build Service credentials file

The credentials file tells Tanzu Build Service where your Kubernetes config file is in order to connect to it. It also defines credentials for Tanzu Build Service to connect to your image repository in order to complete the install. Since this guide uses Docker Hub for the install, we don’t need to define credentials for the registry in this step.

name: build-service-credentials
credentials:
 - name: kube_config
   source:
     path: "/home/jfcoronado/.kube/config"
   destination:
     path: "/root/.kube/config"

Push the Tanzu Build Service bundle to Docker Hub

The bundle (build-service-0.2.0.tgz) contains many images for the buildpack runtime packages Tanzu Build Service will use to build your images. It also contains the install image for Tanzu Build Service. For Tanzu Build Service to have access to these images, they need to be pushed to the image registry. 

First, log in to your Docker Hub account. This command will ask you for your username and password.

>docker login
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /home/jfcoronado/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Then use Duffle to push the bundle to the repo:

>duffle relocate -f ./build-service-0.2.0.tgz -m /tmp/relocated.json -p jfcoronado

Install Tanzu Build Service 

Now it’s time to install Tanzu Build Service. This command will utilize many of the environment variables we previously defined.

The kubernetes_env attribute is the name of your Kubernetes cluster. You can get it by running “kubectl config get-clusters” that will give you a list of your configured clusters.

>kubectl config get-clusters
NAME
aks-cluster

custom_builder_image is the fully-qualified tag where Build Service will create a default cluster-wide builder.

>duffle install my-build-service -c /tmp/credentials.yml \
--set kubernetes_env=aks-cluster \
--set docker_registry=index.docker.io \
--set docker_repository=jfcoronado \
--set registry_username="jfcoronado" \
--set registry_password="XXXXXXXXX" \
--set custom_builder_image="jfcoronado/default-builder" \
-f /home/jfcoronado/Downloads/build-service-0.2.0.tgz \
-m /tmp/relocated.json

The docker_ and registry_ flags you set the registry information, in my case my Docker Hub account.

The installation will take a couple of minutes. After that you can test that your installation was successful running kp command:

>kp custom-cluster-builder list
NAME       READY    STACK                                 IMAGE
base       true     io.buildpacks.stacks.bionic           jfcoronado/default-builder:base@sha256:f6df65162effe938e00b83557d052827f4d1bd3b47bbdf765e6a2b4c4267b4b2
default    true     org.cloudfoundry.stacks.cflinuxfs3    jfcoronado/default-builder:default@sha256:df185b47e0a725260a27d5bb5160779ac0dfe729d8e3fa51cf43dc5baa17e7d2
full       true     org.cloudfoundry.stacks.cflinuxfs3    jfcoronado/default-builder:full@sha256:df185b47e0a725260a27d5bb5160779ac0dfe729d8e3fa51cf43dc5baa17e7d2
tiny       true     io.paketo.stacks.tiny                 jfcoronado/default-builder:tiny@sha256:20b3e0c56596e9d45c7f0aea10ade3afa3226e14054b4172d22c49053f1a1508

Playing with Build Service

Let’s build an application. For this I’m going to use a demo app written on Go that was used in the SpringOne Tour 2020. I will start by cloning the repo locally.

>git clone https://github.com/springone-tour-2020-cicd/go-sample-app
Cloning into 'go-sample-app'...
remote: Enumerating objects: 111, done.
remote: Total 111 (delta 0), reused 0 (delta 0), pack-reused 111
Receiving objects: 100% (111/111), 13.40 KiB | 4.47 MiB/s, done.
Resolving deltas: 100% (39/39), done.

It have already a Docker file that we will not need so let’s go and delete it to make sure we are not using it:

>cd go-sample-app 
>ls
Dockerfile  go.mod  hello-server.go  README.md
>rm Dockerfile 

For Build Service to work we need to create a secret with our registry credentials. You can create it using the kp tool this way:

>kp secret create docker-hub --dockerhub jfcoronado
dockerhub password: 
"docker-hub" created

>kp secret list
NAME                       TARGET
default-token-xzcrd        
docker-hub                 https://index.docker.io/v1/ 

Now we can generate an image also using kp image command. This will generate a pod that will build the image and push it to our registry. You can monitor the pod until it get completed.

>kp image create go-sample-app jfcoronado/go-sample-app --local-path .

>kubectl get pods
NAME                                        READY   STATUS      RESTARTS   AGE
go-sample-app-build-1-qft69-build-pod        0/1     Init:1/6    0          12s

>kubectl get pods
NAME                                        READY   STATUS      RESTARTS   AGE
go-sample-app-build-1-qft69-build-pod        0/1     Completed   0          4m5s

Now you can go ahead and try your app

>kubectl run go-sample-app --image=jfcoronado/go-sample-app:latest
pod/go-sample-app created

>kubectl get pods
NAME                                READY   STATUS      RESTARTS   AGE
go-sample-app                       1/1     Running     0          54s
go-sample-build-1-qft69-build-pod   0/1     Completed   0          12m

>kubectl port-forward go-sample-app 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

>curl localhost:8080
Hello, world!


And vuala! We have our Go app running. We went from source code to container, no compiling, no Dockerfile creation, following cloud native best practices. Easy!