Configuring a KinD cluster with nginx ingress and Tekton components

Configuring a KinD cluster with nginx ingress and Tekton components


5 min read

A bit of background

I have an interest in learning more about writing software, learning Golang, and contributing to open source. Over the last few weeks, from a suggestion by Marky Jackson, I've decided to get involved with Project Sigstore. In doing so, I've learned about Tekton, and have decided to include that in my learning toolkit. Tekton is comprised of a few major parts, one of which is the Dashboard. Since Tekton is cloud native, it runs entirely within a Kubernetes cluster. Many of the docs for Tekton and, if I'm not mistaken, Sigstore, mention the use of Kubernetes in Docker, also known as KinD. KinD was new to me, so I spent some time this week working to get it configured and ready for use. If you're not familiar with KinD, I included a link, but it's a means to running a Kubernetes cluster on your local machine by doing so inside of Docker. Docker can be installed on Linux, Mac, and Windows.

There may be other configurations supported by the tools mentioned here, but I have not explored them. If you are using Podman instead of Docker, I do believe KinD supports running clusters in there as well.

Areas of focus for this post

  • Installing and configuring KinD
  • Deploying Tekton:
    • Pipelines
    • Triggers
    • Dashboard
  • Installing and configuring ingress-nginx

Installing and Configuring KinD

I'm assuming you have Docker installed, if not please visit the Docker installation documentation here

I'm using my Mac at the moment, so to install with homebrew we execute:

brew install kind

You can see other installation instructions for Windows and Linux here

In order to install and make use of the ingress controller, we need to create a cluster using kind with a particular configuration. We will reference a YAML configuration that includes extraPortMappings that allows us to expose port 80 and 443. The below configuration is the one I used. The KinD documentation mentions if you're not using Linux to include the listenAddress value to send traffic from your machine to the node.

This creates a cluster called tekton-cluster. You can change the name to fit what you would like.

cat <<EOF | kind create cluster --name tekton-cluster --config=-
kind: Cluster
- role: control-plane
  - |
    kind: InitConfiguration
        node-labels: "ingress-ready=true"
  - containerPort: 80
    hostPort: 80
    protocol: TCP
    listenAddress: ""
  - containerPort: 443
    hostPort: 443
    protocol: TCP
    listenAddress: ""

After running the above, you should have output that looks like this:

Creating cluster "tekton-cluster" ...
 โœ“ Ensuring node image (kindest/node:v1.21.1) ๐Ÿ–ผ
 โœ“ Preparing nodes ๐Ÿ“ฆ
 โœ“ Writing configuration ๐Ÿ“œ
 โœ“ Starting control-plane ๐Ÿ•น๏ธ
 โœ“ Installing CNI ๐Ÿ”Œ
 โœ“ Installing StorageClass ๐Ÿ’พ
Set kubectl context to "kind-tekton-cluster"
You can now use your cluster with:

kubectl cluster-info --context kind-tekton-cluster

Have a nice day! ๐Ÿ‘‹

kind - config docs

kind - ingress docs

Deploying Tekton

Deploying the Tekton components is pretty straight forward, we're just going to run the following commands. Now, I'm using Tekton because it's what I am currently working on, but you can follow along with a different application or even a demo app.

Install Tekton Pipelines

kubectl apply \

Install Tekton Triggers

kubectl apply \

I did run into an issue when running this config where I got a connection refused error during install. I reran the command a couple times and it eventually was successful. I haven't dug in here, but wanted to note if you see the same thing.

Install Tekton Dashboard

kubectl apply \

All three of these should now be successfully installed. If we run kubectl -n tekton-pipelines get all we should see the resources that were created.

kubectl -n tekton-pipelines get all
NAME                                              READY   STATUS    RESTARTS   AGE
pod/tekton-dashboard-5d44ff59bd-ps9fq             1/1     Running   0          40s
pod/tekton-pipelines-controller-956886f78-2kds9   1/1     Running   0          3m37s
pod/tekton-pipelines-webhook-6c6446886c-hjghs     1/1     Running   0          3m37s
pod/tekton-triggers-controller-7455cbc998-t2fkx   1/1     Running   3          3m26s
pod/tekton-triggers-webhook-86b7dd88c6-jt4lz      1/1     Running   3          3m26s

NAME                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                              AGE
service/tekton-dashboard              ClusterIP     <none>        9097/TCP                             40s
service/tekton-pipelines-controller   ClusterIP    <none>        9090/TCP,8008/TCP,8080/TCP           3m37s
service/tekton-pipelines-webhook      ClusterIP    <none>        9090/TCP,8008/TCP,443/TCP,8080/TCP   3m37s
service/tekton-triggers-controller    ClusterIP    <none>        9000/TCP                             3m26s
service/tekton-triggers-webhook       ClusterIP   <none>        443/TCP                              3m26s

NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tekton-dashboard              1/1     1            1           40s
deployment.apps/tekton-pipelines-controller   1/1     1            1           3m37s
deployment.apps/tekton-pipelines-webhook      1/1     1            1           3m37s
deployment.apps/tekton-triggers-controller    1/1     1            1           3m26s
deployment.apps/tekton-triggers-webhook       1/1     1            1           3m26s

NAME                                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/tekton-dashboard-5d44ff59bd             1         1         1       40s
replicaset.apps/tekton-pipelines-controller-956886f78   1         1         1       3m37s
replicaset.apps/tekton-pipelines-webhook-6c6446886c     1         1         1       3m37s
replicaset.apps/tekton-triggers-controller-7455cbc998   1         1         1       3m26s
replicaset.apps/tekton-triggers-webhook-86b7dd88c6      1         1         1       3m26s

NAME                                                           REFERENCE                             TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook   Deployment/tekton-pipelines-webhook   <unknown>/100%   1         5         1          3m37s

Installing and configuring ingress-nginx

First, we are going to install the ingress-nginx controller:

kubectl apply --filename

Then, we are going to wait for it to become ready by running:

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \ \

When ready, you should see similar output:

pod/ingress-nginx-controller-674cb6ff57-zpxdb condition met

So, moving forward we are going to configure ingress. Before we do so, we're going to create a DNS name that allows us to access our application. I'm going to use a service called that enables DNS that points to the listening post of our node, in this case With my domain is This is very useful as you don't have to edit your /etc/config every time you want to test an app. I'm going to point to a subdomain of tekton for the following configuration, which combined, gives us This domain name will direct to my localhost.

Let's create a file called tekton-ingress.yml with the following contents:

kind: Ingress
  name: tekton-dashboard
  annotations: "false" "false"
  - http:
      - path: /
        pathType: Prefix
           name: tekton-dashboard
             number: 9097

Now we'll apply the config using the following:

kubectl -n tekton-pipelines apply -f tekton-ingress.yml

Which will output the following when successful: created

That's it!

We've configured the KinD cluster, installed Tekton components, and configured ingress. You can plug the domain name into your browser and access the Tekton Dashboard.

I hope this was helpful!