Привет, Хабр! В этой инструкции я покажу, как развернуть сайт в Kubernetes c помощью Terraform. Разберу интеграцию CRaaS с Managed Kubernetes, которая сократит ручную настройку и поможет публиковать образы контейнеров всего в несколько кликов.

Дисклеймер: мы не будем c нуля разбирать особенности работы с Terraform. Если вы не работали с этим инструментом, изучите сначала материал «Как развернуть свое приложение в Kubernetes».

Полезные ресурсы:


Создаем сервисного пользователя


Мы будем работать в панели управления my.selectel.ru.

Регистрируемся или авторизуемся в панели управления. Нажимаем справа сверху на аккаунт и во всплывающем меню выбираем Профиль и настройки. Далее переходим в Управление пользователямиСервисные пользователи.

Создаем пользователя с ролями Администратор аккаунта и Администратор пользователей:


При работе с Terraform мы будем использовать двух провайдеров: Selectel и OpenStack. Этого сервисного пользователя создаем для Selectel. Пользователя для провайдера OpenStack добавим через Terraform.

Клонируем репозиторий с примерами Terraform:

git clone https://github.com/selectel/terraform-examples

И переходим в директорию:

cd terraform-examples/examples/mks/cluster_one_nodegroup_with_net_infra

Создаем отдельный файл для чувствительных данных, где будут храниться: номер аккаунта, имена пользователей и их паролей.

nano secrets.tfvars

Обязательно измените пароли из примера! Вносим в него следующие данные (с указанием ваших данных соответственно):

# Данные для провайдера Selectel
# Задаются в личном кабинете my.selectel.ru
domain_name = "163638"
username = "webinar21"
password = "MJ77FsFE"
# Данные для провайдера OpenStack
# Модуль Terraform автоматически создаст этого пользователя
project_name = "demo11"
project_user_name = "webinar22"
user_password = "lVNH1v+w"
cluster_name = "Demo"
taints = []
labels = {}

  • domain_name — номер аккаунта (или номер договора) в my.selectel.ru;
  • username — имя пользователя, созданного ранее в панели my.selectel.ru;
  • project_name — название проекта в облачной платформе, который создаст Terraform;
  • project_user_name — имя пользователя, который создаст Terraform.

Чувствительные данные хранить в файле не безопасно без какого-то ограничения доступа или шифрования, но зато удобно, видно все и сразу.

Также можно задать такие данные через переменные окружения в консоли. Специальные переменные описаны на этих страницах:

Работа с Terraform


В файле vars.tf задаются основные характеристики для будущего кластера. Значения можно переопределить как в vars.tf, так и в secrets.tfvars.

По умолчанию будет создан кластер с двумя worker-нодами (nodes_count=2). Также по умолчанию установлены характеристики для самих worker-нод: cpus=2, ram_mb=4096, volume_gb=32.


Репозитории Hashicorp могут блокировать запросы из России. Чтобы настроить зеркало можно создать следующий файл:

nano .terraformrc

И вставить в него следующее, чтобы использовать наши репозитории как зеркало:

provider_installation {
  network_mirror {
    url = "https://mirror.selectel.ru/3rd-party/terraform-registry/"
    include = ["registry.terraform.io/*/*"]
  }
  direct {
    exclude = ["registry.terraform.io/*/*"]
  }
}

Инициализируем Terraform в консоли:

terraform init


Создаем инфраструктуру с указанием файла с секретными переменными:

terraform apply -var-file="secrets.tfvars"


При необходимости проверяем, что хочет создать Terraform. После пишем в консоли yes для подтверждения и нажимаем Enter.

Ждем, пока Terraform создаст все нужные для инфраструктуры ресурсы:



Создаем Container Registry


Возвращаемся в панель управления. Открываем Облачная платформаСontainer RegistryРеестры. Здесь должен лежать ваш проект. Мы для примера используем coffee-shop — простой лендинг кофейни.


Далее необходимо подготовить образ, который позже добавим в Container Registry — затем из этого образа мы развернем наше приложение. Чтобы собрать образ и запушить в Container Registry, посмотрим данные для авторизации.

Открываем в панели управления Container Registry, переходим на вкладку Токены и нажимаем Сгенерировать токен.



Копируем токен, а потом открываем консоль и вводим команду:

 docker login cr.selcloud.ru -u token -p <скопированный_из_панели_токен>

Нажимаем Enter и пробуем залогиниться.

Теперь нужно собрать образ из нашего Docker-файла. Вводим в терминале команду:

docker build -t cr.selcloud.ru/<реестр>/<репозиторий> .

docker push  cr.selcloud.ru/<реестр>/<репозиторий>

Собираем и пушим образ в Container Registry:


Проверяем в панели управления:


Кластер Kubernetes и реестр созданы.

Мы подготовили инфраструктуру, создали кластер и подготовили реестр: добавили образ, из которого будет запускаться приложение MKS — Managed Kubernetes.

Настраиваем интеграцию между MKS и Container Registry


Обычно, чтобы добавить приватный Registry в кластер Kubernetes, необходимо взять его креды данного и передать их секретом в этот кластер. В этом и заключается наша интеграция: мы идем в Container Registry, создаем токен и затем складываем его секретом в кластер. Что мы для этого делаем?

Сначала проверяем, что кластер перешел в статус Active:


Далее открываем Container Registry в панели управления и переходим в реестр coffee-shop. Жмем Доступ к реестру, выбираем Интеграция с Kubernetes:


Мы увидим список кластеров, которые находятся в том же проекте, где развернут реестр:


Выбираем наш кластер и нажимаем кнопку Интегрировать. Если интеграция пройдет успешно, вы увидите сообщение «Интегрирован с Kubernetes»:


Берем наш кластер и качаем конфигурационный файл:


Копируем путь до этого файла и делаем экспорт:

export KUBEСONFIG=<полный_путь_до_файла>

Проверяем ошибки. Смотрим, какие ноды есть в кластере:

kubectl get nodes

Инструкция по установке kubectl доступна на официальной странице.

Устанавливаем приложение в Kubernetes


Опишем, как разместить приложение в кластере Kubernetes.

Клонируем репозиторий командой:

git clone https://gitlab.com/cr-mks-webinar/infra.git

Переходим в директорию с манифестами Kubernetes:

cd infra/k8s/coffee-shop/

В файле deployment.yaml изменяем название секрета, который будет приходить в кластер интеграции:

imagePullSecrets:
  - name: craas-auth

И меняем URL образа на актуальный:

containers:
  - name: coffee-shop
  image: cr.selcloud.ru/coffee-shop/coffee-shop:latest
 

В файле ingress.yaml меняем домен, по которому будет работать лендинг:

  ingressClassName: nginx
  rules:
    - host: coffee-shop.yourname11.ru

Можно указать используемый вами домен.

Создаем неймспейс, в котором будут находиться абстракции Kubernetes:

kubectl create namespace webinar

Разворачиваем приложение в кластере:

kubectl apply -f .

Смотрим список подов. Проверяем, что все находятся в статусе Running:

kubectl get pods -n webinar


Делаем приложение доступным в интернете


Выпускаем сертификат


Выпустим для домена SSL-сертификат и используем его на балансировщике нагрузки.

Открываем в панели управления Менеджер секретов и выпускаем новый сертификат:


Есть разные варианты, мы используем сертификат от Let’s Encrypt. Вводим имя и выбираем домен:


Здесь yourname11.ru — имя вашего домена, который также указан в ingress.yaml.


После того как новый сертификат стал активен, скопируем его uuid, чтобы указать потом в Helm-чарте ingress-контроллера.


Важно: сертификат можно выпускать не более пяти раз в неделю.

Устанавливаем облачный балансировщик и Ingress-controller


Далее устанавливаем Ingress-контроллер. При его разворачивании мы укажем uuid сертификата, чтобы он был добавлен на Облачный балансировщик.

Переходим по ссылке на инструкцию в нашей документации.

Выбираем вкладку c настройкой балансировщика нагрузки.

Так выглядит генерация values.yaml файла:

helm inspect values ingress-nginx/ingress-nginx > values.yaml

В инструкции по ссылке выше из пункта 4 открываем сгенерированный values.yaml.

И в аннотации сервиса балансировщика указываем uuid сертификата:

    annotations: {
      loadbalancer.openstack.org/default-tls-container-ref: "<certificate_uuid>"
    }

values.yaml. <certificate_uuid>скопированный ранее uuid сертификата из менеджера секретов.


Важно: в этом же блоке, service, немного ниже нужно изменить порт назначения с HTTPS на HTTP:

        targetPorts:
          # -- Port of the ingress controller the external HTTP listener is mapped to.
          http: http
          # -- Port of the ingress controller the external HTTPS listener is mapped to.
          https: http # Здесь сделали замену https -> http

Устанавливаем ингресс-контроллер, пишем в консоли:

helm install ingress-nginx/ingress-nginx --generate-name -f values.yaml

Возвращаемся в панель управления и открываем раздел Балансировщики. Видим, что балансировщик появился, а к нему добавились два слушателя:


Когда балансировщик перейдет в статус Active, обновим страницу и скопируем его внешний IP-адрес:


Далее устанавливаем этот IP-адрес в А-записи домена: Сетевые сервисыДНС-хостингДоменыИзменитьРедактировать запись.


Работа с услугой DNS-хостинг также описана в нашей документации. Готово!


Возможно, эти тексты тоже вас заинтересуют:

Китайская компания Intellifusion представила 14-нм ИИ-процессор. Что это за чип и для чего он нужен?
Python, JavaScript или C++? Рассказываем, какие языки программирования изучать в 2024 году
Бэкапы для самых маленьких и матерых

Комментарии (9)


  1. mayorovp
    08.04.2024 11:41
    +2

    Что-то слишком много ручных действий в инструкции. Через terraform-то это всё не настроить никак?

    Ну и статья как будто из далёкого прошлого. Если она нацеливается на начинающих (а кому ещё нужно в картинках объяснять что куда вводить на сайте?) - то где инструкция по настройке зеркала репозитория terraform?


    1. outworld66 Автор
      08.04.2024 11:41
      +1

      Да, можно все в целом автоматизировать через Terraform, обращаясь в API Selectel, например, в провайдере http, вместо ручных действий в панели управления. Хотелось показать работу в нашей панели управления, поэтому так.

      Да, статья нацелена на начинающих. Спасибо за обратную связь, настройку зеркал для провайдеров добавил в статью.


      1. pxz
        08.04.2024 11:41
        +3

        Выглядит так, что большинство выполненных вручную действий как раз и должно быть реализовано в провайдере Selectel для TF. Надо его развивать. Действия в админке должны заканчиваться на генерации доступов к API, иначе это не IaC.

        Использование провайдера HTTP вместе с API, не поддерживающим идемпотентность, может привести к проблемам.


  1. mayorovp
    08.04.2024 11:41

    Ну и организация кода у вас в репозитории веселит:

    resource "selectel_mks_cluster_v1" "cluster_1" {
      name                              = var.cluster_name
      project_id                        = var.project_id
      region                            = var.region
      kube_version                      = var.kube_version
      enable_autorepair                 = var.enable_autorepair
      enable_patch_version_auto_upgrade = var.enable_patch_version_auto_upgrade
      network_id                        = var.network_id
      subnet_id                         = var.subnet_id
      maintenance_window_start          = var.maintenance_window_start
    }
    

    И это отдельный модуль! Вот нафига? Правда ли этот модуль использовать проще, чем лежащий в его основе провайдер?


    1. outworld66 Автор
      08.04.2024 11:41
      +2

      Разница в удобстве небольшая :) Можно и просто ресурс провайдера использовать. Примеры в репозитории разложены по модулям и, вероятно, поэтому и этот ресурс не стал исключением


      1. mayorovp
        08.04.2024 11:41

        Примеры у вас разложены по папкам. И отдельная папка модулей непонятно для чего.


  1. momai
    08.04.2024 11:41
    +2

    export KUBEСONFIG=<полный_путь_до_файла>

    ребят, ну вы чего? В KUBEСONFIG у вас C - русская!


    1. mayorovp
      08.04.2024 11:41

      Вот весело будет начинающим-то...


  1. Angry_Bel
    08.04.2024 11:41

    А терраформ то где? Странная история, когда мы про терраформ, но делаем всё руками через что угодно.

    Почему нельзя сделать одним терраформ эпплай?

    Пушить руками контейнер не лучший вариант, вы не знаете что там запушено, насколько кривые руки это делали и т.д. Стоит построить микропайплайн для этого, если уж код в Гите лежит