用Terraform和GitLab管理OpenStack

GitOps的一个优点是基础设施即代码。它通过使用共享配置和策略存储库来鼓励协作。使用GitLab可以进一步增强OpenStack集群中的协作。GitLab CI可以作为CI/CD的源代码控制和编排中心,甚至可以管理Terraform的状态。

要做到这一点,你需要以下几点:

——GitLab账户或实例。

——私有OpenStack集群。

——计算机(最好是容器主机)。

GitLab和Terraform状态

目标是通过Terraform实现协作,因此需要有一个集中的状态文件。GitLab具有Terraform的托管状态。使用此功能,你可以让个人协作管理OpenStack。

创建GitLab组和项目

登录GitLab,单击菜单,然后单击Groups→View all groups。

cb60224cfe3dff579ab375dc34fedc83.jpeg

单击New group,然后单击Create group来创建组。

7d846d8885ef9a0eef30604d1928465e.jpeg

为组命名以生成唯一的组URL,并邀请团队与你一起工作。

827c29be7942b54bc7d11e536a2702f6.jpeg

创建组后,单击“Create new project”,然后单击“Create blank project”,创建项目:

acaf6a86258db8b342400186698a25e1.jpeg

为项目命名。GitLab为你生成一个唯一的项目URL。这个项目包含Terraform脚本和Terraform状态的存储库。

创建个人访问令牌

存储库需要一个个人访问令牌来管理这个Terraform状态。在你的个人资料中,选择Edit Profile:

6484cf43d3c873b361a1f4cfc00bd99b.jpeg

单击侧面板中的Access Token以访问用于创建访问令牌的菜单。保存令牌,因为你无法再次查看它。

7b22f693a2b3a916dd540d870e8b2a15.jpeg

克隆空存储库

在可以直接访问OpenStack安装的计算机上,克隆存储库,然后更改到生成的目录:

$ git clone git@gitlab.com:testgroup2170/testproject.git$ cd testproject

创建backend.tf和provider文件

创建一个后端文件,将GitLab配置为你的状态后端:

$ cat >> backend.tf << EOFterraform {  backend "http" {  } } EOF

此provider文件为OpenStack拉取provider:

$ cat >> provider.tf << EOFterraform {  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

因为你在provider中声明了一个变量,所以必须在变量文件中声明它:

$ cat >> variables.tf << EOFvariable "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 << EOFOS_USERNAME = "admin" OS_TENANT   = "admin" OS_PASSWORD = "YYYYYYYYYYYYYYYYYYYYYY" OS_AUTH_URL = "http://X.X.X.X:35357/v3" OS_REGION   = "RegionOne" EOF

这些详细信息可在OpenStack上的rc文件中找到。

在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,请查看侧面板“Project Information”选项卡上方的项目详细信息。通常是项目名称。

926cca36645ed178bfd8140ebd8ac56b.jpeg

对笔者来说,是42580143。

使用你的用户名作为gitlab用户名。笔者的是ajohnsc。

gitlab-personal-access-token是你在本练习之前创建的令牌。在本例中,笔者使用wwwwwwww。你可以将your-unique-state-name命名为任何名称。笔者用的是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

输出类似于:

40013d1130dac34572085294d25d01d1.jpeg

测试Terraform脚本

以下为笔者的OpenStack风格设置了VM的大小:

$ cat >> flavors.tf << EOFresource "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 << EOFresource "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 << EOFresource "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 << EOFresource "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

以下是Demo租户:

$ cat >> demo-project-user.tf << EOFresource "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 planAcquiring 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-approveAcquiring 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并导航到你的项目。查看Infrastructure→ Terraform确认已创建homelab状态。

e5dc3edfc548b908de706c810876dcda.jpeg

销毁状态以测试CI

现在你已经创建了一个状态,请尝试销毁基础设施,以便以后可以应用CI管道。当然,这纯粹是为了从Terraform CLI迁移到Pipeline。如果你有现有的基础设施,可以跳过此步骤。

$ terraform destroy -auto-approveAcquiring 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集群不是面向公众的,OpenStack API也没有公开。你必须有一个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 psCONTAINER 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

现在在GitLab项目的“Settings→ CI/CD”面板中将其注册到项目中:

29588021821b7e477178b83d30d1eec3.jpeg

向下滚动至Runners→ Collapse:

ae1ccdd91df4b74f06bf096b43a22d4e.jpeg

需要GitLab运行程序注册令牌和URL。禁用右侧的共享runner,以确保它仅在runner上运行。运行gitlab-runner容器以注册runner:

$ docker exec -ti gitlab-runner /usr/bin/gitlab-runner registerRuntime 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界面将显示你的runner为有效。它看起来像这样:

0a716d45444e7a0cbb8fcc07fc3b31f6.jpeg

现在,你可以使用该runner在GitLab中使用CI/CD管道自动调配。

设置GitLab管道

现在可以设置管道了。在存储库中添加名为.gitlab-ci.yaml的文件以定义ci/CD步骤。忽略不需要的文件,如.traform目录和敏感数据,如变量文件。

这是笔者的.gitignore文件:

$ cat .gitignore*.tfvars .terraform*

以下是.gitlab-CI.yaml中的CI管道条目:

$ cat .gitlab-ci.yamldefault:  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"

该过程首先声明每个步骤和阶段都在homeab标签下,允许GitLab runner运行它。

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脚本,获取provider,并将其后端设置为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创建计划文件,并使用artifacts标记临时保存它。

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"

存在变量,因此必须在“Settings→ CI/CD→ Varibles→ Expand”中声明它们:

28eee0d19badc4a92263744bc0318191.jpeg

添加所有必需的变量:

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。

733ea0625f3a66bd5ebf26adb65513e5.jpeg

最后一步是将新文件推送到存储库:

$ 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 pushEnumerating 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

查看结果

在GitLab的CI/CD部分查看新管道。

9aca648b3ee2a42f713ff63e0601dbc8.jpeg

在OpenStack方面,你可以看到Terraform创建的资源。

网络:

0e07c4c455176a9ba6ce73b4d069bc14.jpeg

flavors:

1eb231ae22b8def03938129b6798023c.jpeg

镜像:

7f818ed7b4a0bb6870388e62139cfc18.jpeg

项目:

a6d6d977d700dc4481bf69c5792f70fb.jpeg

用户:

2d4a4d4cc729f5699d13e0ea202f5d5c.jpeg

下一步

Terraform有很大的潜力。Terraform和Ansible一起用很棒。在下一篇文章中,笔者将演示Ansible如何使用OpenStack。

原文链接:

https://opensource.com/article/23/2/manage-openstack-using-terraform-and-gitlab

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值