Kubernetes — это система с открытым исходным кодом, разработанная Google для запуска и управления контейнерными приложениями на основе микросервисов в кластере. Людям, которые используют Kubernetes, часто нужно, чтобы службы, которые они создают в Kubernetes, были доступны за пределами их кластера Kubernetes.
Хотя Kubernetes предоставляет встроенные решения для предоставления услуг, описанные ниже, эти решения ограничивают вас балансировкой нагрузки уровня 4 или циклическим распределением нагрузки HTTP.
В этом посте показано, как использовать NGINX Plus в качестве усовершенствованного решения для балансировки нагрузки уровня 7 для предоставления услуг Kubernetes Интернету, независимо от того, используете ли вы Kubernetes в облаке или в собственной инфраструктуре.
Мы предполагаем, что у вас есть базовые знания о Kubernetes (модули, службы, контроллеры репликации и метки) и работающий кластер Kubernetes. Чтобы узнать больше о Kubernetes, пожалуйста, посетите официальное руководство пользователя Kubernetes .
Предоставление услуг Kubernetes с помощью встроенных решений
Kubernetes предлагает несколько вариантов предоставления услуг . Два из них — NodePort и LoadBalancer — соответствуют определенному типу сервиса. Третий вариант, Ingress API, стал доступен как бета-версия в выпуске Kubernetes 1.1.
NodePort
Указание типа сервиса в качестве NodePort делает сервис доступным на том же порту на каждом узле Kubernetes. Чтобы предоставить службу Интернету, вы должны открыть один или несколько узлов на этом порту. Для обеспечения высокой доступности вы можете предоставить доступ к нескольким узлам и использовать балансировку нагрузки на основе DNS для распределения трафика между ними, либо вы можете разместить узлы за балансировщиком нагрузки по вашему выбору.
Когда входящий трафик попадает на узел в порту, он распределяется по нагрузке между модулями службы. Балансировка нагрузки, выполняемая прокси-сервером Kubernetes, работающим на каждом узле, ограничена балансировкой нагрузки TCP / UDP.
LoadBalancer
Указание типа службы в качестве LoadBalancer выделяет балансировщик нагрузки облака, который распределяет входящий трафик между модулями службы.
Решение LoadBalancer поддерживается только некоторыми облачными провайдерами и Google Container Engine и недоступно, если вы используете Kubernetes в собственной инфраструктуре. Кроме того, Kubernetes позволяет настроить циклическую балансировку нагрузки TCP, даже если облачный балансировщик нагрузки имеет расширенные функции, такие как сохранение сеанса или сопоставление запросов.
Входной API
Создание ресурса Ingress позволяет вам предоставлять сервисы Интернету по индивидуальным URL-адресам (например, сервис A по URL / foo и сервис B по URL / bar ) и нескольким именам виртуальных хостов (например, foo.example.com для одна группа услуг и bar.example.com для другой группы). Контроллер Ingress использует ресурс Ingress и устанавливает внешний балансировщик нагрузки.
Контроллер Ingress не является частью стандартного развертывания Kubernetes: вам нужно выбрать контроллер, который лучше всего соответствует вашим потребностям, или внедрить его самостоятельно и добавить его в свой кластер Kubernetes. Ожидается, что многие реализации контроллера появятся в ближайшее время, но на данный момент единственной доступной реализацией является контроллер для Google Compute Engine HTTP Balancer , который работает, только если вы используете Kubernetes в Google Compute Engine или Google Container Engine . Входной API поддерживает только циклическую балансировку нагрузки HTTP, даже если фактический балансировщик нагрузки поддерживает расширенные функции.
На момент написания статьи и Ingress API, и контроллер для Google Compute Engine HTTP Load Balancer находятся в стадии бета-тестирования.
Хотя упомянутые выше решения просты в настройке и работают «из коробки», они не предоставляют никаких дополнительных функций, особенно функций, связанных с балансировкой нагрузки на уровне 7.
Предоставление услуг Kubernetes с NGINX Plus
Чтобы интегрировать NGINX Plus с Kubernetes, нам нужно убедиться, что конфигурация NGINX Plus остается синхронизированной с Kubernetes, отражая изменения в службах Kubernetes, такие как добавление или удаление модулей. С помощью программного обеспечения NGINX с открытым исходным кодом вы вручную изменяете файл конфигурации NGINX и выполняете перезагрузку конфигурации. С NGINX Plus есть два способа динамического обновления конфигурации :
- С API. Этот метод использует API реконфигурации NGINX Plus « на лету» для добавления и удаления записей для модулей Kubernetes в конфигурации NGINX Plus, а также API Kubernetes для получения IP-адресов модулей. Этот метод требует от нас написания некоторого кода, и мы не будем подробно его обсуждать. Подробности смотрите на вебинаре Келси Хайтауэра « Вывод Kubernetes на грань с NGINX Plus» , на котором он исследует API и создает приложение, которое их использует.
- По именам DNS повторно разрешения — Этот метод требует только правильной конфигурации одноразового Nginx Plus, как описан в следующем разделе.
Использование реконфигурации на основе DNS
Мы предполагаем, что у вас уже есть работающий кластер Kubernetes и хост с kubectl
утилитой, доступной для управления кластером; инструкции см. в руководстве по началу работы с Kubernetes для вашего типа кластера. Вам также необходимо создать образ NGINX Plus Docker, и инструкции доступны в этом блоге .
Вот схема того, что мы будем делать:
- Сконфигурируйте модуль NGINX Plus для предоставления и балансировки нагрузки службы, которую мы создаем на шаге 2.
- Создайте простой сервис, который обслуживает статические веб-страницы.
- Масштабируйте сервис вверх и вниз и посмотрите, как NGINX Plus автоматически перенастраивается.
Примечания: Мы протестировали решение, описанное в этом блоге, с Kubernetes 1.0.6, работающим на Google Compute Engine, и локальной установкой Vagrant , которую мы используем ниже.
В командах значения, которые могут отличаться для вашей настройки Kubernetes, выделены курсивом.
Настройка модуля NGINX Plus
Мы помещаем NGINX Plus в модуль Kubernetes на узле, который мы выставляем в Интернете. Наш модуль создан контроллером репликации, который мы также настраиваем. Наш специфический для Kubernetes файл конфигурации NGINX Plus находится в папке, совместно используемой модулем NGINX Plus и узлом, что упрощает обслуживание.
Выбор узла, в котором находится стручок NGINX Plus
Чтобы обозначить узел, где работает модуль NGINX Plus, мы добавляем метку для этого узла. Мы получаем список всех узлов, выполнив:
$ kubectl get nodes
NAME LABELS STATUS
10.245.1.3 Kubernetes.io/hostname=10.245.1.3 Ready
10.245.1.4 Kubernetes.io/hostname=10.245.1.4 Ready
10.245.1.5 Kubernetes.io/hostname=10.245.1.5 Ready
Мы выбираем первый узел и добавляем к нему метку, выполняя:
$ kubectl label node 10.245.1.3 role=nginxplus
Настройка контроллера репликации для модуля NGINX Plus
Мы не создаем модуль NGINX Plus напрямую, а через контроллер репликации. Мы настраиваем контроллер репликации для модуля NGINX Plus в файле объявления Kubernetes с именем nginxplus-rc.yaml .
- Мы устанавливаем число
replicas
в единицу, что означает, что Kubernetes гарантирует, что один модуль NGINX Plus всегда работает: если модуль выходит из строя, он заменяется новым модулем. - В
nodeSelector
поле мы указываем, что модуль NGINX Plus создается на узле с меткойrole:
nginxplus
. - Наш контейнер NGINX Plus предоставляет два порта, 80 и 8080, и мы настроили сопоставление между ними и портами 80 и 8080 на узле.
- Наш контейнер NGINX Plus также совместно использует папку /etc/nginx/conf.d, которая находится на узле. Как будет объяснено ниже, общий доступ к папке позволяет нам перенастроить NGINX Plus без перестройки образа контейнера.
apiVersion: v1
kind: ReplicationController
metadata:
name: nginxplus-rc
spec:
replicas: 1
selector:
app: nginxplus
template:
metadata:
labels:
app: nginxplus
spec:
nodeSelector:
role: nginxplus
containers:
- name: nginxplus
image: nginxplus
ports:
- name: http
containerPort: 80
hostPort: 80
- name: http-alt
containerPort: 8080
hostPort: 8080
volumeMounts:
- mountPath: "/etc/nginx/conf.d"
name: etc-nginx-confd
volumes:
- hostPath:
path: "/etc/nginx/conf.d"
name: etc-nginx-confd
Обеспечение доступности образа докера NGINX Plus на узле
Как мы уже говорили выше, мы уже создали образ NGINX Plus Docker. Теперь мы делаем его доступным на узле. Для простоты мы не используем частный репозиторий Docker, а просто загружаем изображение на узел вручную.
На хосте, на котором мы создали образ Docker, мы запускаем следующую команду, чтобы сохранить образ в файл:
$ docker save -o nginxplus.tar nginxplus
Мы передаем nginxplus.tar на узел и запускаем следующую команду на узле, чтобы загрузить изображение из файла:
$ docker load -i nginxplus.tar
Настройка NGINX Plus
В папке / etc / nginx контейнера NGINX Plus мы сохраняем основной файл конфигурации nginx.conf по умолчанию, который поставляется с пакетами NGINX Plus. include
Директива в файле по умолчанию считывает в других файлах конфигурации из /etc/nginx/conf.d папки. Как указано в для контроллера репликации NGINX Plus ( nginxplus-rc.yaml ), мы совместно используем папку /etc/nginx/conf.d на узле NGINX Plus с контейнером. Совместное использование означает, что мы можем вносить изменения в файлы конфигурации, хранящиеся в папке (на узле), без необходимости перестраивать образ NGINX Plus Docker, что мы должны были бы сделать, если бы создали папку непосредственно в контейнере. Мы помещаем наш специфичный для Kubernetes файл конфигурации (backend.conf ) в общей папке.
Сначала давайте создадим папку /etc/nginx/conf.d на узле.
$ mkdir /etc/nginx/conf.d
Затем мы создаем файл backend.conf и включаем эти директивы:
resolver
— Определяет IP-адрес преобразователя DNS Kubernetes, используя IP-адрес по умолчанию, 10.0.0.10.valid
Параметр говорит NGINX Plus для повторной решимости любого DNS имени каждых пяти секунд. IP-адрес вашей службы DNS Kubernetes может отличаться. Запустите эту команду, чтобы узнать это:$ kubectl get svc kube-dns --namespace=kube-system
upstream
— Создает вышестоящую группу под названием backend для службы Kubernetes, которую мы представляем. Мы идентифицируем серверы в вышестоящей группе по имени хоста и включаемresolve
директиву, чтобы NGINX повторно разрешил имя хоста во время выполнения.server
(дважды) — Определите два виртуальных сервера:
- Первый сервер прослушивает порт 80 и распределяет нагрузку по входящим запросам для / nginx-service среди модулей нашего сервиса. Мы также настроили активные проверки здоровья .
- Второй сервер прослушивает порт 8080. Здесь мы настроили мониторинг активности NGINX Plus. Позже мы будем использовать его для проверки правильности перенастройки NGINX Plus.
resolver 10.0.0.10 valid=5s;
upstream backend {
zone upstream-backend 64k;
server nginx-service.default.svc.cluster.local resolve;
}
server {
listen 80;
status_zone backend-servers;
location /nginx-service/ {
proxy_pass http://backend/;
health_check;
}
}
server {
listen 8080;
root /usr/share/nginx/html;
location = /status.html { }
location /status {
status;
}
}
Создание контроллера репликации
Теперь мы готовы создать контроллер репликации, выполнив эту команду на нашем узле:
$ kubectl create -f nginxplus-rc.yaml
Чтобы убедиться, что модуль NGINX Plus был создан, мы запускаем:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginxplus-rc-0ts5t 1/1 Running 0 17s
Мы запускаем Kubernetes на локальной установке Vagrant, поэтому мы знаем, что внешний IP-адрес нашего узла — 10.245.1.3, и мы будем использовать этот адрес до конца этого примера. Если вы используете Kubernetes на облачном провайдере, вы можете получить внешний IP-адрес вашего узла, выполнив:
$ kubectl get nodes node-name -o json | grep -i externalIP -A 1
"type": "ExternalIP",
"address": XXX.XXX.XXX.XXX
Если вы работаете в облаке, не забудьте настроить правило брандмауэра, чтобы разрешить узлу NGINX Plus принимать входящий трафик. Пожалуйста, обратитесь к документации вашего облачного провайдера.
Мы можем проверить, что наш модуль NGINX Plus запущен и работает, посмотрев на панель мониторинга NGINX Plus в режиме реального времени, которая доступна через порт 8080 по внешнему IP-адресу узла (например, http://10.245.1.3:8080/status .html в нашем случае). Однако если мы посмотрим на этот момент, мы не увидим никаких серверов для нашего сервиса, потому что мы еще не создали его.
Создание простого сервиса Kubernetes
Теперь пришло время создать сервис Kubernetes. Наш сервис состоит из двух серверов NGINX (с открытым исходным кодом), которые обслуживают статические веб-страницы.
Создание контроллера репликации для службы
Сначала мы создаем контроллер репликации, чтобы Kubernetes следил за тем, чтобы указанное количество реплик (модулей) веб-сервера NGINX всегда работало в кластере. Вот файл декларации ( nginx-rc.yaml ):
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-rc
spec:
replicas: 2
selector:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Наш контроллер состоит из двух веб-серверов NGINX. Мы объявляем контроллер, состоящий из модулей с одним контейнером NGINX, открывающим порт 80. Образ NGINX будет извлечен из Docker Hub.
Чтобы создать контроллер репликации, мы запускаем следующие команды на узле:
$ kubectl create -f nginx-rc.yaml
Чтобы проверить, что наши модули были созданы, мы можем запустить следующую команду. Мы используем селектор меток, app=nginx
чтобы получить только модули, созданные контроллером репликации на предыдущем шаге:
$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-rc-544f1 1/1 Running 0 2m
nginx-rc-uk6pm 1/1 Running 0 2m
Создание сервиса
Затем мы создаем сервис для модулей, созданных нашим контроллером репликации. Мы объявляем сервис со следующим файлом ( nginx-service.yaml ):
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ClusterIP: None
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
Здесь мы объявляем специальный безголовый сервис , устанавливая ClusterIP
поле в None
. При использовании этого типа службы IP-адрес кластера не выделяется, а служба недоступна через прокси-сервер kube. DNS-запрос к Kubernetes DNS возвращает несколько A
записей (IP-адреса наших модулей).
Устанавливая selector
поле в app:
nginx
, мы объявляем, какие модули принадлежат сервису, а именно, модули, созданные нашим контроллером репликации NGINX (определено в nginx-rc.yaml ).
На узле мы запускаем следующую команду, которая создает сервис:
$ kubectl create -f nginx-service.yaml
Теперь, если мы обновим страницу панели инструментов и перейдем на вкладку Upstreams в верхнем правом углу, мы увидим два добавленных сервера.
Мы также можем проверить, что NGINX Plus является трафиком с балансировкой нагрузки между модулями сервиса. Если это так, мы видим страницу приветствия NGINX по умолчанию при доступе к http://10.245.1.3/nginx-service/ в браузере.
Если мы обновим эту страницу несколько раз и посмотрим на панель состояния, мы увидим, как запросы распределяются по двум вышестоящим серверам.
Масштабирование службы Kubernetes
Теперь давайте добавим еще два модуля в наш сервис и убедимся, что конфигурация NGINX Plus снова обновляется автоматически. Мы запускаем эту команду, чтобы изменить количество модулей на четыре, масштабируя контроллер репликации:
$ kubectl scale rc nginx-rc --replicas=4
scaled
Чтобы проверить, что NGINX Plus был перенастроен, мы могли бы снова взглянуть на приборную панель, но на этот раз мы вместо этого используем API статуса NGINX Plus. На нашем узле мы выполняем следующую команду, где 10.245.1.3 является внешним IP-адресом нашего узла NGINX Plus. Чтобы отформатировать вывод JSON, мы направляем вывод в jq
.
$ curl -s 10.245.1.3:8080/status/upstreams/backend | jq .
{
"peers": [
{
"id": 1,
"server": "10.0.0.1:80",
"backup": false,
"weight": 1,
"state": "unhealthy",
"active": 0,
"requests": 1,
"responses": {
"1xx": 0,
"2xx": 0,
"3xx": 0,
"4xx": 0,
"5xx": 0,
"total": 0
},
"sent": 0,
"received": 0,
"fails": 0,
"unavail": 0,
"health_checks": {
"checks": 1,
"fails": 1,
"unhealthy": 1,
"last_passed": false
},
"downtime": 33965,
"downstart": 1445378182275,
"selected": 1445378131000
},
{
"id": 2,
"server": "10.246.1.6:80",
...
},
{
"id": 3,
"server": "10.246.3.2:80",
...
{
"id": 4,
"server": "10.0.0.2:80",
...
}
],
"keepalive": 0
}
peers
Массив на выходе JSON имеет ровно четыре элемента, по одному для каждого веб — сервера Nginx.
Теперь давайте уменьшим количество стручков с четырех до одного и снова проверим статус NGINX Plus:
$ kubectl scale rc nginx-rc --replicas=1
scaled
$ curl -s 10.245.1.3:8080/status/upstreams/backend | jq .
Теперь peers
массив в выводе JSON содержит только один элемент.
Теперь, когда NGINX Plus запущен и работает, мы можем начать использовать его расширенные функции, такие как сохранение сеанса , завершение SSL , маршрутизация запросов , расширенный мониторинг и многое другое .
Резюме
Варианты реконфигурации «на лету», доступные в NGINX Plus, позволяют легко интегрировать его с Kubernetes: программно через API или полностью с помощью DNS. Использование NGINX Plus для предоставления услуг Kubernetes Интернету предоставляет множество функций, которые отсутствуют в современных встроенных решениях балансировки нагрузки Kubernetes.