NGINX Ingress
Ingress is a Kubernetes resource that enables access to services within a cluster via HTTP and HTTPS. It provides routing based on URLs, domains, and other parameters. This article explores the use of Nginx Ingress with three Nginx deployments simulating three different services. We will also configure an SSL certificate to secure the connection.
Installing Nginx Ingress Copy link
First, Nginx Ingress needs to be installed in the cluster.
- Go to the Kuberenetes section and click on the cluster.
- In the Addons tab, click on the three dots next to Nginx Ingress.
- Select Install.
After installation, verify that Ingress is functioning correctly by running the command:
kubectl get pods -n ingress-nginxEnsure that all pods have the Running status.
Configuring Deployments and Services Copy link
Let’s consider an example of using NGINX Ingress. We will deploy three Deployments based on Nginx images, each simulating a separate service. For each Deployment, we will create a Service of type ClusterIP—the default service type in Kubernetes—which provides an internal IP address within the cluster. This type of service is not directly accessible from outside the cluster; however, it can be exposed to external traffic using an Ingress.
For convenience, we will create a separate namespace that will contain all the manifests:
kubectl create namespace ingress-exampleTo distinguish the services from each other, we will create a ConfigMap containing three different HTML pages. Create a file named configmap.yaml with the following content:
apiVersion: v1
kind: ConfigMap
metadata:
name: service-config
namespace: ingress-example
data:
service1.html: |
<html>
<head><title>Service 1</title></head>
<body><h1>Welcome to Service 1!</h1></body>
</html>
service2.html: |
<html>
<head><title>Service 2</title></head>
<body><h1>Welcome to Service 2!</h1></body>
</html>
service3.html: |
<html>
<head><title>Service 3</title></head>
<body><h1>Welcome to Service 3!</h1></body>
</html>Next, we will define the Deployments.
service1-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service1
namespace: ingress-example
spec:
replicas: 2
selector:
matchLabels:
app: service1
template:
metadata:
labels:
app: service1
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html
volumes:
- name: config-volume
configMap:
name: service-config
items:
- key: service1.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: service1
namespace: ingress-example
spec:
selector:
app: service1
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIPManifest explanation:
Deploymentreplicas:2specifies that two replicas of Nginx pods will be running.- The
selectorandtemplate.metadata.labelssection defines how the service will locate the pods. volumeMountsandvolumesare used to mount theservice1.htmlfile from aConfigMapinto the directory from which Nginx serves content by default.
ServiceClusterIPmeans the service will be accessible only within the cluster via an assigned IP address. For external access, we will use Ingress.
The manifests for service2 and service3 are similar, differing only in the service name and the HTML file used.
service2-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service2
namespace: ingress-example
spec:
replicas: 2
selector:
matchLabels:
app: service2
template:
metadata:
labels:
app: service2
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html
volumes:
- name: config-volume
configMap:
name: service-config
items:
- key: service2.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: service2
namespace: ingress-example
spec:
selector:
app: service2
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIPservice3-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service3
namespace: ingress-example
spec:
replicas: 2
selector:
matchLabels:
app: service3
template:
metadata:
labels:
app: service3
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html
volumes:
- name: config-volume
configMap:
name: service-config
items:
- key: service3.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: service3
namespace: ingress-example
spec:
selector:
app: service3
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIPApply the maniests:
kubectl apply -f configmap.yaml
kubectl apply -f service1-deployment.yaml
kubectl apply -f service2-deployment.yaml
kubectl apply -f service3-deployment.yamlCheck the pods statuses:
kubectl get pods -n ingress-exampleAll pods should have the Running status.
Creating Ingress Copy link
With Ingress, we will define which traffic (based on domains and paths) should be redirected to the corresponding services. We will create the ingress.yaml manifest.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: ingress-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: ingress1.example.com
http:
paths:
- path: /service1
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- path: /service2
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
- host: ingress2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service3
port:
number: 80Manifest explanation:
rules.hostspecifies the domain to which Ingress will be bound.pathsdefines the routing rules:
- Requests to
ingress1.example.com/service1will be redirected toservice1. - Requests to
ingress1.example.com/service2will be redirected toservice2. - Requests to
ingress2.example.com/will be redirected toservice3.
- Requests to
Apply the manifest:
kubectl apply -f ingress.yamlCreating a LoadBalancer Copy link
To access Nginx Ingress from an external network, we will create a Service of type LoadBalancer, which will handle load balancing and provide an external IP address. We will prepare the loadbalancer.yaml manifest for this.
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
selector:
app.kubernetes.io/name: ingress-nginx
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
type: LoadBalancerApply the manifest:
kubectl apply -f loadbalancer.yamlWait until the load balancer is created and verify that it has an external IP address:
kubectl get services -n ingress-nginxThe external IP will be displayed in the EXTERNAL-IP column.
Add the external IP to the domain’s DNS settings as A records for the domains ingress1.example.com and ingress2.example.com. Once the DNS updates, your domains will point to this load balancer, and you will be able to access the services via external URLs:
http://ingress1.example.com/service1— will display the header "Welcome to Service 1!".http://ingress1.example.com/service2— will display the header "Welcome to Service 2!".http://ingress2.example.com/— will display the header "Welcome to Service 3!".
Configuring an SSL Certificate Copy link
To ensure a secure connection in Nginx Ingress, you need to add an existing SSL certificate as a Kubernetes Secret and specify this secret in the Ingress manifest.
If you want to automate certificate issuance and renewal (e.g., using Let’s Encrypt), use cert-manager.
Preparing Certificate and Key Files Copy link
Save the tls.key (private key) and tls.crt (certificate) files locally. Ensure that the certificate is not expired and matches the domains you want to secure.
Creating a Kubernetes Secret Copy link
To add the certificate to the cluster, encode the files in Base64 and create a Secret manifest. Run the following commands in the terminal:
base64 -w 0 ./tls.crt
base64 -w 0 ./tls.keyThen, create the tls-secret.yaml file with the following content:
apiVersion: v1
kind: Secret
metadata:
name: ingress-example-tls
namespace: ingress-example
type: kubernetes.io/tls
data:
tls.crt: |-
<BASE64_ENCODED_CERTIFICATE>
tls.key: |-
<BASE64_ENCODED_KEY>
Save the file and apply the manifest:
kubectl apply -f tls-secret.yamlVerify that the key and certificate values are not empty by running:
kubectl describe secret ingress-example-tls -n ingress-exampleUpdating the Ingress Manifest Copy link
Update your ingress.yaml manifest by adding the tls section and specifying the created secret.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: ingress-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- ingress1.example.com
- ingress2.example.com
secretName: ingress-example-tls
rules:
- host: ingress1.example.com
http:
paths:
- path: /service1
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- path: /service2
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
- host: ingress2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service3
port:
number: 80Apply the updated manifest:
kubectl apply -f ingress.yamlNow, when accessing ingress1.example.com or ingress2.example.com over HTTPS, the browser will use the certificate stored in the ingress-example-tls secret. This ensures that traffic to your services is secured.
If you have multiple certificates for different domains, create a Secret for each of them. For example, for example.com and example.org, create two separate secrets.
Then, update the Ingress manifest by adding a tls section for each domain.
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
- hosts:
- example.org
secretName: example-org-tlsEach domain will then use its respective certificate as specified in the corresponding secret.