Skip to main content

Use an Ingress Controller

Deploy the NGINX Ingress Controller

Check documentation

Add a Helm chart repository with the Ingress NGINX:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

Install the NGINX Ingress Controller:

helm install --create-namespace --namespace ingress-nginx ingress-nginx ingress-nginx/ingress-nginx

Update the NGINX Ingress Controller with hostNetwork true:

helm upgrade -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx --set controller.hostNetwork=true

Verify the Ingress NGINX installation:

kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
helm list -n ingress-nginx

Check the installed version of NGINX Ingress:

POD_NAME=$(kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n ingress-nginx -it $POD_NAME -- /nginx-ingress-controller --version

Output should be similar to:

-------------------------------------------------------------------------------
NGINX Ingress controller
Release: v1.5.1
Build: d003aae913cc25f375deb74f898c7f3c65c06f05
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.21.6

-------------------------------------------------------------------------------

Deploy a hello-world app

Create a new Namespace:

kubectl create namespace webapp

Create a Deployment using the following command:

kubectl create deployment -n webapp hello-world --image=gcr.io/google-samples/hello-app:1.0 --replicas=3
See created Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: hello-world
name: hello-world
namespace: webapp
spec:
replicas: 3
selector:
matchLabels:
app: hello-world
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: hello-world
spec:
containers:
- image: gcr.io/google-samples/hello-app:1.0
name: hello-app
resources: {}
status: {}

Expose the Deployment:

kubectl expose deployment -n webapp hello-world --type=ClusterIP --port=8080
See created Service
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: hello-world
name: hello-world
namespace: webapp
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: hello-world
type: ClusterIP
status:
loadBalancer: {}

Verify if the Service is created and is available on a node port:

kubectl get service -n webapp hello-world

Output:

NAME      TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
web ClusterIP 10.104.133.249 <none> 8080/TCP 12m

Create an Ingress resource:

The following file is an Ingress resource that sends traffic to your Service via hello-world.nc.

Create the ingress-hello.yaml from the following file:

ingress-hello.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-hello
namespace: webapp
spec:
ingressClassName: "nginx"
rules:
- host: hello-world.nc
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-world
port:
number: 8080

Create the Ingress resource by running the following command:

kubectl apply -f ingress-hello.yaml

Verify on which node Ingress-Nginx is running:

kubectl get pods -n ingress-nginx -o wide

Use the worker IP, then set /etc/hosts.

Add the following line to the bottom of the /etc/hosts file.

note

The IP address displayed within the ingress list will be the internal IP.

IP_ADDRESS hello-world.nc
sudo bash -c 'echo "IP_ADDRESS hello-world.nc" >> /etc/hosts'

Check if the Ingress controller is directing traffic:

curl http://hello-world.nc

or

curl --header 'Host: hello-world.nc' http://IP_ADDRESS

Output:

Hello, world!
Version: 1.0.0
Hostname: hello-world-55b8c6998d-8k564

Create a second Deployment

Create a second Deployment using the following command:

kubectl create deployment -n webapp hello-world2 --image=gcr.io/google-samples/hello-app:2.0
See created Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: hello-world2
name: hello-world2
namespace: webapp
spec:
replicas: 1
selector:
matchLabels:
app: hello-world2
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: hello-world2
spec:
containers:
- image: gcr.io/google-samples/hello-app:2.0
name: hello-app
resources: {}
status: {}

Expose the Deployment:

kubectl expose deployment -n webapp hello-world2 --port=8080 --type=ClusterIP
See created Service
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: hello-world2
name: hello-world2
namespace: webapp
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: hello-world2
type: ClusterIP
status:
loadBalancer: {}

Edit the existing ingress-hello.yaml and add the following lines:

      - path: /v2
pathType: Prefix
backend:
service:
name: hello-world2
port:
number: 8080
See finall Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-hello
namespace: webapp
spec:
ingressClassName: "nginx"
rules:
- host: hello-world.nc
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-world
port:
number: 8080
- path: /v2
pathType: Prefix
backend:
service:
name: hello-world2
port:
number: 8080

Apply the changes:

kubectl apply -f ingress-hello.yaml

Test your Ingress by accessing the 1st version of the Hello World app.

curl http://hello-world.nc

Output:

Hello, world!
Version: 1.0.0
Hostname: hello-world-55b8c6998d-8k564

Access the 2nd version of the Hello World app.

curl http://hello-world.nc/v2

Output:

Hello, world!
Version: 2.0.0
Hostname: hello-world2-75cd47646f-t8cjk

Install and use Certificate Manager

To secure HTTP connection to the Ingress Controller we can use an additional extension, which is Certficate Manager

Add a Helm chart repository with the Certificate Manager:

helm repo add jetstack https://charts.jetstack.io
helm repo update

Check available versions of Certificate Manager:

helm search repo jetstack/cert-manager -l

Install the Certificate Manager:

helm install --create-namespace --namespace cert-manager cert-manager jetstack/cert-manager  \
--version v1.12.6 --set installCRDs=true

Verify the Certificate Manager installation:

helm list -n cert-manager
helm status -n cert-manager cert-manager
helm history -n cert-manager cert-manager

Check if the Certificate Manager pods are running:

kubectl get pods -n cert-manager

Create Certificate Issuers for the WebApp application:

We'll set up two issuers for Let's Encrypt in this example: staging and production.

The Let's Encrypt production issuer has very strict rate limits. When you're experimenting and learning, it can be very easy to hit those limits. Because of that risk, we'll start with the Let's Encrypt staging issuer, and once we're happy that it's working we'll switch to the production issuer.

note

You'll see a warning about untrusted certificates from the staging issuer, but that's totally expected.

Create this definition locally and update the email address to your own. This email is required by Let's Encrypt and used to notify you of certificate expiration and updates.

To learn more

To learn more about it, go to official Certificate Manager documentation

issuer-staging.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: example@your_domain.com
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
class: nginx
issuer-production.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: example@your_domain.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx

Apply Issuer manifests onto Kubernetes:

kubectl apply -f issuer-staging.yaml
kubectl apply -f issuer-production.yaml

Both of these issuers are configured to use the HTTP01 challenge provider.

Check on the status of the clusterissuer after you create it:

kubectl describe -n webapp clusterissuer letsencrypt-staging

Now we can tell Ingress NGINX to use Certificate Manager Issuer to secure communication:

ingress-hello.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-hello
namespace: webapp
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging
spec:
ingressClassName: "nginx"
rules:
- host: web<LAB_ID>.go4clouds.net
http:
paths:
- path: /
...

tls:
- hosts:
- web<LAB_ID>.go4clouds.net
secretName: web-go4clouds-net-tls

Apply changes to Kubernetes with Ingress:

kubectl apply -f ingress-hello.yaml

Now, you should be able to open the website https://web<LAB_ID>.go4clouds.net in your web browser.

Clean up:

kubectl delete ns webapp