Build and push an image with Tekton
This guide shows you how to:
- Create a Task to clone source code from a git repository.
- Create a second Task to use the cloned code to build a Docker image and push it to a registry.
If you are already familiar with Tekton and just want to see the example, you can skip to the full code samples.
Prerequisites
-
To follow this How-to you must have a Kubernetes cluster up and running and kubectl properly configured to issue commands to your cluster.
-
Install Tekton Pipelines:
kubectl apply --filename \ https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
See the Pipelines installation documentation for other installation options.
-
Install the Tekton CLI,
tkn
, on your machine.
If this is your first time using Tekton Pipelines, we recommend that you complete the Getting Started tutorials before proceeding with this guide.
Clone the repository
Create a new Pipeline, pipeline,yaml
, that uses the git clone Task to clone
the source code from a git repository:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-build-push
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and
pushes it to a registry
params:
- name: repo-url
type: string
workspaces:
- name: shared-data
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
Then create the corresponding pipelinerun.yaml
file:
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-build-push-run-
spec:
pipelineRef:
name: clone-build-push
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
params:
- name: repo-url
value: https://github.com/google/docsy-example.git
For this how-to we are using a public repository as an example. You can also use git clone with private repositories, using SSH authentication.
Build the container image with Kaniko
To build the image use the Kaniko Task from the community hub.
-
Add the image reference to the
params
section inpipeline.yaml
:params: - name: image-reference type: string
This parameter is used to add the tag corresponding the container registry where you are going to push the image.
-
Create the new
build-push
Task in the samepipeline.yaml
file:tasks: ... - name: build-push runAfter: ["fetch-source"] taskRef: name: kaniko workspaces: - name: source workspace: shared-data params: - name: IMAGE value: $(params.image-reference)
This new Task refers to
kaniko
, which is going to be installed from the community hub. A Task has its own set ofworkspaces
andparams
passed down from the parameters and Workspaces defined at Pipeline level. In this case, the Workspacesource
and the value ofIMAGE
. Check the kaniko Task documentation to see all the available options. -
Instantiate the
build-push
Task. Add the value ofimage-reference
to theparams
section inpipelinerun.yaml
:params: - name: image-reference value: container.registry.com/sublocation/my_app:version
Replace
container.registry.com/sublocation/my_app:version
with the actual tag for your registry. You can set up a local registry for testing purposes.
Check the full code samples to see how all the pieces fit together.
Container registry authentication
In most cases, to push the image to a container registry you must provide authentication credentials first.
-
Set up authentication with the Docker credential helper and generate the Docker configuration file,
~/.docker/config.json
, for your registry. This step is different depending on your registry.- Google Artifact Registry
- Red Hat Quay
- Docker Hub
- Azure container registry
- Amazon ECR
- Jfrog Artifactory
Check your cloud provider documentation to complete this step.
-
Create a Kubernetes Secret,
docker-credentials.yaml
with your credentials:apiVersion: v1 kind: Secret metadata: name: docker-credentials data: config.json: efuJAmF1...
The value of
config.json
is the base64-encoded~/.docker/config.json
file. You can get this data with the following command:cat ~/.docker/config.json | base64 -w0
-
Update
pipeline.yaml
and add a Workspace to mount the credentials directory:At the Pipeline level:
workspaces: - name: docker-credentials
And under the
build-push
Task:workspaces: - name: dockerconfig workspace: docker-credentials
-
Instantiate the new
docker-credentials
Workspace in yourpipelinerun.yaml
file by adding a new entry underworkspaces
:- name: docker-credentials secret: secretName: docker-credentials
See the complete files in the full code samples section.
Run your Pipeline
You are ready to install the Tasks and run the pipeline.
-
Install the
git-clone
andkaniko
Tasks:tkn hub install task git-clone tkn hub install task kaniko
-
Apply the Secret with your Docker credentials.
kubectl apply -f docker-credentials.yaml
-
Apply the Pipeline:
kubectl apply -f pipeline.yaml
-
Create the PipelineRun:
kubectl create -f pipelinerun.yaml
This creates a PipelineRun with a unique name each time:
pipelinerun.tekton.dev/clone-build-push-run-4kgjr created
-
Use the PipelineRun name from the output of the previous step to monitor the Pipeline execution:
tkn pipelinerun logs clone-build-push-run-4kgjr -f
After a few seconds, the output confirms that the image was built and pushed successfully:
[fetch-source : clone] + '[' false '=' true ] [fetch-source : clone] + '[' false '=' true ] [fetch-source : clone] + '[' false '=' true ] [fetch-source : clone] + CHECKOUT_DIR=/workspace/output/ [fetch-source : clone] + '[' true '=' true ] [fetch-source : clone] + cleandir [fetch-source : clone] + '[' -d /workspace/output/ ] [fetch-source : clone] + rm -rf '/workspace/output//*' [fetch-source : clone] + rm -rf '/workspace/output//.[!.]*' [fetch-source : clone] + rm -rf '/workspace/output//..?*' [fetch-source : clone] + test -z [fetch-source : clone] + test -z [fetch-source : clone] + test -z [fetch-source : clone] + /ko-app/git-init '-url=https://github.com/google/docsy-example.git' '-revision=' '-refspec=' '-path=/workspace/output/' '-sslVerify=true' '-submodules=true' '-depth=1' '-sparseCheckoutDirectories=' [fetch-source : clone] {"level":"info","ts":1654637310.4419358,"caller":"git/git.go:170","msg":"Successfully cloned https://github.com/google/docsy-example.git @ 1c7f7e300c90cd690ca5be66b43fe58713bb21c9 (grafted, HEAD) in path /workspace/output/"} [fetch-source : clone] {"level":"info","ts":1654637320.384655,"caller":"git/git.go:208","msg":"Successfully initialized and updated submodules in path /workspace/output/"} [fetch-source : clone] + cd /workspace/output/ [fetch-source : clone] + git rev-parse HEAD [fetch-source : clone] + RESULT_SHA=1c7f7e300c90cd690ca5be66b43fe58713bb21c9 [fetch-source : clone] + EXIT_CODE=0 [fetch-source : clone] + '[' 0 '!=' 0 ] [fetch-source : clone] + printf '%s' 1c7f7e300c90cd690ca5be66b43fe58713bb21c9 [fetch-source : clone] + printf '%s' https://github.com/google/docsy-example.git [build-push : build-and-push] WARN [build-push : build-and-push] User provided docker configuration exists at /kaniko/.docker/config.json [build-push : build-and-push] INFO Retrieving image manifest klakegg/hugo:ext-alpine [build-push : build-and-push] INFO Retrieving image klakegg/hugo:ext-alpine from registry index.docker.io [build-push : build-and-push] INFO Built cross stage deps: map[] [build-push : build-and-push] INFO Retrieving image manifest klakegg/hugo:ext-alpine [build-push : build-and-push] INFO Returning cached image manifest [build-push : build-and-push] INFO Executing 0 build triggers [build-push : build-and-push] INFO Unpacking rootfs as cmd RUN apk add git requires it. [build-push : build-and-push] INFO RUN apk add git [build-push : build-and-push] INFO Taking snapshot of full filesystem... [build-push : build-and-push] INFO cmd: /bin/sh [build-push : build-and-push] INFO args: [-c apk add git] [build-push : build-and-push] INFO Running: [/bin/sh -c apk add git] [build-push : build-and-push] fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz [build-push : build-and-push] fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz [build-push : build-and-push] OK: 76 MiB in 41 packages [build-push : build-and-push] INFO[0012] Taking snapshot of full filesystem... [build-push : build-and-push] INFO[0013] Pushing image to us-east1-docker.pkg.dev/tekton-tests/tektonstuff/docsy:v1 [build-push : build-and-push] INFO[0029] Pushed image to 1 destinations [build-push : write-url] us-east1-docker.pkg.dev/my-tekton-tests/tekton-samples/docsy:v1
Full code samples
The Pipeline:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-build-push
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and
pushes it to a registry
params:
- name: repo-url
type: string
- name: image-reference
type: string
workspaces:
- name: shared-data
- name: docker-credentials
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: build-push
runAfter: ["fetch-source"]
taskRef:
name: kaniko
workspaces:
- name: source
workspace: shared-data
- name: dockerconfig
workspace: docker-credentials
params:
- name: IMAGE
value: $(params.image-reference)
The PipelineRun:
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-build-push-run-
spec:
pipelineRef:
name: clone-build-push
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- name: docker-credentials
secret:
secretName: docker-credentials
params:
- name: repo-url
value: https://github.com/google/docsy-example.git
- name: image-reference
value: container.registry.com/sublocation/my_app:version
The Docker credentials Kubernetes Secret:
apiVersion: v1
kind: Secret
metadata:
name: docker-credentials
data:
config.json: efuJAmF1...
Use your credentials as the value of the data
field. Check the registry
authentication section for more
information.
Further reading
Feedback
Was this page helpful?
Thanks! Tell us how we can further improve.
Sorry about that. Tell us how we can further improve.