Cloud Native Buildpacks: Getting Started with `kpack` to Automate Builds

Tyler Britten & Ivan Tarin

kpack is a Kubernetes-native build service that builds container images on Kubernetes using Cloud Native Buildpacks. It takes source code repositories (like GitHub), builds the code into a container image, and uploads it to the container registry of your choice.

Before You Begin

There are a few things you need to do before getting started with kpack:

  • Have access to a Kubernetes cluster. If you don’t, you can use local options like Docker Desktop or Minikube.

  • Check out Kubernetes 101 on KubeAcademy, particularly if you’ve never worked with Kubernetes before.

  • Optionally install stern, a tool that makes it easy to tail the logs during builds.

    • Command to install with Homebrew on Mac OS brew install stern
  • Have the kubectl CLI to interact with your cluster.

    • Command to install with Homebrew on Mac OS brew install kubectl
  • Accessible Docker V2 Registry, DockerHub will suffice it is free and creating an account is easy.

  • Follow the documentation for installing kpack in your Kubernetes cluster.

Initial kpack Configuration

Among the things you will need before you get started are a code repository with compatible code (I’m using Spring Java in this case) and a container registry (I’m using Google GCR).

To make sure your kpack environment is ready after following the install instructions above, run.

kubectl get pods --namespace kpack --watch

Using kpack

Set Up Container Registry Secret

The first thing you need to do is tell kpack how to access the container registry to upload the completed images when they’re done.

You’ll need a secret with credentials to access GCR, so you’ll create a manifest like this and apply it with kubectl apply -f.

gcr-registry-credentials.yaml
dockerhub-registry-credentials.yaml

For more details see the kpack secrets documentation.

Also note the annotation of kpack.io/docker; it tells kpack which registries to use these credentials for. In the case of gcr-registry-credentials.yaml, any image tagged for us.gcr.io.

Set Up Container Registry Service Account

Now you need a service account referencing those credentials in your secret. The manifest is pretty simple:

gcr-registry-service-account.yaml
dockerhub-service-account.yaml

Create your Store

A store is a repository of buildpacks packaged into buildpackages that kpack uses to build images. You can add more languages by including more buildpacks you create or from Paketo Buildpacks we have only included a few bellow.

The store will be referenced by a builder resource.

kubectl apply -f store.yaml 
store.yaml

Apply a Cluster Stack

A stack provides the buildpack lifecycle with build-time and run-time environments in the form of images.

The pack CLI command: pack suggest-stacks will display a list of recommended stacks that can be used. We recommend starting with the io.buildpacks.stacks.bionic base stack.

kubectl apply -f stack.yaml
stack.yaml

Apply a Builder

A builder is an image that bundles all the bits and information on how to build your apps, like

  • A buildpack
  • An implementation of the lifecycle
  • A build-time environment that platforms may use to execute the lifecycle.

Kpack will push the builder image to your registry.

kubectl apply -f builder.yaml 
builder.yaml

Create an Image Configuration

Now you’re all ready to start building images and pushing them to your registry. To create a manifest that builds containers off the application code on GitHub:

gcr-image.yaml
dockerhub-image.yaml

You can see the GitHub URL, and that you’re building off master. Also, you configured the desired image tag (including the registry) and included the service account and builders you created. Once you apply this manifest, it will begin building.

By running kubectl get images you should see the image created but not complete:

NAME              LATESTIMAGE   READY
petclinic-image                 Unknown

Watching the Build

If you run a kubectl get pods, you’ll see a pod created (with a series of init containers) to build the image.

Since it includes six different containers, it’s hard to use kubectl logs because you have to know which container to specify at which stage. It’s much easier to use the stern tool mentioned at the beginning.

The pod that is created has a name that starts with image-name-build; so in this case, petclinic-image-build. The command to run to see the logs is stern petclinic-image-build, and you’ll see all the logs pass by during the build and upload.

Once it’s complete you can recheck the image with kubectl get images:

NAME LATESTIMAGE                                                                                                        READY
petclinic-image   us.gcr.io/pgtm-tbritten/spring-petclinic@sha256:<sha hash>   True

You can now run docker pull us.gcr.io/<project>/<spring-petclinic> to download the completed image. Or you can create a Kubernetes manifest to run the image.

As mentioned in the previous section on image configuration, the spec.source.git.revision is the commit used to build, try changing it to trigger a new build!

Bonus - Deploy your app to Kubernetes

Kpack is best used in conjunction with a CI/CD tool, but if you want to deploy your app to Kubernetes now you can very easily.

You will reuse your secret with your registry and pull from the repository that holds the container image. You created this repo in the Create an Image Configuration section and can be found at spec.tag place it after --image=$DH_USERNAME/app .

Create a deployment with the image kpack made with your source code

kubectl create deployment kpack-demo --image=<registry-name>/<app-repo>      

To verify deployment

kubectl get deployments                                          

Expose the Pod to the public internet using the kubectl expose command:

kubectl expose deployment kpack-demo --type=LoadBalancer --port=8080

The --type=LoadBalancer flag exposes your Service outside of the cluster. The application code inside the image k8s.gcr.io/echoserver only listens on TCP port 8080.

To verify your service

kubectl get services                

On cloud providers that support load balancers, an external IP address would be provisioned to access the Service.

On minikube, the LoadBalancer type makes the Service accessible using:

minikube service kpack-demo