Exercise
In this exercise, you will install an Nginx-based Ingress Controller and configure it to serve the country.dev domain over HTTPS.
Prerequisites
Ensure you have installed the nginx Ingress Controller as detailed in the previous exercise.
Test Application
Copy the following specification into the country.yaml file. This specification defines a Pod running a simple Python application that returns a random country (on a GET /random request), and a ClusterIP type service to expose this Pod.
apiVersion: v1
kind: Pod
metadata:
labels:
app: country
name: country
spec:
containers:
- image: lucj/country:1.0
name: country
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: country
spec:
ports:
- port: 80
targetPort: 5000
selector:
app: country
Create the Pod and corresponding Service:
kubectl apply -f country.yaml
Certificate and Private Key
Use the following command to create a private key and a self-signed certificate for the domain name country.dev
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.crt -subj "/CN=country.dev"
:warning: if you’re using Git-Bash, use the following command to generate the certificate and private key (double // in the -subj definition)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.crt -subj "//CN=country.dev"
Then create a tls type secret containing the certificate and private key created previously.
kubectl create secret tls country-certs --cert=./cert.crt --key=./cert.key
Ingress Controller Configuration
You will now create the Ingress resource that will configure the Ingress Controller to act as a TLS termination for the country.dev domain.
Copy the following specification into the ingress.yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: country
spec:
ingressClassName: nginx
tls:
- hosts:
- country.dev
secretName: country-certs
rules:
- host: "country.dev"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: country
port:
number: 80
then create the resource:
kubectl apply -f ingress.yaml
The tls section of this specification indicates that the certificates needed for the domain name country.dev are found in the country-certs secret created previously.
Testing
There are 2 scenarios:
- 1st case: if the Ingress Controller is exposed with a LoadBalancer type service, as in the case below:
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.106.237.119 194.182.170.229 80:30810/TCP,443:31703/TCP 98s
ingress-nginx-controller-admission ClusterIP 10.96.179.17 <none> 443/TCP 98s
Modify your /etc/hosts file (C:\Windows\System32\drivers\etc\hosts on Windows) to add the mapping between the domain name and your Load Balancer’s IP address. In the previous example, you would need to add the following record to this file:
194.182.170.229 country.dev
Alternatively, you can use the following command to verify that you can access the application using the domain name country.dev directly, making sure to replace LOAD_BALANCER_IP with your Load Balancer’s IP (194.182.170.229 in the above example).
Note: the –resolve option handles the name resolution of country.dev
curl -k --resolve country.dev:443:LOAD_BALANCER_IP https://country.dev/random
You should get a result similar to the following:
{"alpha_2":"LA","alpha_3":"LAO","name":"Lao People's Democratic Republic","numeric":"418"}
- 2nd case: if the Ingress Controller is exposed with a NodePort type service, as in the case below:
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller-admission ClusterIP 10.43.139.141 <none> 443/TCP 5m14s
ingress-nginx-controller NodePort 10.43.106.85 <none> 80:30846/TCP,443:32615/TCP 5m14s
Use the following command after replacing:
- NODE-PORT with the port exposing port 443 externally (32615 in this example)
- NODE_IP with the IP address of one of your cluster nodes (which you can get with the command
kubectl get no -o wide
)
curl -k --resolve country.dev:NODE-PORT:NODE_IP https://country.dev:NODE_PORT/random
You should get a result similar to the following:
{"alpha_2":"SA","alpha_3":"SAU","name":"Saudi Arabia","numeric":"682"}
The application is now exposed over TLS. In a real world scenario we usually rely on an external component, like Cert-Manager to handle the certificate issuance and renewal for us.