Управляйте OpenStack с помощью Terraform и GitLab
Следуйте этому руководству, чтобы узнать, как использование GitLab может еще больше улучшить совместную работу в вашем кластере OpenStack.
Одним из достоинств GitOps является инфраструктура как код. Это поощряет сотрудничество за счет использования общего хранилища конфигурации и политик. Использование GitLab может еще больше улучшить совместную работу в вашем кластере OpenStack. GitLab CI может служить центром управления исходным кодом и оркестрации для CI/CD и даже управлять состоянием Terraform.
Чтобы добиться этого, вам необходимо следующее:
- Учетная запись или экземпляр GitLab.
- Частный кластер OpenStack. Если у вас его нет, прочитайте мою статью «Настройка OpenStack в кластере Raspberry Pi».
- Компьютер (желательно хост-контейнер).
Состояние GitLab и Terraform
Цель состоит в том, чтобы добиться совместной работы с помощью Terraform, поэтому вам необходимо иметь централизованный файл состояния. В GitLab есть управляемое состояние для Terraform. С помощью этой функции вы можете предоставить отдельным пользователям возможность совместно управлять OpenStack.
Создайте группу и проект GitLab.
Войдите в GitLab, щелкните меню гамбургера и выберите Группы → Просмотреть все группы.
(Эй Джей Канлас, CC BY-SA 4.0)
Создайте группу, нажав Новая группа, а затем Создать группу.
(Эй Джей Канлас, CC BY-SA 4.0)
Назовите группу, чтобы создать уникальный URL-адрес группы, и пригласите свою команду работать с вами.
(Эй Джей Канлас, CC BY-SA 4.0)
После создания группы создайте проект, нажав Создать новый проект, а затем Создать пустой проект:
(Эй Джей Канлас, CC BY-SA 4.0)
Назовите свой проект. GitLab генерирует для вас уникальный URL-адрес проекта. Этот проект содержит репозиторий для ваших скриптов Terraform и состояния Terraform.
Создайте токен личного доступа
Репозиторию необходим личный токен доступа для управления этим состоянием Terraform. В своем профиле выберите Редактировать профиль:.
(Эй Джей Канлас, CC BY-SA 4.0)
Нажмите Токен доступа на боковой панели, чтобы открыть меню для создания токена доступа. Сохраните свой токен, потому что вы не сможете просмотреть его снова.
(Эй Джей Канлас, CC BY-SA 4.0)
Клонировать пустой репозиторий
На компьютере с прямым доступом к вашей установке OpenStack клонируйте репозиторий, а затем перейдите в полученный каталог:
$ git clone git@gitlab.com:testgroup2170/testproject.git
$ cd testproject
Создайте серверный файл .tf и файл поставщика.
Создайте бэкэнд-файл, чтобы настроить GitLab в качестве бэкэнда вашего состояния:
$ cat >> backend.tf << EOF
terraform {
backend "http" {
}
}
EOF
Этот файл провайдера извлекает провайдера для OpenStack:
$ cat >> provider.tf << EOF
terraform {
required_version = ">= 0.14.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "1.49.0"
}
}
}
provider "openstack" {
user_name = var.OS_USERNAME
tenant_name = var.OS_TENANT
password = var.OS_PASSWORD
auth_url = var.OS_AUTH_URL
region = var.OS_REGION
}
EOF
Поскольку вы объявили переменную в поставщике, вы должны объявить ее в файле переменных:
$ cat >> variables.tf << EOF
variable "OS_USERNAME" {
type = string
description = "OpenStack Username"
}
variable "OS_TENANT" {
type = string
description = "OpenStack Tenant/Project Name"
}
variable "OS_PASSWORD" {
type = string
description = "OpenStack Password"
}
variable "OS_AUTH_URL" {
type = string
description = "OpenStack Identitiy/Keystone API for authentication"
}
variable "OS_REGION" {
type = string
description = "OpenStack Region"
}
EOF
Поскольку изначально вы работаете локально, вам необходимо установить эти переменные, чтобы все работало:
$ cat >> terraform.tfvars << EOF
OS_USERNAME = "admin"
OS_TENANT = "admin"
OS_PASSWORD = "YYYYYYYYYYYYYYYYYYYYYY"
OS_AUTH_URL = "http://X.X.X.X:35357/v3"
OS_REGION = "RegionOne"
EOF
Эти сведения доступны в вашем файле rc
на OpenStack.
Инициализируйте проект в Terraform
Инициализация проекта совершенно другая, потому что вам нужно указать Terraform использовать GitLab в качестве бэкэнда вашего состояния:
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_STATE_NAME="<your-unique-state-name>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/${TF_STATE_NAME}"
$ terraform init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Чтобы просмотреть gitlab-project-id
, просмотрите сведения о проекте чуть выше вкладки Информация о проекте на боковой панели. Обычно это название вашего проекта.
(Эй Джей Канлас, CC BY-SA 4.0)
Для меня это 42580143
.
Используйте свое имя пользователя для gitlab-username
. Мой — ajohnsc
.
gitlab-personal-access-token
— это токен, который вы создали ранее в этом упражнении. В этом примере я использую wwwwwwwwwwwwwwwwww
. Вы можете назвать ваше-уникальное-имя-состояния
как угодно. Я использовал homelab
.
Вот мой скрипт инициализации:
PROJECT_ID="42580143"
TF_USERNAME="ajohnsc"
TF_PASSWORD="wwwwwwwwwwwwwwwwwwwww"
TF_STATE_NAME="homelab"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/${TF_STATE_NAME}"
Чтобы использовать файл:
$ terraform init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Вывод аналогичен этому:
(Эй Джей Канлас, CC BY-SA 4.0)
Проверьте скрипт Terraform
Это устанавливает размер виртуальных машин для моих версий OpenStack:
$ cat >> flavors.tf << EOF
resource "openstack_compute_flavor_v2" "small-flavor" {
name = "small"
ram = "4096"
vcpus = "1"
disk = "0"
flavor_id = "1"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "medium-flavor" {
name = "medium"
ram = "8192"
vcpus = "2"
disk = "0"
flavor_id = "2"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "large-flavor" {
name = "large"
ram = "16384"
vcpus = "4"
disk = "0"
flavor_id = "3"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "xlarge-flavor" {
name = "xlarge"
ram = "32768"
vcpus = "8"
disk = "0"
flavor_id = "4"
is_public = "true"
}
EOF
Настройки моей внешней сети следующие:
$ cat >> external-network.tf << EOF
resource "openstack_networking_network_v2" "external-network" {
name = "external-network"
admin_state_up = "true"
external = "true"
segments {
network_type = "flat"
physical_network = "physnet1"
}
}
resource "openstack_networking_subnet_v2" "external-subnet" {
name = "external-subnet"
network_id = openstack_networking_network_v2.external-network.id
cidr = "10.0.0.0/8"
gateway_ip = "10.0.0.1"
dns_nameservers = ["10.0.0.254", "10.0.0.253"]
allocation_pool {
start = "10.0.0.2"
end = "10.0.254.254"
}
}
EOF
Настройки роутера выглядят так:
$ cat >> routers.tf << EOF
resource "openstack_networking_router_v2" "external-router" {
name = "external-router"
admin_state_up = true
external_network_id = openstack_networking_network_v2.external-network.id
}
EOF
Введите следующее для изображений:
$ cat >> images.tf << EOF
resource "openstack_images_image_v2" "cirros" {
name = "cirros"
image_source_url = "https://download.cirros-cloud.net/0.6.1/cirros-0.6.1-x86_64-disk.img"
container_format = "bare"
disk_format = "qcow2"
}
EOF
Вот демонстрационный арендатор:
$ cat >> demo-project-user.tf << EOF
resource "openstack_identity_project_v3" "demo-project" {
name = "Demo"
}
resource "openstack_identity_user_v3" "demo-user" {
name = "demo-user"
default_project_id = openstack_identity_project_v3.demo-project.id
password = "demo"
}
EOF
По завершении у вас будет следующая файловая структура:
.
├── backend.tf
├── demo-project-user.tf
├── external-network.tf
├── flavors.tf
├── images.tf
├── provider.tf
├── routers.tf
├── terraform.tfvars
└── variables.tf
План выпуска
После того, как файлы будут готовы, вы можете создать файлы планов с помощью команды terraform plan
:
$ terraform plan
Acquiring state lock. This may take a few moments...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# openstack_compute_flavor_v2.large-flavor will be created
+ resource "openstack_compute_flavor_v2" "large-flavor" {
+ disk = 0
+ extra_specs = (known after apply)
+ flavor_id = "3"
+ id = (known after apply)
+ is_public = true
+ name = "large"
+ ram = 16384
+ region = (known after apply)
+ rx_tx_factor = 1
+ vcpus = 4
}
[...]
Plan: 10 to add,
Releasing state lock. This may take a few moments...
После создания всех файлов планов примените их с помощью команды terraform apply
:
$ terraform apply -auto-approve
Acquiring state lock. This may take a few moments...
[...]
Plan: 10 to add, 0 to change, 0 to destroy.
openstack_compute_flavor_v2.large-flavor: Creating...
openstack_compute_flavor_v2.small-flavor: Creating...
openstack_identity_project_v3.demo-project: Creating...
openstack_networking_network_v2.external-network: Creating...
openstack_compute_flavor_v2.xlarge-flavor: Creating...
openstack_compute_flavor_v2.medium-flavor: Creating...
openstack_images_image_v2.cirros: Creating...
[...]
Releasing state lock. This may take a few moments...
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
После применения инфраструктуры вернитесь в GitLab и перейдите к своему проекту. Откройте Инфраструктура → Terraform, чтобы убедиться, что состояние homelab
создано.
(Эй Джей Канлас, CC BY-SA 4.0)
Уничтожьте состояние, чтобы проверить CI
Теперь, когда вы создали состояние, попробуйте уничтожить инфраструктуру, чтобы позже можно было применить конвейер CI. Конечно, это исключительно для перехода от Terraform CLI к конвейеру. Если у вас есть существующая инфраструктура, вы можете пропустить этот шаг.
$ terraform destroy -auto-approve
Acquiring state lock. This may take a few moments...
openstack_identity_project_v3.demo-project: Refreshing state... [id=5f86d4229003404998dfddc5b9f4aeb0]
openstack_networking_network_v2.external-network: Refreshing state... [id=012c10f3-8a51-4892-a688-aa9b7b43f03d]
[...]
Plan: 0 to add, 0 to change, 10 to destroy.
openstack_compute_flavor_v2.small-flavor: Destroying... [id=1]
openstack_compute_flavor_v2.xlarge-flavor: Destroying... [id=4]
openstack_networking_router_v2.external-router: Destroying... [id=73ece9e7-87d7-431d-ad6f-09736a02844d]
openstack_compute_flavor_v2.large-flavor: Destroying... [id=3]
openstack_identity_user_v3.demo-user: Destroying... [id=96b48752e999424e95bc690f577402ce]
[...]
Destroy complete! Resources: 10 destroyed.
Теперь у вас есть состояние, которое может использовать каждый. Вы можете обеспечить использование централизованного состояния. При наличии правильного конвейера вы можете автоматизировать типичные задачи.
Настройте бегун GitLab
Ваш кластер OpenStack не является общедоступным, и API OpenStack не доступен. Для запуска конвейеров GitLab у вас должен быть исполнитель GitLab. Исполнители GitLab — это службы или агенты, которые запускают и выполняют задачи на удаленном сервере GitLab.
На компьютере в другой сети создайте контейнер для запуска GitLab:
$ docker volume create gitlab-runner-config
$ docker run -d --name gitlab-runner --restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v gitlab-runner-config:/etc/gitlab-runner \
gitlab/gitlab-runner:latest
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
880e2ed289d3 gitlab/gitlab-runner:latest "/usr/bin/dumb-init …" 3 seconds ago Up 2 seconds gitlab-runner-test
Теперь зарегистрируйте его в своем проекте на панели Настройки → CI/CD вашего проекта GitLab:
(Эй Джей Канлас, CC BY-SA 4.0)
Прокрутите вниз до пункта Бегуны → Свернуть:
(Эй Джей Канлас, CC BY-SA 4.0)
Требуется регистрационный токен и URL-адрес участника GitLab. Отключите общий бегун справа, чтобы убедиться, что он работает только на бегуне. Запустите контейнер gitlab-runner
, чтобы зарегистрировать бегуна:
$ docker exec -ti gitlab-runner /usr/bin/gitlab-runner register
Runtime platform arch=amd64 os=linux pid=18 revision=6d480948 version=15.7.1
Running in system-mode.
Enter the GitLab instance URL (for example, https://gitlab.com/):
https://gitlab.com/
Enter the registration token:
GR1348941S1bVeb1os44ycqsdupRK
Enter a description for the runner:
[880e2ed289d3]: dockerhost
Enter tags for the runner (comma-separated):
homelab
Enter optional maintenance note for the runner:
WARNING: Support for registration tokens and runner parameters in the 'register' command has been deprecated in GitLab Runner 15.6 and will be replaced with support for authentication tokens. For more information, see https://gitlab.com/gitlab-org/gitlab/-/issues/380872
Registering runner... succeeded runner=GR1348941S1bVeb1o
Enter an executor: docker-ssh, shell, virtualbox, instance, kubernetes, custom, docker, parallels, ssh, docker+machine, docker-ssh+machine:
docker
Enter the default Docker image (for example, ruby:2.7):
ajscanlas/homelab-runner:3.17
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml"
В случае успеха ваш интерфейс GitLab отобразит ваш бегун как действительный. Это выглядит так:
(Эй Джей Канлас, CC BY-SA 4.0)
Теперь вы можете использовать этот бегун для автоматизации подготовки с помощью конвейера CI/CD в GitLab.
Настройте конвейер GitLab
Теперь вы можете настроить конвейер. Добавьте файл с именем .gitlab-ci.yaml
в свой репозиторий, чтобы определить шаги CI/CD. Игнорируйте ненужные файлы, например каталоги .terraform
, и конфиденциальные данные, такие как файлы переменных.
Вот мой файл .gitignore
:
$ cat .gitignore
*.tfvars
.terraform*
Вот мои записи конвейера CI в .gitlab-ci.yaml
:
$ cat .gitlab-ci.yaml
default:
tags:
- homelab
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/homelab
cache:
key: homelab
paths:
- ${TF_ROOT}/.terraform*
stages:
- prepare
- validate
- build
- deploy
before_script:
- cd ${TF_ROOT}
tf-init:
stage: prepare
script:
- terraform --version
- terraform init -backend-config=address=${BE_REMOTE_STATE_ADDRESS} -backend-config=lock_address=${BE_REMOTE_STATE_ADDRESS}/lock -backend-config=unlock_address=${BE_REMOTE_STATE_ADDRESS}/lock -backend-config=username=${BE_USERNAME} -backend-config=password=${BE_ACCESS_TOKEN} -backend-config=lock_method=POST -backend-config=unlock_method=DELETE -backend-config=retry_wait_min=5
tf-validate:
stage: validate
dependencies:
- tf-init
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform validate
tf-build:
stage: build
dependencies:
- tf-validate
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform plan -out "planfile"
artifacts:
paths:
- ${TF_ROOT}/planfile
tf-deploy:
stage: deploy
dependencies:
- tf-build
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform apply -auto-approve "planfile"
Процесс начинается с объявления того, что каждый шаг и этап находятся под тегом homelab
, что позволяет вашему исполнителю GitLab запустить его.
default:
tags:
- homelab
Далее переменные устанавливаются в конвейер. Переменные присутствуют только во время работы конвейера:
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/homelab
Существует кеш, который сохраняет определенные файлы и каталоги при переходе от этапа к этапу:
cache:
key: homelab
paths:
- ${TF_ROOT}/.terraform*
Вот этапы, которым следует конвейер:
stages:
- prepare
- validate
- build
- deploy
Здесь объявляется, что делать перед запуском каких-либо этапов:
before_script:
- cd ${TF_ROOT}
На этапе prepare
tf-init
инициализирует сценарии Terraform, получает поставщика и устанавливает для его серверной части GitLab. Переменные, которые еще не объявлены, добавляются как переменные среды позже.
tf-init:
stage: prepare
script:
- terraform --version
- terraform init -backend-config=address=${BE_REMOTE_STATE_ADDRESS} -backend-config=lock_address=${BE_REMOTE_STATE_ADDRESS}/lock -backend-config=unlock_address=${BE_REMOTE_STATE_ADDRESS}/lock -backend-config=username=${BE_USERNAME} -backend-config=password=${BE_ACCESS_TOKEN} -backend-config=lock_method=POST -backend-config=unlock_method=DELETE -backend-config=retry_wait_min=5
В этой части задание CI tf-validate
и этап validate
запускают Terraform для проверки отсутствия синтаксических ошибок в сценариях Terraform. Еще не объявленные переменные добавляются как переменные среды позже.
tf-validate:
stage: validate
dependencies:
- tf-init
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform validate
Затем задание CI tf-build
на этапе build
создает файл плана, используя terraform plan
, и временно сохраняет его, используя артефакты. тег
.
tf-build:
stage: build
dependencies:
- tf-validate
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform plan -out "planfile"
artifacts:
paths:
- ${TF_ROOT}/planfile
В следующем разделе задание CI tf-deploy
с этапом deploy
применяет файл плана.
tf-deploy:
stage: deploy
dependencies:
- tf-build
variables:
TF_VAR_OS_AUTH_URL: ${OS_AUTH_URL}
TF_VAR_OS_PASSWORD: ${OS_PASSWORD}
TF_VAR_OS_REGION: ${OS_REGION}
TF_VAR_OS_TENANT: ${OS_TENANT}
TF_VAR_OS_USERNAME: ${OS_USERNAME}
script:
- terraform apply -auto-approve "planfile"
Существуют переменные, поэтому их необходимо объявить в Настройки → CI/CD → Переменные → Развернуть.
(Эй Джей Канлас, CC BY-SA 4.0)
Добавьте все необходимые переменные:
BE_ACCESS_TOKEN => GitLab Access Token
BE_REMOTE_STATE_ADDRESS => This was the rendered TF_ADDRESS variable
BE_USERNAME => GitLab username
OS_USERNAME => OpenStack Username
OS_TENANT => OpenStack tenant
OS_PASSWORD => OpenStack User Password
OS_AUTH_URL => Auth URL
OS_REGION => OpenStack Region
Итак, для этого примера я использовал следующее:
BE_ACCESS_TOKEN = "wwwwwwwwwwwwwwwwwwwww"
BE_REMOTE_STATE_ADDRESS = https://gitlab.com/api/v4/projects/42580143/terraform/state/homelab
BE_USERNAME = "ajohnsc"
OS_USERNAME = "admin"
OS_TENANT = "admin"
OS_PASSWORD = "YYYYYYYYYYYYYYYYYYYYYY"
OS_AUTH_URL = "http://X.X.X.X:35357/v3"
OS_REGION = "RegionOne"
И для защиты он замаскирован GitLab.
(Эй Джей Канлас, CC BY-SA 4.0)
Последний шаг — отправить новые файлы в репозиторий:
$ git add .
$ git commit -m "First commit"
[main (root-commit) e78f701] First commit
10 files changed, 194 insertions(+)
create mode 100644 .gitignore
create mode 100644 .gitlab-ci.yml
create mode 100644 backend.tf
create mode 100644 demo-project-user.tf
create mode 100644 external-network.tf
create mode 100644 flavors.tf
create mode 100644 images.tf
create mode 100644 provider.tf
create mode 100644 routers.tf
create mode 100644 variables.tf
$ git push
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 4 threads
Compressing objects: 100% (10/10), done.
Writing objects: 100% (12/12), 2.34 KiB | 479.00 KiB/s, done.
Total 12 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.com:testgroup2170/testproject.git
* [new branch] main -> main
Посмотреть результаты
Просмотрите свои новые конвейеры в разделе CI/CD на GitLab.
(Эй Джей Канлас, CC BY-SA 4.0)
На стороне OpenStack вы можете увидеть ресурсы, созданные Terraform.
Сети:
(Эй Джей Канлас, CC BY-SA 4.0)
Вкусы:
(Эй Джей Канлас, CC BY-SA 4.0)
Изображения:
(Эй Джей Канлас, CC BY-SA 4.0)
Проект:
(Эй Джей Канлас, CC BY-SA 4.0)
Пользователь:
(Эй Джей Канлас, CC BY-SA 4.0)
Следующие шаги
У Terraform огромный потенциал. Terraform и Ansible отлично сочетаются друг с другом. В моей следующей статье я продемонстрирую, как Ansible может работать с OpenStack.