Ingress — это ресурс Kubernetes, позволяющий организовать доступ к сервисам внутри кластера через HTTP и HTTPS. Он предоставляет маршрутизацию на основе URL, доменов и других параметров. В этой статье рассмотрим использование Nginx Ingress на примере трех деплойментов Nginx, имитирующих три разных сервиса. Мы также настроим SSL-сертификат для защиты соединения.
Для начала необходимо установить Nginx Ingress в кластере. В панели управления кластером перейдите во вкладку «Дополнения», нажмите на три точки рядом с Nginx Ingress и выберите «Установить».
После установки проверьте, что Ingress работает корректно. Выполните команду:
kubectl get pods -n ingress-nginx
Убедитесь, что все поды находятся в статусе Running
.
Для удобства создадим отдельный неймспейс, в котором будут находиться все манифесты:
kubectl create namespace ingress-example
Мы развернем три Deployment
с образами Nginx, каждый будет имитировать отдельный сервис. К каждому Deployment
мы создадим Service
с типом ClusterIP
— это служебный тип сервиса в Kubernetes, который выдает внутренний IP-адрес внутри кластера. Такой сервис не доступен извне напрямую, однако он может быть подцеплен к Ingress для публикации во внешнюю сеть.
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
Пояснения к манифесту:
Deployment
replicas: 2 указывает, что будет запущено две реплики подов с Nginx.
В секции selector и template.metadata.labels задаётся соответствие между подами и тем, как их будет находить сервис.
volumeMounts и volumes используются, чтобы подмонтировать файл service1.html
из ConfigMap
в директорию, откуда Nginx по умолчанию раздает контент.
Service
ClusterIP означает, что сервис будет доступен только внутри кластера по выделенному IP-адресу. Для внешнего доступа мы будем использовать 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
Чтобы отличать наши сервисы друг от друга, создадим ConfigMap
с тремя разными HTML-страницами.
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>
И применим манифесты:
kubectl apply -f configmap.yaml
kubectl apply -f service1-deployment.yaml
kubectl apply -f service2-deployment.yaml
kubectl apply -f service3-deployment.yaml
Проверим статус подов:
kubectl get pods -n ingress-example
Все поды должны иметь статус Running
. На этом подготовительные работы можно считать завершенными.
С помощью Ingress мы укажем, какой трафик (по доменам и путям) перенаправлять на соответствующие сервисы. Создадим манифест ingress.yaml
:
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
Пояснения к манифесту:
rules.host задает домен, к которому будет привязан Ingress.
paths определяет правила маршрутизации:
При обращении к ingress1.example.com/service1
будет перенаправление на service1
.
При обращении к ingress1.example.com/service2
будет перенаправление на service2
.
При обращении к ingress2.example.com/
будет перенаправление на service3
.
Применим манифест:
kubectl apply -f ingress.yaml
Чтобы обратиться к Nginx Ingress из внешней сети, создадим Service
типа LoadBalancer
, который будет отвечать за балансировку нагрузки и предоставит нам внешний IP-адрес. Подготовим для этого манифест loadbalancer.yaml
следующего содержания:
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
Применим манифест:
kubectl apply -f loadbalancer.yaml
Дождитесь, пока балансировщик создастся, и убедитесь, что у него появился внешний IP-адрес:
kubectl get services -n ingress-nginx
Внешний IP будет отображен в колонке EXTERNAL-IP
.
Полученный IP-адрес необходимо прописать в DNS-настройках домена в виде А-записей для доменов ingress1.example.com
и ingress2.example.com
. После обновления DNS ваши домены будут указывать на этот балансировщик, и вы сможете обращаться к сервисам по внешним URL:
http://ingress1.example.com/service1
— отобразится заголовок «Welcome to Service 1!».http://ingress1.example.com/service2
— отобразится заголовок «Welcome to Service 2!».http://ingress2.example.com/
— отобразится заголовок «Welcome to Service 3!».Для обеспечения защищенного соединения в Nginx Ingress необходимо добавить существующий SSL-сертификат в виде Kubernetes-секрета, а затем указать этот секрет в манифесте Ingress.
Если вы хотите автоматизировать выпуск и продление сертификатов (например, через Let’s Encrypt), рекомендуем использовать инструмент cert-manager.
Сохраните файл ключа tls.key
и сертификат tls.crt
локально. Если вы заказывали сертификат в Timeweb Cloud, содержимое ключа и сертификата можно скопировать со страницы управления сертификатом в панели Timeweb Cloud. Убедитесь, что сертификат не просрочен и соответствует доменам, которые вы хотите защитить.
Чтобы добавить сертификат в кластер, необходимо закодировать файлы в Base64 и создать манифест секрета. Выполните в терминале команды:
base64 -w 0 ./tls.crt
base64 -w 0 ./tls.key
Затем создайте файл tls-secret.yaml
следующего содержания:
apiVersion: v1
kind: Secret
metadata:
name: ingress-example-tls
namespace: ingress-example
type: kubernetes.io/tls
data:
tls.crt: |-
<BASE64_ЗАКОДИРОВАННЫЙ_СЕРТИФИКАТ>
tls.key: |-
<BASE64_ЗАКОДИРОВАННЫЙ_КЛЮЧ>
Сохраните файл и примените манифест:
kubectl apply -f tls-secret.yaml
Проверьте, что значения ключа и сертификата ненулевые. Для этого выполните:
kubectl describe secret ingress-example-tls -n ingress-example
Обновите ваш манифест ingress.yaml
, добавив секцию tls
, и укажите имя созданного секрета:
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
Примените измененный манифест:
kubectl apply -f ingress.yaml
Теперь при обращении к ingress1.example.com
или ingress2.example.com
по HTTPS браузер будет использовать сертификат, указанный в секрете ingress-example-tls
. Таким образом, трафик к вашим сервисам будет защищен.
Если у вас несколько сертификатов для разных доменов, создайте Secret
для каждого из них. Например, для доменов example.com
и example.org
создайте два секрета.
После этого обновите манифест Ingress, добавив секцию tls
для каждого домена:
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
- hosts:
- example.org
secretName: example-org-tls
После этого каждый домен будет использовать свой сертификат, указанный в соответствующем секрете.