Для обеспечения балансировки нагрузки, масштабируемости и повышения отказоустойчивости могут использоваться вспомогательные средства — оркестраторы. Среди них большой популярностью сейчас пользуется сервис Kubernetes. Самый простой способ попробовать его в деле — развернуть его в облаке, чем мы сегодня и займемся.

Первым делом заходим на портал Azure, нажимаем «Создать ресурс» и находим сервис под названием Kubernetes Service. Выбираем имя и префикс DNS на свой вкус. Имя влияет на то, как ты будешь обращаться к своему кластеру, а вот префикс влияет на его FQDN-адрес.

Создание кластера Kubernetes в Azure. Основные настройки
Создание кластера Kubernetes в Azure. Основные настройки

INFO

Практически сразу после релиза Google передала проект Kubernetes в созданный при сотрудничестве с The Linux Foundation фонд под названием Cloud Native Computing Foundation.

Вторым шагом предлагается создать service principal. Service principal — это своеобразный сервисный аккаунт, под которым могут выполняться какие-то определенные задачи. Плюсы в том, что права такого аккаунта можно ограничить. Кроме того, можно создать любое количество подобных аккаунтов (в то время как число обычных аккаунтов ограничено подпиской). Найти созданные аккаунты service principal можно в Active Directory среди App Registrations.

Создание кластера Kubernetes в Azure. Проверка подлинности
Создание кластера Kubernetes в Azure. Проверка подлинности

RBAC (role-based access control) — это возможность ограничить или предоставить доступ к определенным ресурсам (или группам ресурсов). То есть ты сможешь разграничить, какие пользователи подписки имеют права доступа, а какие не имеют.

Создание кластера Kubernetes в Azure. Сетевые подключения
Создание кластера Kubernetes в Azure. Сетевые подключения

На данный момент процесс занимает минут двадцать, но все может зависеть от конфигурации. Найти официальные руководства можно по ссылкам создание кластера AKS с помощью портала и создание кластера AKS с помощью CLI.

Для работы нам понадобится командная строка Azure — CLI (Command Line Interface). Ее можно установить как под Windows, так и под macOS или Linux. Лично я предпочитаю использовать Azure Cloud Shell. Это командная строка, которая запускается из загруженной в браузер страницы портала Azure. Для работы она требует созданного blob-хранилища. Его стоимость составит несколько центов в месяц, и потому я предпочитаю не париться по поводу установки CLI на свою машину.

Kubernetes поддерживает различные технологии контейнеров, но давай рассмотрим самую популярную — Docker. Docker.hub позволяет хранить один приватный образ докера бесплатно. Если нужно больше, то можно разместить их за деньги. Но за деньги приватный образ докера можно разместить и в Azure Container Registry. Сейчас цены начинаются с 5 долларов в месяц (за базовый SKU).

Я создал сервис ACR под именем myservice. Если ты тоже соберешься воспользоваться ACR, то после создания сервиса будет необходимо получить его ключи.

Ключи доступа к ACR
Ключи доступа к ACR

Затем станет возможным залогиниться, выполнив команду

docker login myservice.azurecr.io 

Вводим взятые с портала имя пользователя myservice и пароль PJSeyO9=lCMRDI7dGkz68wjhFGRGxSY3. Теперь, зайдя в директорию с проектом, можно будет построить образ, одновременно пометив его нужным тегом. А после этого отправить его в облачный сервис:

docker build -t myservice.azurecr.io/myservice .
docker push myservice.azurecr.io/myservice
 

Секреты, секреты… Предоставляем доступ к образу и сохраняем настройки

При работе с развернутым AKS необходимо получить его креды. Иначе команды kubectl не будут выполняться. Получить доступ к AKS позволяет следующая команда:

az aks get-credentials --resource-group KubernetesGroup --name verycoolcluster

Для того чтобы получить доступ к образу докера, расположенному в репозитории докера в приватном контейнере, понадобится создать секрет. Если у тебя публичный образ, то этот шаг можно пропустить. Для создания файла секрета нужно выполнить команду такого вида:

kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

Если твой образ находится в репозитории докера, то значением <your-registry-server> будет https://index.docker.io/v1/. Для Azure Container Registry FQDN — <registry-name>.azurecr.io. То есть, чтобы создать секрет для контейнера в моем случае, я выполнил

kubectl create secret docker-registry regcred --docker-server="myservice.azurecr.io" --docker-username="myservice" --docker-password="PJSeyO9=lCMRDI7dGkz68wjhFGRGxSY3" --docker-email="asommer@yandex.ru"

Посмотреть содержимое созданного файла секрета теперь можно с помощью команды

kubectl get secret regcred --output=yaml

Если ты используешь AKS, то можно не создавать файл секрета, а предоставить доступ сервису AKS к сервису ACR иным способом — выполнив особый скрипт. Взять его можно со следующей странички: Authenticate with Azure Container Registry from Azure Kubernetes Service.

#!/bin/bash

AKS_RESOURCE_GROUP=KubernetesGroup
AKS_CLUSTER_NAME=verycoolcluster
ACR_RESOURCE_GROUP=MyACRGroup
ACR_NAME=myservice

# Get the id of the service principal configured for AKS
CLIENT_ID=$(az aks show --resource-group $AKS_RESOURCE_GROUP --name $AKS_CLUSTER_NAME --query "servicePrincipalProfile.clientId" --output tsv)

# Get the ACR registry resource id
ACR_ID=$(az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP --query "id" --output tsv)

# Create role assignment
az role assignment create --assignee $CLIENT_ID --role Reader --scope $ACR_ID

Можешь просто модифицировать значения переменных AKS_* и ACR_*, скопировать скрипт и вставить его в Azure CLI или Cloud Shell.

Kubernetes содержит безопасное хранилище учетных данных. То есть можно создать файл с настройками, и доступ к этим настройкам получить извне будет затруднительно. В этом файле обычно находятся строки подключения к базам данных и какие-то креды. Если такой информации у тебя в приложении нет (что, правда?), то этот шаг можно пропустить.

Чтобы создать файл с настройками из командной строки, нам понадобятся команды vi.

  • vi <имя файла> создаст файл, если он отсутствует, или откроет существующий.
  • Сохранить введенные изменения — ESC и после этого ZZ.
  • Просто выйти без сохранения — ESC и после :q!.

Очень сокращенное описание, но его должно хватить. Могу добавить, что может очень пригодиться использование клавиши Insert.

Итак, через Azure Cloud Shell создаешь файл с произвольным названием (допустим, appsettings.json) и необходимым содержимым. Допустим, таким:

{
  "ConnectionString": "some secret string goes there"
}

И после выполняешь команду

kubectl create secret generic secret-appsettings --from-file=/home/youraccount/appsettings.json

Эта команда создаст секрет с настройками под именем secret-appsettings. Узнать, на какой путь заменить /home/youraccount, можно с помощью команды pwd.

 

Создание deployment

Deployments предназначены для stateless-сервисов (хорошо сказал, сразу вспоминаются шутки про билингвов, митболы и сторителлинг. 🙂 — Прим. ред.). Они описывают то, как Pods и ReplicaSets будут созданы и как они будут обновляться. Pod — это группа контейнеров (или же один контейнер), которые работают в одном окружении. ReplicaSet следит за тем, чтобы указанное количество pod было запущено и постоянно работало.

Я создаю файл deploy.yaml, который создаст три пода. Файл содержит следующий код (напоминаю, что пробелы в YAML очень важны):

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: mydeployment
spec:
  replicas: 3  
  minReadySeconds: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: myservice.azurecr.io/myservice:latest
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        imagePullPolicy: Always
        env:
        - name: "ASPNETCORE_ENVIRONMENT"
          value: "Production"
        volumeMounts:
        - name: secrets
          mountPath: /app/secrets
          readOnly: true
      imagePullSecrets:
      - name: regcred
      volumes:
      - name: secrets
        secret:
          secretName: secret-appsettings

Рассмотрим код. В начале описывается количество реплик и стратегия обновления. Затем деплойменту задается имя (myapp) и указывается ссылка на образ контейнера. Прописываются порты: 80 — это стандартный порт для HTTP. Далее идут ASP.NET Core’овские настройки environment’а. Затем монтируются креды приватного образа докера и секретные настройки приложения, которые мы не так давно создавали.

  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1

Этот кусок отвечает за процесс обновления. maxSurge — количество подов, создаваемых сверх существующих при обновлении (в штуках или процентах). maxUnavailable — максимальное количество подов, которые могут становиться недоступными во время обновления.

Deployment можно создать с помощью команды

kubectl apply -f deploy.yaml
 

Знакомься — ingress

Для того чтобы предоставить доступ к сервисам кластера и организовать балансировку нагрузки, используется сервис под названием ingress. Довольно популярен ingress, созданный на основании nginx. Проще всего его установить, используя пакетный менеджер Kubernetes, который называется helm. Плюсом Azure Cloud Shell будет то, что helm уже в нее установлен. Для установки nginx-ingress остается ввести

helm init

подождать немного и выполнить

helm install stable/nginx-ingress --namespace kube-system --set rbac.create=false
 

Создание SSL-сертификатов с помощью Let’s Encrypt

Так как SSL-сертификат привязывается к какому-то доменному имени, то зададим нашему ресурсу DNS-имя. Выполним следующую команду и возьмем внешний (external) IP:

kubectl get service -l app=nginx-ingress --namespace kube-system

Подставим IP и придуманное нами имя для субдомена в следующий скрипт:

#!/bin/bash

# Public IP address of your ingress controller
IP="168.63.19.2"

# Name to associate with public IP address
DNSNAME="myservice-ingress"

# Get the resource-id of the public ip
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public ip address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME

Этот скрипт просто скопируем, вставим в командную строку и таким образом выполним. В качестве имени для субдомена я задал очень оригинальное имя — myservice-ingress.

Установим менеджер сертификатов, аналогичным способом скопировав и вставив в командную строку следующий скрипт. Здесь даже ничего особо менять не нужно.

helm install \
--name cert-manager \
--namespace kube-system \
stable/cert-manager \
--set ingressShim.defaultIssuerName=letsencrypt-prod \
--set ingressShim.defaultIssuerKind=ClusterIssuer \
--set rbac.create=false \
--set serviceAccount.create=false

Если бы у нас кластер был с RBAC, то скрипт был бы другим.

helm install stable/cert-manager --set ingressShim.defaultIssuerName=letsencrypt-staging --set ingressShim.defaultIssuerKind=ClusterIssuer

Если файл сертификата имеется в наличии, то можно его добавить как-то так:

kubectl create secret tls tls-secret --cert CERT.crt --key KEY-FOR-CERT.key

Но поскольку у нас сертификата, подписанного CA, нет, придется немного потанцевать с бубном. Мы создадим CA с помощью бесплатного сервиса под названием Let’s Encrypt. Let’s Encrypt — это Certificate Authority, который выдает сертификаты совершенно бесплатно. Такая вот альтруистическая организация, цель которой — безопасный интернет.

Итак, создаем файл cluster-issuer.yaml. Он описывает организацию, выдавшую сертификат.

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: youeemail@yourdomain.ru
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

Тебе необходимо только заменить email на свой адрес, и можно выполнять

kubectl apply -f cluster-issuer.yaml

Затем создаем файл сертификата certificate.yaml, указав имя созданного ClusterIssuer и домен, для которого предназначен сертификат, — myservice-ingress.westeurope.cloudapp.azure.com.

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: tls-prod-secret
spec:
  secretName: tls-prod-secret
  dnsNames:
  - myservice-ingress.westeurope.cloudapp.azure.com
  acme:
    config:
    - http01:
        ingressClass: nginx
      domains:
      - myservice-ingress.westeurope.cloudapp.azure.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Выполняем:

kubectl apply -f certificate.yaml
 

Создание сервиса и ingress

В Kubernetes можно создавать сервисы четырех типов.

  1. Сервис по умолчанию — ClusterIP. Доступ к этому сервису возможен только из кластера по внутреннему IP.
  2. NodePort автоматически создает сервис ClusterIP. Доступ к NodePort возможен извне по маршруту <NodeIP>:<NodePort>.
  3. Балансировщик нагрузки LoadBalancer предоставляет доступ к сервису извне, автоматически создавая сервисы NodePort и ClusterIP.
  4. ExternalName связывает сервис со внешним именем.

Нам хватит базового сервиса:

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  type: ClusterIP
  ports:
    - port: 80
      name: http
      targetPort: http
  selector:
    app: myapp

Значением selector мы указываем имя нашего деплоймента. Остается создать сервис:

kubectl apply -f service.yaml

И в качестве заключительного этапа создаем ingress. В YAML мы укажем имя cluster-issuer и сертификата. Их мы создавали ранее.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myingress
  annotations:
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - hosts:
    - myservice-ingress.westeurope.cloudapp.azure.com
    secretName: tls-prod-secret
  rules:
  - host: myservice-ingress.westeurope.cloudapp.azure.com
    http:
      paths:
      - path: /
        backend:
          serviceName: myservice
          servicePort: 80

Через какое-то время после создания ingress с помощью все той же команды kubectl apply наш микросервис должен стать доступным по адресу https://myservice-ingress.westeurope.cloudapp.azure.com. Кликнув на замочек в адресной строке браузера рядом с https, можно убедиться, что сертификат валидный и выдан CA.

Сертификат
Сертификат

Оставить мнение