Skip to content

Tutorial

Stack we install in this tutorial

  • KinD (kubernetes in docker)
  • nginx-ingress-controller (for remote access)
  • cert-manager (automatic SSL)

PreReq

Optional: - k9s (brew install k9s)

add/update metallb and cert-manager helm repos

1
2
3
helm repo add metallb https://metallb.github.io/metallb
helm repo add jetstack https://charts.jetstack.io
helm repo update

Create the kind cluster

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
EOF

Grab your kube config

1
sudo kind get kubeconfig > ~/.kube/kubeconfig

MetalLb installation

Learn more about metallb here.

1
helm install metallb metallb/metallb -n kube-system --wait

Wait on metallb to deploy, because sometimes helm wait doesn't do the trick:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kubectl rollout status -n kube-system deployment/metallb-controller

kubectl wait --namespace kube-system \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/instance=metallb \
  --timeout=120s

kubectl wait --namespace kube-system \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=speaker \
  --timeout=120s

Now we can apply the metallb custom resources.... see: https://metallb.universe.tf/configuration/ Sometimes it still fails, but just keep trying, if you get an error for the custom resource not being available:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cat <<EOF | kubectl apply -f -
  apiVersion: metallb.io/v1beta1
  kind: IPAddressPool
  metadata:
    name: base-pool
    namespace: kube-system
  spec:
    addresses:
      - "$CIDR"
EOF

cat <<EOF | kubectl apply -f -
  apiVersion: metallb.io/v1beta1
  kind: L2Advertisement
  metadata:
    name: base-pool
    namespace: kube-system
EOF
    sleep 3
done

Deploy the Nginx Ingress Controller

Kind has a special deploy.yml maintained by the kuberentes project that makes this really easy:

1
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

Wait on nginx ingress controller to deploy:

1
2
kubectl rollout status deployment/ingress-nginx-controller -n ingress-nginx
kubectl wait --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=90s -n ingress-nginx

Set up cert manager

Don't forget the --set installCRDs=true!

1
2
3
4
helm install cert-manager jetstack/cert-manager \
    --namespace kube-system \
    --version v1.9.1 \
    --set installCRDs=true 

Wait on cert-manager to deploy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
kubectl rollout status -n kube-system deployment/cert-manager

kubectl rollout status -n kube-system deployment/cert-manager-webhook

kubectl wait --namespace kube-system \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/name=cert-manager \
  --timeout=90s

kubectl wait --namespace kube-system \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=webhook \
  --timeout=90s

You can also use k9s to monitor the cluster and wait for resources to come up.

Installing ClusterIssuer Resource

After cert-manager is completely up, you can apply this if you're going to test with external internet facing hosts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    cat <<EOF | kubectl apply -f -
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-staging
    spec:
      acme:
        email: $EMAIL
        server: https://acme-staging-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-staging
        solvers:
          - http01:
              ingress:
                class: nginx
EOF

That's it :)