Build container images (and push them to a registry) on Kubernetes

shipwright docker build Kubernetes

3 min read | by Jordi Prats

Shipwright is a framework that allow us to build container images and push them to remote registries from within a Kubernetes clusters. It supports popular tools such as Kaniko, Cloud Native Buildpacks and Buildah

Shipwright installation

To install shipwright we will need to install tekton, shipwright itself and predefined build strategies that they provide. We can do it using the following commands:

kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.34.1/release.yaml
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.9.0/release.yaml
kubectl apply -f https://github.com/shipwright-io/build/releases/download/v0.9.0/sample-strategies.yaml

Create secrets

If we need to work with private repositories we will need to create some Kubernetes Secrets containing the key to use to be able to fetch the repository we want to build. To import ~/.ssh/id_rsa into a Kubernetes ssh-auth secret named githubssh we can use the following command:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: githubssh
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: $(base64 -w0  ~/.ssh/id_rsa)
EOF

Again, to be able to push the container image, we are, most likely, going to have to authenticate against it. In case we want to push it to docker Hub we can use the following command (just needing to set docker-username, docker-username and docker-email to the appropriate values)

kubectl create secret docker-registry hubdocker \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=demouser \
  --docker-username=passw0rd \
  --docker-email=demouser@pet2cattle.com

We can, of course, use other solutions like KES to dynamically fetch secrets from an external source.

Build definition

To start defining the build process we'll have to create the Build object defining the template:

  • source: git repository containing the source to build
  • output: Where to upload the container to
apiVersion: shipwright.io/v1alpha1
kind: Build
metadata:
  name: build
spec:
  source:
    url: https://github.com/jordiprats/flask-pet2cattle
    credentials:
      name: githubssh
  strategy:
    name: kaniko
    kind: ClusterBuildStrategy
  output:
    image: docker.io/jordiprats/shipwright-test:latest
    credentials:
      name: hubdocker

Build instance

Using the Build as a template, we can now create a BuildRun that will create a Pod to actually build the container and upload it to the registry:

Using this object we can override the image name that it's going to use using spec.output.name:

apiVersion: shipwright.io/v1alpha1
kind: BuildRun
metadata:
  name: buildrun
spec:
  buildRef:
    name: build
  output:
    image: {{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}

As soon as we apply these objects on the cluster, it will start the build process: Building the container image and then uploading it to the registry using the image name defined on the BuildRun object:

$ kubectl get build
NAME    REGISTERED   REASON      BUILDSTRATEGYKIND      BUILDSTRATEGYNAME   CREATIONTIME
build   True         Succeeded   ClusterBuildStrategy   kaniko              8m10s
$ kubectl get buildrun
NAME       SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
buildrun   True        Succeeded   8m16s       7m39s
$ kubectl get pods
NAME                       READY   STATUS      RESTARTS   AGE
buildrun-rj2wv-pod-q4np5   0/2     Completed   0          8m26s

Posted on 30/05/2022