Настройка Nginx Ingress в Kubernetes с помощью Helm
Cloud Server | Комментировать запись
Kubernetes Ingress обеспечивает гибкий способ маршрутизации трафика от вашего кластера к внутренним сервисам Kubernetes. Ресурсы Ingress – это объекты Kubernetes, которые определяют правила маршрутизации трафика HTTP и HTTPS на сервисы. Чтобы они работали, нужен контроллер (Ingress Controller); его роль заключается в реализации правил при приеме трафика (скорее всего, через балансировщик нагрузки) и его направлении на соответствующие сервисы. Большинство контроллеров используют один глобальный балансировщик нагрузки для всех Ingress-ов, что более эффективно, чем создание индивидуального балансировщика для каждого сервиса.
Helm – менеджер пакетов для управления Kubernetes. Использование чартов Helm в Kubernetes предоставляет возможность настройки и управления жизненным циклом приложения Kubernetes (обновлениями, откатом и удалением).
В этом мануале мы настроим контроллер Nginx Ingress Controller, поддерживаемый Kubernetes, с помощью Helm. Затем мы создадим ресурс Ingress для маршрутизации трафика ваших доменов на тестовый бэкенд сервис Hello World. После настройки Ingress мы установим в кластер Cert-Manager, чтобы иметь возможность автоматически получать TLS сертификаты Let’s Encrypt для защиты Ingress-ов.
Требования
- Кластер Kubernetes с настроенным kubectl по умолчанию.
- Менеджер пакетов Helm на вашем локальном компьютере и Tiller в кластере. Для этого выполните шаги 1 и 2 мануала Установка программного обеспечения в кластер Kubernetes с помощью пакетного менеджера Helm.
- Два полностью зарегистрированных домена и записи А для них. В этом мануале будут использоваться условные домены hw1.example.com и hw2.example.com .
1: Настройка развертываний Hello World
В этом разделе перед развертыванием Nginx Ingress мы развернем простое приложение Hello World под названием hello-kubernetes, чтобы получить тестовые сервисы, на которые вы будете перенаправлять трафик. Чтобы в дальнейшем была возможность убедиться, что Nginx Ingress работает правильно, нужно развернуть его дважды с разными приветственными сообщениями, которые будут отображаться при доступе из браузера.
Хранить конфигурацию развертывания нужно на локальном компьютере. Первая конфигурация будет находиться в файле hello-kubernetes-first.yaml. Создайте его с помощью текстового редактора:
nano hello-kubernetes-first.yaml
Добавьте следующие строки:
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-first
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-first
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-first
template:
metadata:
labels:
app: hello-kubernetes-first
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.5
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: Hello from the first deployment!
Эта конфигурация определяет развертывание и сервис. Развертывание состоит из трех реплик образа paulbouwer/hello-kubernetes:1.5 и переменной среды MESSAGE – ее значение будет отображаться при доступе к приложению. Сервис здесь предоставляет доступ к кластеру развертывания по порту 80.
Сохраните и закройте файл.
Затем создайте этот первый вариант приложения hello-kubernetes в Kubernetes, выполнив следующую команду:
kubectl create -f hello-kubernetes-first.yaml
Вы увидите такой вывод:
service/hello-kubernetes-first created
deployment.apps/hello-kubernetes-first created
Чтобы проверить создание сервиса, выполните команду:
kubectl get service hello-kubernetes-first
Вывод будет выглядеть так:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-kubernetes-first ClusterIP 10.245.85.236 <none> 80:31623/TCP 35s
Вы увидите, что недавно созданному сервису присвоен ClusterIP, а это означает, что он работает правильно. Весь трафик, отправленный на него, будет перенаправлен на выбранное развертывание через порт 8080. Теперь, когда вы развернули первый вариант приложения hello-kubernetes, можно поработать над вторым.
Откройте файл hello-kubernetes-second.yaml в редакторе:
nano hello-kubernetes-second.yaml
Добавьте следующие строки:
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-second
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-second
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-second
template:
metadata:
labels:
app: hello-kubernetes-second
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.5
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: Hello from the second deployment!
Сохраните и закройте файл.
Этот вариант приложения имеет ту же структуру, что и предыдущая конфигурация; отличаются только имена развертываний и сервисов (чтобы избежать конфликтов) и текст сообщения.
Теперь создайте его в Kubernetes с помощью следующей команды:
kubectl create -f hello-kubernetes-second.yaml
Появится такой вывод:
service/hello-kubernetes-second created
deployment.apps/hello-kubernetes-second created
Убедитесь, что второй сервис запущен и работает:
kubectl get service
Вывод будет примерно таким:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-kubernetes-first ClusterIP 10.245.85.236 <none> 80:31623/TCP 54s
hello-kubernetes-second ClusterIP 10.245.99.130 <none> 80:30303/TCP 12s
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 5m
В выводе показан как сервис hello-kubernetes-first, так и hello-kubernetes-second, а это значит, что Kubernetes успешно создал их.
Итак, вы создали два развертывания приложения hello-kubernetes с сопутствующими сервисами. Каждое развертывание имеет свой набор сообщений в спецификации, что позволит вам различать их во время тестирования. На следующем этапе вы установите Nginx Ingress Controller.
2: Установка входного контроллера Ingress Kubernetes
Теперь вы установите поддерживаемый Kubernetes Nginx Ingress Controller с помощью Helm. Обратите внимание, есть несколько Nginx Ingress-ов.
Контроллер Nginx Ingress состоит из пода и сервиса. Под запускает контроллер, который постоянно опрашивает конечную точку /ingresses на API-сервере кластера на наличие обновлений для доступных ресурсов Ingress. Сервис имеет тип LoadBalancer. Через балансировщик трафик будет попадать в контроллер. Затем контроллер направит трафик к соответствующим сервисам, как определено в ресурсах Ingress.
Только сервис LoadBalancer знает IP-адрес вашего балансировщика нагрузки. Некоторым приложениям (таким как ExternalDNS) необходимо знать его IP-адрес, но они могут только читать конфигурацию Ingress. Контроллер можно настроить для публикации IP-адреса на каждом Ingress-е, для этого нужно добавить параметр controller.publishService.enabled со значением true в команду helm install. Рекомендуется включить этот параметр для поддержки приложений, которые могут зависеть от IP-адреса балансировщика нагрузки.
Чтобы установить Nginx Ingress Controller в ваш кластер, выполните следующую команду:
helm install stable/nginx-ingress --name nginx-ingress --set controller.publishService.enabled=true
Эта команда устанавливает Nginx Ingress Controller из репозитория чартов stable, называет релиз nginx-ingress и присваивает параметру publishService значение true.
Вывод будет выглядеть так:
NAME: nginx-ingress
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
nginx-ingress-controller 1 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-7658988787-npv28 0/1 ContainerCreating 0 0s
nginx-ingress-default-backend-7f5d59d759-26xq2 0/1 ContainerCreating 0 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller LoadBalancer 10.245.9.107 <pending> 80:31305/TCP,443:30519/TCP 0s
nginx-ingress-default-backend ClusterIP 10.245.221.49 <none> 80/TCP 0s
==> v1/ServiceAccount
NAME SECRETS AGE
nginx-ingress 1 0s
==> v1beta1/ClusterRole
NAME AGE
nginx-ingress 0s
==> v1beta1/ClusterRoleBinding
NAME AGE
nginx-ingress 0s
==> v1beta1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-ingress-controller 0/1 1 0 0s
nginx-ingress-default-backend 0/1 1 0 0s
==> v1beta1/Role
NAME AGE
nginx-ingress 0s
==> v1beta1/RoleBinding
NAME AGE
nginx-ingress 0s
NOTES:
...
Helm зарегистрировал ресурсы, которые он создал в Kubernetes как часть установки чарта.
Вы можете увидеть, как появляется доступ к балансировщику, запустив команду:
kubectl get services -o wide -w nginx-ingress-controller
Вы установили Ingress контроллер Nginx, поддерживаемый сообществом Kubernetes. Он будет направлять трафик HTTP и HTTPS от балансировщика нагрузки к соответствующим бэкенд сервисам, настроенным в ресурсах Ingress. На следующем этапе вы познакомитесь с развертываниями приложения hello-kubernetes с помощью этих ресурсов.
3: Настройка доступа к приложениям с помощью Ingress
Теперь пора создать Ingress ресурс и использовать его для демонстрации развертываний приложений hello-kubernetes на желаемых доменах. Затем мы протестируем приложение, открыв его через браузер.
Хранить Ingress мы будем в файле hello-kubernetes-ingress.yaml. Создайте его в редакторе:
nano hello-kubernetes-ingress.yaml
Добавьте следующие строки в ваш файл:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: hw1.example.com
http:
paths:
- backend:
serviceName: hello-kubernetes-first
servicePort: 80
- host: hw2.example.com
http:
paths:
- backend:
serviceName: hello-kubernetes-second
servicePort: 80
В приведенном выше коде определяется ресурс Ingress по имени hello-kubernetes-ingress. Затем указывается два правила хоста, так что hw1.example.com направляется на сервис hello-kubernetes-first, а hw2.example.com направляется на Сервис второго развертывания (hello-kubernetes-second).
Не забудьте заменить условные домены своими собственными, затем сохраните и закройте файл.
Создайте ресурс в Kubernetes, выполнив следующую команду:
kubectl create -f hello-kubernetes-ingress.yaml
Затем вам нужно убедиться, что ваши два домена указаны в балансировщике нагрузки через записи А. Это делается через DNS провайдера.
Теперь вы можете перейти к домену hw1.example.com в вашем браузере. Вы увидите следующее сообщение:
Hello from the first deployment!
Второй вариант приложения (hw2.example.com) покажет другое сообщение:
Hello from the second deployment!
Мы убедились, что Ingress Controller правильно направляет запросы (в этом случае от двух доменов к двум разным сервисам).
Вы создали и настроили ресурс Ingress для обслуживания развертываний приложений hello-kubernetes на ваших доменах. На следующем этапе мы настроим Cert-Manager, чтобы иметь возможность защитить ваши ресурсы с помощью бесплатных сертификатов TLS от Let’s Encrypt.
4: Защита доступа с помощью Cert-Manager
Чтобы обезопасить свои ресурсы Ingress, вы установите Cert-Manager, создадите ClusterIssuer для производства и измените конфигурацию Ingress, чтобы использовать сертификаты TLS. ClusterIssuer – это ресурс Cert-Manager в Kubernetes, которые предоставляют сертификаты TLS. После установки и настройки ваше приложение будет работать по HTTPS.
Перед установкой Cert-Manager в кластер через Helm нужно вручную применить требуемые CRD (Custom Resource Definitions, пользовательские определения ресурсов) из репозитория jetstack/cert-manager, выполнив следующую команду:
kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml
Вы получите такой вывод:
customresourcedefinition.apiextensions.k8s.io/certificates.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/challenges.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/issuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/orders.certmanager.k8s.io created
Этот вывод показывает, что Kubernetes применил пользовательские ресурсы, необходимые для cert-manager.
Примечание: Если вы следовали этому руководству и выполнили требования, скорее всего, вы не создали пространство имен Kubernetes по имени cert-manager, поэтому вам не нужно будет запускать команду в этом блоке. Однако если это пространство имен существует в вашем кластере, вам нужно будет сообщить Cert-Manager, что оно не должно проходить валидацию, с помощью следующей команды:
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation="true"
Компонент Webhook в Cert-Manager требует сертификаты TLS для безопасной связи с сервером API Kubernetes. Чтобы Cert-Manager впервые сгенерировал для него сертификаты, должна быть отключена валидация ресурса в пространстве имен, в котором он развернут. В противном случае он застрянет в бесконечном цикле, не имея возможности связаться с API и создать сертификаты TLS.
Вывод будет выглядеть так:
namespace/cert-manager labeled
Затем нужно добавить в Helm репозиторий Jetstack, в котором находится чарт Cert-Manager. Для этого выполните следующую команду:
helm repo add jetstack https://charts.jetstack.io
Helm покажет следующий результат:
"jetstack" has been added to your repositories
Наконец, установите Cert-Manager в пространство имен cert-manager:
helm install --name cert-manager --namespace cert-manager jetstack/cert-manager
Вы увидите следующий вывод:
NAME: cert-manager
LAST DEPLOYED: ...
NAMESPACE: cert-manager
STATUS: DEPLOYED
RESOURCES:
==> v1/ClusterRole
NAME AGE
cert-manager-edit 3s
cert-manager-view 3s
cert-manager-webhook:webhook-requester 3s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
cert-manager-5d669ffbd8-rb6tr 0/1 ContainerCreating 0 2s
cert-manager-cainjector-79b7fc64f-gqbtz 0/1 ContainerCreating 0 2s
cert-manager-webhook-6484955794-v56lx 0/1 ContainerCreating 0 2s
...
NOTES:
cert-manager has been deployed successfully!
In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
More information on the different types of issuers and how to configure them
can be found in our documentation:
https://docs.cert-manager.io/en/latest/reference/issuers.html
For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:
https://docs.cert-manager.io/en/latest/reference/ingress-shim.html
Вывод показывает, что установка прошла успешно. Как указано в NOTES в выводе, вам необходимо настроить Issuer для выдачи сертификатов TLS.
Теперь мы создадим Issuer, который выдает сертификаты Let’s Encrypt, и сохраним его конфигурацию в файле production_issuer.yaml. Создайте файл и откройте его для редактирования:
nano production_issuer.yaml
Добавьте следующие строки:
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your_email_address
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
http01: {}
Эта конфигурация определяет ClusterIssuer, который связывается с Let’s Encrypt для получения сертификатов. Вам нужно заменить your_email_address адресом электронной почты, чтобы получать срочные уведомления о безопасности и истечении срока действия ваших сертификатов.
Сохраните и закройте файл.
Запустите его с помощью kubectl:
kubectl create -f production_issuer.yaml
Вы увидите следующий вывод:
clusterissuer.certmanager.k8s.io/letsencrypt-prod created
Установив Cert-Manager, вы можете представить сертификаты ресурсу Ingress, определенному на предыдущем этапе. Откройте hello-kubernetes-ingress.yaml для редактирования:
nano hello-kubernetes-ingress.yaml
Добавьте в него выделенные строки:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- hw1.example.com
- hw2.example.com
secretName: letsencrypt-prod
rules:
- host: hw1.example.com
http:
paths:
- backend:
serviceName: hello-kubernetes-first
servicePort: 80
- host: hw2.example.com
http:
paths:
- backend:
serviceName: hello-kubernetes-second
servicePort: 80
Блок tls в спецификации определяет, в каком секрете будут храниться сертификаты для сайтов (перечисленных в разделе hosts). Этот блок должен быть индивидуальным для каждого Ingress, который вы создаете.
Не забудьте заменить hw1.example.com и hw2.example.com собственными доменами. Когда вы закончите редактирование, сохраните и закройте файл.
Примените эту конфигурацию к вашему кластеру, выполнив следующую команду:
kubectl apply -f hello-kubernetes-ingress.yaml
Вы увидите следующий вывод:
ingress.extensions/hello-kubernetes-ingress configured
Вам нужно будет подождать несколько минут, чтобы серверы Let’s Encrypt выдали сертификаты для ваших доменов. В то же время вы можете отслеживать прогресс, проверив вывод следующей команды:
kubectl describe certificate letsencrypt-prod
Конец вывода будет выглядеть примерно так:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Generated 56s cert-manager Generated new private key
Normal GenerateSelfSigned 56s cert-manager Generated temporary self signed certificate
Normal OrderCreated 56s cert-manager Created Order resource "hello-kubernetes-1197334873"
Normal OrderComplete 31s cert-manager Order "hello-kubernetes-1197334873" completed successfully
Normal CertIssued 31s cert-manager Certificate issued successfully
Если последняя строка выводит Certificate issued successfully, вы можете выйти, нажав CTRL + C. Перейдите к одному из ваших доменов в браузере и проверьте его работу. Вы увидите в браузере замочек слева от адресной строки, означающий, что ваше соединение защищено.
Вы установили Cert-Manager с помощью Helm и создали ClusterIssuer для Let’s Encrypt. После этого вы обновили свой ресурс Ingress, чтобы применить Issuer для создания сертификатов TLS. Также вы подтвердили, что HTTPS работает правильно, перейдя на один из ваших доменов в браузере.
Tags: Cert-Manager, Helm, Ingress, Kubernetes, NGINX, Tiller