Setting Up Nginx Ingress, Letsencrypt in Kubernetes without LoadBalancers

Deploying services using Docker containers are all in the rage nowadays and Kubernetes provides a good way to manage them. Also, majority of the cloud providers have kubernetes as a service. So there's that too.

Before we begin

I assume that you have setup Kubernetes and have Kubectl configured on your local machine.
If not, i suggest you yo go and set those up before starting.
Now lets get started :D

via GIPHY

Installing Helm

What is helm and why do i need it?

  • Helm is a package manager for kubernetes.
  • Since we are going to install some services and their dependencies into the cluster, we need helm to make sure we can install them with simple set of commands.
  • Alternatively, you can install these packages without helm. Just go their respective github repos and find the yaml files and install them using kubectl apply

Spin up your terminal and fire up the following commands to install helm.

kubectl --namespace kube-system create sa tiller
# create a cluster role binding for tiller
kubectl create clusterrolebinding tiller \
   --clusterrole cluster-admin \
   --serviceaccount=kube-system:tiller
echo "initialize helm"
# initialized helm within the tiller service account
helm init --service-account tiller
# updates the repos for Helm repo integration
helm repo update
echo "verify helm"
# verify that helm is installed in the cluster
kubectl get deploy,svc tiller-deploy -n kube-system

Basically what the above commands does is as follows

  • Creates a service account called tiller in the namespace kube-system which is the system namespace that kubernetes creates after the cluster creation
  • Assigns the cluster-admin role to the namespace so that we can install other charts via helm without any problems
  • Install helm to the cluster.

Installing nginx ingress controller

Now that we've got helm setup and going, we need to install nginx ingress controller in the cluster using helm
To do this, we run

helm install stable/nginx-ingress \
    --namespace=kube-system \
    --name nginx-ingress \
    --set controller.kind=DaemonSet \
    --set controller.daemonset.useHostPort=true \
    --set controller.service.enabled=false

Basically what we are doing here is installing nginx with some specific settings so that it doesn't spin up loadbalancers during the actual creation of ingress.

  • You can read more about DaemonSets here
  • useHostPort basically tells the controller to use host network of the cluster nodes and allows us to access 80 and 443 ports from outside the cluster.

Installing certmanager

We need a way to issue certificates to the cluster and this is done by using certmanager.
Install it using helm by

helm install --name cert-manager --version v0.5.2 \
    --namespace kube-system stable/cert-manager

Now that we have installed certmanger, we need someone to issue the certificate for us, lets use LetsEncrypt for it.

Installing Letencrypt as certificate issuer

Open a text editor and enter the below

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: "<YOUR_EMAIL>"
    privateKeySecretRef:
      name: letsencrypt-staging
    http01: {}
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: "<YOUR_EMAIL>"
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

save the above file as lets_encrpyt.yml and then run kubectl apply -f lets_encrypt.yml

Run an ingress

Now that we have setup letsencrypt as cluster issuer, we need to setup an ingress to handle the incoming connections.
Open another editor and enter the following

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    certmanager.k8s.io/acme-http01-edit-in-place: "true"
    kubernetes.io/ingress.class: "nginx"
  name: custom-ingress-nginx
spec:
  rules:
    - host: <YOUR-HOSTNAME>
      http:
        paths:
          - path: /
            backend:
              serviceName: "<SERVICE-NAME>"
              servicePort: <SERVICE-PORT>
  tls:
    - secretName: test-eng-secret
      hosts:
        - <YOUR-HOSTNAME>
  • we specify the cluster issuer name in the annotation to issue us certificates. Use letsencrypt-staging to see if your setup is working and then use the production one.
  • And we specify the ingress class as nginx to use the nginx ingress controller.
  • the <SERVICE-NAME> and <SERVICE-PORT> are the names and ports in the NodePort services exposed above.

Thanks for reading and look forward to my future struggles.