You’re going to need a bigger boat.
В 2020е годы стали активно развиваться новые SaaS платформы, в противовес широко используемой "большой тройке" AWS, GCP, Azure. В частности, в РФ появился целый ряд Cloud-провайдеров с разным функционалом и целевой аудиторией. Одним из примеров новой волны клаудов стал SberCloud. Наибольший интерес представляет его часть, называемая advanced, функционал которой выглядит наиболее похоже на привычные публичные клауды и имеет открытый API.
Данный пост не является обзором функционала или сравнением с другими игроками. Не секрет, что под капотом SberCloud Advanced находится адаптированный дистрибутив HuaweiCloud, что легко заметить по практически идентичной документации (например Elastic Cloud Server в SberCloudи HuaweiCloud).
Будет рассмотрена следующая задача:
- поднять минимальный стенд с managed Kubernetes, используя подход Infrastructure-as-Code.
Под минимальным стендом подразумевается следующее:
Первое знакомство с SberCloud, как всегда в таких случаях, начинается с работы в веб-консоли, но для построения полноценного IaC, нам потребуется API клауда и некая автоматизация вокруг, например на базе Terraform. К счастью, инженеры из сберклауда тоже озаботились этим вопросом и поиск по гитхабу даёт следующий репозиторий с соответствующим терраформ провайдером. Репозиторий живой, выходят регулярые релизы с чейнджлогами, есть пулл-реквесты и закрытые ишуи. Отдельно стоит отметить директорию examples, в которой есть практически всё, что может пригодиться для быстрого старта. Однако, есть некоторые тонкости.
Начинать следует с конфигурации аутентификации терраформ клиента по инструкции отсюда. В случае, когда у вас есть учётные данные только для IAM юзера, то нужно посетать следующие переменные окружения:
$ export SBC_ENTERPRISE_PROJECT_ID="YOUR_ENTERPRISE_UUID"
$ export SBC_PROJECT_NAME="YOUR_ENTERPRISE_PROJECT_NAME"
При этом, в SBC_PROJECT_NAME нужно писать имя не в том виде, в котором его видно в веб-консоли. Формат
должен быть следующий: ${SBC_REGION_NAME}_${PROJECT_NAME_FROM_WEBCONSOLE}
. Например ru-moscow-1_my-awesome-project
.
На момент написания, данная информация отсутствовала в документации, однако можно было подсмотреть в исходниках провайдера.
В остальном, можно смело брать примеры из репозитория и компилировать из них своё решение, HCL код там хороший и показать его потом будет не стыдно.
Печальный тренд на cancel culture не обошёл стороной и компанию Hashicorp. Выражается это в следующем: при запуске в терминале
terraform init
появляется сообщение об ошибке:
╷
│ Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/aws: could not connect to registry.terraform.io:
│ Failed to request discovery document: 403 Forbidden
╵
Тем не менее, существует несколько лазеек, позволяющих обойти такие ограничения. Первая и самая очевидная - использовать VPN с адресом где-нибудь за пределами подсанкционных стран.
Вторая - это завести свой собственный registry сервер для хостинга артефактов провайдеров. На данный момент, есть открытая спецификация Provider Registry Protocol, по которой можно самостоятельно реализовать сервер. Из готовых же opensource реализаций был найден только terralist, возможно со временем их будет появляться больше.
Третья лазейка - настроить терраформ на использование в качестве registry некую директорию на локальной машине, в которой положить заранее собранные\скачанные бинари провайдеров. В данном случае, понадобится два провайдера:
Подготавливаем terraform:
Создаём конфиг для терраформа /home/user/.terraformrc
с путями до директории с бинарями провайдеров:
provider_installation {
filesystem_mirror {
path = "/home/user/tfproviders"
}
}
disable_checkpoint = true
Создаём директории, где терраформ будет их искать:
$ mkdir -p ~/tfproviders/registry.terraform.io
Скаченные бинари по ссылкам выше раскладываем в следующие места (кто на MacOS - повнимательней с названием платформы и путями $HOME, кто на Windows - пожалуйста, перестаньте использовать эту систему):
/home/user/tfproviders/registry.terraform.io/hashicorp/local/2.2.2/linux_amd64/terraform-provider-local_v2.2.2_x5
/home/user/tfproviders/registry.terraform.io/sbercloud-terraform/sbercloud/1.10.0/linux_amd64/terraform-provider-sbercloud_v1.10.0
Теперь terraform init
отработает корректно можно будет двигаться дальше.
Все переменные, использующиеся в HCL коде будут определены отдельно.
Начнём с создания VPC, подсетей и правил безопасности, потом бастион и, наконец, сам кластер k8s.
resource "sbercloud_vpc" "vpc" {
name = var.vpc_name
cidr = var.vpc_cidr
tags = var.tags
}
resource "sbercloud_vpc_subnet" "subnet" {
name = var.subnet_name
cidr = var.subnet_cidr
gateway_ip = var.subnet_gateway_ip
primary_dns = var.subnet_dns1
secondary_dns = var.subnet_dns2
vpc_id = sbercloud_vpc.vpc.id
tags = var.tags
}
locals {
default_rules = {
http-rule = {
description = "Allow HTTP from anywhere",
protocol = "tcp",
port = 80,
source = "0.0.0.0/0"
},
https-rule = {
description = "Allow HTTPS from anywhere",
protocol = "tcp",
port = 443,
source = "0.0.0.0/0"
},
ssh-rule = {
description = "Allow SSH from anywhere",
protocol = "tcp",
port = 22,
source = "0.0.0.0/0"
}
}
}
resource "sbercloud_networking_secgroup" "sg_default" {
name = var.default_security_group_name
description = "Default security group"
}
resource "sbercloud_networking_secgroup_rule" "default_ingress_icmp" {
direction = "ingress"
ethertype = "IPv4"
description = "Allow ICMP from anywhere"
protocol = "icmp"
remote_ip_prefix = "0.0.0.0/0"
security_group_id = sbercloud_networking_secgroup.sg_default.id
}
resource "sbercloud_networking_secgroup_rule" "default_ingress" {
for_each = local.default_rules
direction = "ingress"
ethertype = "IPv4"
description = each.value.description
protocol = each.value.protocol
port_range_min = each.value.port
port_range_max = each.value.port
remote_ip_prefix = each.value.source
security_group_id = sbercloud_networking_secgroup.sg_default.id
}
resource "sbercloud_compute_instance" "bastion" {
name = var.hostname
image_id = var.ecs_image_id
flavor_id = var.ecs_flavor
security_groups = [var.default_security_group_name]
availability_zone = var.vpc_az
key_pair = var.keypair_name
system_disk_type = var.ecs_system_disk_type
system_disk_size = var.ecs_system_disk_size
# инстансы в SberCloud поддерживают cloud-init
user_data = file("${path.module}/setup.sh")
tags = var.tags
network {
uuid = var.subnet_id
}
}
resource "sbercloud_vpc_eip" "bastion_eip" {
tags = var.tags
publicip {
type = "5_bgp"
}
bandwidth {
name = "elb-bastion-bandwidth"
size = var.bandwidth_size
share_type = "PER"
charge_mode = var.bandwidth_charge_mode
}
}
resource "sbercloud_compute_eip_associate" "associated_01" {
public_ip = sbercloud_vpc_eip.bastion_eip.address
instance_id = sbercloud_compute_instance.bastion.id
}
resource "sbercloud_cce_cluster" "default" {
name = var.cce_cluster_name
flavor_id = var.cce_flavor
container_network_type = "overlay_l2"
container_network_cidr = var.subnet_cidr
multi_az = false
vpc_id = var.vpc_id
subnet_id = var.subnet_id
}
resource "sbercloud_cce_node_pool" "default" {
cluster_id = sbercloud_cce_cluster.default.id
name = var.cce_nodepool_name
flavor_id = var.cce_node_flavor
availability_zone = var.vpc_az
key_pair = var.keypair_name
scall_enable = true
min_node_count = 1
initial_node_count = 1
max_node_count = var.max_node_count
scale_down_cooldown_time = 100
priority = 1
type = "vm"
os = "CentOS 7.6"
tags = var.tags
root_volume {
size = 50
volumetype = "SAS"
}
data_volumes {
size = 100
volumetype = "SAS"
}
}
resource "local_file" "kubeconfig" {
depends_on = [sbercloud_cce_cluster.default]
filename = "./kubeconfig"
# А вот тут нам и пригодился провайдер local - он нам сгенерит конфиг для kubectl
content = sbercloud_cce_cluster.default.kube_config_raw
}
На данном этапе мы подготовили примерный код, который можно аккуратно разложить по директориями и запустить
terraform apply
, после чего можно заходить по ssh на бастион и полноценно работать с кластером k8s (не забыв забрать
сгенерённый kubeconfig). Готовый к использованию код можно найти тут.
Подробнее про варианты конфигурации ресурсов в SberCloud можно почитать в
документации.