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.
For convenience, create a separate namespace where all manifests will be located:
kubectl create namespace ingress-example
We will deploy three Deployments with Nginx images, each simulating a separate service. For each Deployment, we will create a Service of type ClusterIP—a service type in Kubernetes that assigns an internal IP address within the cluster. Such a service is not directly accessible from the outside but can be linked to Ingress for external exposure.
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.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
To differentiate our services, we will create a ConfigMap with three different HTML pages.
configmap.yaml:
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>
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.