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.
First, Nginx Ingress needs to be installed in the cluster. In the cluster management panel, go to the Addons tab, click on the three dots next to Nginx Ingress, and select Install.
After installation, verify that Ingress is functioning correctly by running the command:
kubectl get pods -n ingress-nginx
Ensure that all pods have the Running status.
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-example
To 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: ClusterIP
Manifest explanation:
Deployment
replicas: 2 specifies that two replicas of Nginx pods will be running.selector and template.metadata.labels section defines how the service will locate the pods.volumeMounts and volumes are used to mount the service1.html file from a ConfigMap into the directory from which Nginx serves content by default.Service
ClusterIP means 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: ClusterIP
service3-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: ClusterIP
Apply the maniests:
kubectl apply -f configmap.yaml
kubectl apply -f service1-deployment.yaml
kubectl apply -f service2-deployment.yaml
kubectl apply -f service3-deployment.yaml
Check the pods statuses:
kubectl get pods -n ingress-example
All pods should have the Running status.
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: 80
Manifest explanation:
rules.host specifies the domain to which Ingress will be bound.paths defines the routing rules:ingress1.example.com/service1 will be redirected to service1.ingress1.example.com/service2 will be redirected to service2.ingress2.example.com/ will be redirected to service3.Apply the manifest:
kubectl apply -f ingress.yaml
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: LoadBalancer
Apply the manifest:
kubectl apply -f loadbalancer.yaml
Wait until the load balancer is created and verify that it has an external IP address:
kubectl get services -n ingress-nginx
The 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!".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.
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.
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.key
Then, 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.yaml
Verify that the key and certificate values are not empty by running:
kubectl describe secret ingress-example-tls -n ingress-example
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: 80
Apply the updated manifest:
kubectl apply -f ingress.yaml
Now, 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-tls
Each domain will then use its respective certificate as specified in the corresponding secret.