Настройка Nginx Ingress в Kubernetes с помощью Helm

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-ов.

Требования

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: , , , , ,