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.