Let's walk through how to setup a k8 cluster on digitalocean with knative.

Digital Ocean

Start the cluster

Installing and configure the doctl tool. Then setup a cluster:

1
2
3
  doctl kubernetes cluster create gratitude \
      --auto-upgrade \
      "--node-pool=name=default;min-nodes=1;max-nodes=10;size=s-4vcpu-8gb;auto-scale=true"

Once that's in place, make sure that you have a domain, in my case gitgratitude.com:

1
  doctl compute domain create gitgratitude.com

Installing knative

We are going to use the knative operator to setup the install. For this post, we will only being using serving.

Operator

1
kubectl apply -f https://github.com/knative/operator/releases/download/knative-v1.0.0/operator.yaml

Check status:

1
kubectl get deployment knative-operator
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
knative-operator   1/1     1            1           24h

Serving

We will now tell the operator to deploy knative serving, and we will use kourier, and set our domain to gitgratitude.com:

serving.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  apiVersion: v1
  kind: Namespace
  metadata:
    name: knative-serving
  ---
  apiVersion: operator.knative.dev/v1alpha1
  kind: KnativeServing
  metadata:
    name: knative-serving
    namespace: knative-serving
  spec:
    ingress:
      kourier:
        enabled: true
    config:
      network:
        ingress.class: "kourier.ingress.networking.knative.dev"
      domain:
        gitgratitude.com: ""
1
  kubectl apply -f serving.yaml
namespace/knative-serving configured
knativeserving.operator.knative.dev/knative-serving configured

And to see what the status of the deployment is:

1
kubectl get deployment -n knative-serving

Add default domain

Lets add the default domain serving as well.

1
  kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.0.0/serving-default-domain.yaml
job.batch/default-domain created
service/default-domain-service created

Add the certmanager-controller:

This tells knative to use the certmanager when services get created/deleted:

1
  kubectl apply --filename https://github.com/knative/net-certmanager/releases/download/knative-v1.0.0/release.yaml

Set the cert-manager config map

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  apiVersion: v1
  kind: ConfigMap
  metadata:
    name: config-certmanager
    namespace: knative-serving
    labels:
      networking.knative.dev/certificate-provider: cert-manager
  data:
    issuerRef: |
      kind: ClusterIssuer
      name: letsencrypt-staging      
1
  kubectl apply -f cert-config.yaml
configmap/config-certmanager configured

Add revision garbage collection

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-gc
  namespace: knative-serving
data:
  max-non-active-revisions: "1"
  retain-since-create-time: "disabled"
  retain-since-last-active-time: "disabled"
1
  kubectl apply -f gc.yaml
configmap/config-gc configured

Install cert-manager

Install helm package

1
  helm repo add jetstack https://charts.jetstack.io
1
2
3
4
5
6
  helm upgrade --install \
       cert-manager jetstack/cert-manager \
       --namespace cert-manager \
       --create-namespace \
       --version v1.6.0 \
       --set installCRDs=true

Configure letencrypt

Create certs.yaml to define how we interact with let-encrypt. I'm going to use the http challenge here.

Also replace wschenk@gmail.com with your email address.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  apiVersion: cert-manager.io/v1
  kind: ClusterIssuer
  metadata:
    name: letsencrypt-staging
  spec:
    acme:
      # You must replace this email address with your own.
      # Let's Encrypt will use this to contact you about expiring
      # certificates, and issues related to your account.
      email: wschenk@gmail.com
      server: https://acme-staging-v02.api.letsencrypt.org/directory
      privateKeySecretRef:
        # Secret resource that will be used to store the account's private key.
        name: staging-issuer-account-key
      # Add a single challenge solver, HTTP01 using nginx
      solvers:
      - http01:
          ingress:
            class: istio #.ingress.networking.knative.dev
  ---
  apiVersion: cert-manager.io/v1
  kind: ClusterIssuer
  metadata:
    name: letsencrypt-prod
  spec:
    acme:
      # You must replace this email address with your own.
      # Let's Encrypt will use this to contact you about expiring
      # certificates, and issues related to your account.
      email: wschenk@gmail.com
      server: https://acme-v02.api.letsencrypt.org/directory
      privateKeySecretRef:
        # Secret resource that will be used to store the account's private key.
        name: prod-issuer-account-key
      # Add a single challenge solver, HTTP01 using nginx
      solvers:
      - http01:
          ingress:
            class: istio
            #.ingress.networking.knative.dev

Then apply it:

1
  kubectl apply -f certs.yaml

DNS

Set the domain

My domain is gitgratitude.com – you should use yours.

Check above where we setup knative-serving.

Turn on auto-tls and autocreate-cluster-domain-claims:

1
  kubectl patch configmap config-network --namespace knative-serving -p '{"data":{"auto-tls":"Enabled","autocreate-cluster-domain-claims":"true"}}'
configmap/config-network patched (no change)

DNS

Get the IP

1
  kubectl --namespace knative-serving get service kourier -o json| jq ".status.loadBalancer.ingress[0].ip"
"143.244.212.121"
1
  doctl compute domain records create gitgratitude.com --record-type A --record-data 143.244.212.121 --record-name default
ID           Type    Name       Data               Priority    Port    TTL     Weight
280306756    A       default    143.244.212.121    0           0       1800    0

Then setup a wildcard CNAME to point to the root.

1
  doctl compute domain records create gitgratitude.com --record-type CNAME --record-data default\. --record-name \*.default
ID           Type     Name         Data                        Priority    Port    TTL     Weight
280306923    CNAME    *.default    default.gitgratitude.com    0           0       1800    0

Testing out a simple service

1
  kn service create helloworld-go --image gcr.io/knative-samples/helloworld-go
Creating service 'helloworld-go' in namespace 'default':

  0.036s The Route is still working to reflect the latest desired specification.
  0.064s Configuration "helloworld-go" is waiting for a Revision to become ready.
  0.099s ...
 17.273s ...
 17.343s Ingress has not yet been reconciled.
 17.416s Waiting for load balancer to be ready
 17.628s Ready to serve.

Service 'helloworld-go' created to latest revision 'helloworld-go-00001' is available at URL:
http://helloworld-go.default.gitgratitude.com

And you should be able to hit your function now.

1
curl -k http://helloworld-go.default.gitgratitude.com
Hello GitHub!

Look to see if a tls endpoint has been added

1
kn service ls
NAME            URL                                              LATEST                AGE    CONDITIONS   READY   REASON
helloworld-go   https://helloworld-go.default.gitgratitude.com   helloworld-go-00001   114s   3 OK / 3     True    

Look at the certificates

1
kubectl get certificates
NAME                                         READY   SECRET                                       AGE
route-7bbf3267-6eb1-4516-bbb8-e65d81e0b968   True    route-7bbf3267-6eb1-4516-bbb8-e65d81e0b968   62s
1
2
  curl --insecure -vvI https://helloworld-go.default.gitgratitude.com 2>&1 | \
      awk 'BEGIN { cert=0 } /^\* SSL connection/ { cert=1 } /^\*/ { if (cert) print }'
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=helloworld-go.default.gitgratitude.com
*  start date: Dec  7 10:28:31 2021 GMT
*  expire date: Mar  7 10:28:30 2022 GMT
*  issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Artificial Apricot R3
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x120012a00)
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
* Connection #0 to host helloworld-go.default.gitgratitude.com left intact

Previously

K8 Dashboard on Docker Desktop what’s going on

2021-11-28

Next

Serving a knative function on the root root to services

2021-12-01

howto

Previously

K8 Dashboard on Docker Desktop what’s going on

2021-11-28

Next

Serving a knative function on the root root to services

2021-12-01