Installing Contour on a Tanzu Community Edition cluster

Update 2022-10-21: After just one year in the wild VMware announced on Oct 21 2022 that they would no longer update or maintain the TCE project and that by end of 2022 the Github project will be removed. For more information check out my blog post here

Most of the things mentioned in this post (outside of installing TCE) should still be valid for other Kubernetes distributions

In an earlier post I installed MetalLB as a LoadBalancer service provider on a Tanzu Community Edition (TCE) cluster. A LoadBalancer is essential, but to be able to work with L7 and http we need to make use of the Ingress resource in Kubernetes. Ingress objects requires an Ingress Controller to work, and one of the most popular ones are Contour

To install Contour on TCE we will make use of the Tanzu package repository which makes it easy to deploy and manage software installed in the Kubernetes cluster. For clusters running on other platforms use the Contour documentation for installation instructions

For more information on Tanzu packages and how to get started with it on TCE check out the TCE documentation

Tanzu Package Repository

Add available packages

First, let's check out the cluster and then add the TCE package repo to the cluster with the tanzu cli

1tanzu package repository add tce-repo --url projects.registry.vmware.com/tce/main:0.9.1

TCE cluster and Tanzu package repo

To verify that the Package repo was added, and to check out which packages are available to us we run the following commands

List available packages

1tanzu package repository list
2tanzu package available list

Tanzu packages available

Verify that the Repository status is Reconcile succeeded, it migh take a few minutes.

Check the details of a package

Let's check the details of the Contour package

1tanzu package available get contour.community.tanzu.vmware.com

Contour package details

We can also list the available versions for the package

1tanzu package available list contour.community.tanzu.vmware.com

Contour versions

When installing a package we can instruct it to use a yaml file with configuration parameters used during the installation. To check which parameters we can use we'll pull it with the --values-schema flag

1tanzu package available get contour.community.tanzu.vmware.com/1.18.1 --values-schema

Contour package values schema

cert-manager

Before we proceed with the installation of Contour we'll take a quick look at cert-manager.

cert-manager is a piece of software that can serve certificates in our cluster which is good for securing the communication between services in our cluster. It can also integrate with other PKI providers (Like Hashicorp Vault, Let's Encrypt etc.), but that's something for a later post.

The installation of cert-manager is quite straightforward

1tanzu package available list cert-manager.community.tanzu.vmware.com
2tanzu package available get cert-manager.community.tanzu.vmware.com/1.5.3 --values-schema
3tanzu package install cert-manager --package-name cert-manager.community.tanzu.vmware.com --version 1.5.3

Cert manager installed

Deploy Contour package

To deploy Contour we'll use a pretty simple config. We'll configure it to use cert-manager, and we will tell Envoy to use a service type of LoadBalancer. Note that the structure of the settings when compared to the output we saw earlier is to split the settings by the "." and use the parent/child yaml syntax, i.e. envoy.service.type becomes

1envoy:
2  service:
3    type: <value>

The full config file used in my simple setup is the following

1certificates:
2  useCertManager: true
3envoy:
4  service:
5    type: LoadBalancer

Deploy Contour with values file

That's all there's to it.

We can also verify the deployment from the kubectl side of things

Contour resources with kubectl

Test Ingress

Now let's test the new Ingress capabilities available to us

We'll create a deployment with a nginx pod (like I normally do) and then expose it with a ClusterIP service type

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: nginx
 5  labels:
 6    app: my-web
 7spec:
 8  replicas: 1
 9  selector:
10    matchLabels:
11      app: my-web
12  template:
13    metadata:
14      labels:
15        app: my-web
16    spec:
17      containers:
18      - name: nginx
19        image: nginx
20        ports:
21        - containerPort: 80
1kubectl apply -f cont-deployment.yaml
2kubectl expose deployment nginx --type=ClusterIP --port=80

Deploy nginx

Now let's take a look at the definition for a simple Ingress to work with this

 1apiVersion: networking.k8s.io/v1
 2kind: Ingress
 3metadata:
 4  name: nginx-ingress
 5  labels:
 6    app: my-web
 7spec:
 8  defaultBackend:
 9    service:
10      name: nginx
11      port:
12        number: 80
1kubectl apply -f cont-ingress.yaml

Create Ingress

Normally we work with host names, but as the asterix reveals this accepts all requests to the IP

Test HTTP routing with HTTPProxy

Contour comes with a CRD, HTTPProxy, that let's us route based on the URL prefix which can come in handy. This is an evolution of the IngressRoute that existed in previous versions.

To do a simple test of this we'll have two nginx deployments running with different background color to make it nice and visual.

The first is the "blue" deployment

 1apiVersion: v1
 2kind: ConfigMap
 3metadata:
 4  name: nginx-index-b
 5data:
 6  index.html: |
 7    <html>
 8      <head><title>The BLUE page</title></head>
 9      <body style="background-color: blue">
10        <h1>Welcome</h1>
11        </br>
12        <h2>Hi! This is the BLUE page</h2>
13      </body>
14    </html>    
15---
16apiVersion: apps/v1
17kind: Deployment
18metadata:
19  name: nginx-deployment-b
20spec:
21  selector:
22    matchLabels:
23      app: nginx-b
24  replicas: 1
25  template:
26    metadata:
27      labels:
28        app: nginx-b
29    spec:
30      containers:
31      - name: nginx-b
32        image: nginx
33        ports:
34        - containerPort: 80
35        volumeMounts:
36            - name: nginx-index-file
37              mountPath: /usr/share/nginx/html/
38      volumes:
39      - name: nginx-index-file
40        configMap:
41          name: nginx-index-b

Deploy nginx BLUE

Then we'll do the same for the green deployment and we should have two deployments and two services running

Deployments and services

To test HTTPProxy we'll instruct Contour to send requests for the path /green to the "green" service and everything else to the "blue" service

 1apiVersion: projectcontour.io/v1
 2kind: HTTPProxy
 3metadata:
 4  name: nginx-http-proxy
 5  namespace: default
 6spec:
 7  virtualhost:
 8    fqdn: my-ingress-test.rhmlab.local
 9  routes:
10    - conditions:
11      - prefix: /
12      services:
13        - name: nginx-deployment-b
14          port: 80
15    - conditions:
16      - prefix: /green
17      pathRewritePolicy:
18        replacePrefix:
19        - replacement: /
20      services:
21        - name: nginx-deployment-g
22          port: 80

HTTPProxy created

Let's verify with a couple of curl requests

Test with curl

And in the browser

Test with browser

There's a lot more capabilities in HTTPProxy and Contour, check out the documentation for more examples

This page was modified on October 22, 2022: Added TCE retirement info