Terraform项目的.gitlab-ci.yml模板

你好。

我們在GitLab上管理Terraform的代碼,所以現在談談我們創建的.gitlab-ci.yml文件。

本篇文章的动机是因为我觉得如果能够在每个环境中使用terraform plan和terraform apply,就可以满足基本的持续集成功能,并且可能还可以实现模板化。

.gitlab-ci.yml是什么?

GitLab Runner使用的文件,用于管理项目的作业。
将其放置在项目的根目录中,即可设置CI。

项目结构

在这个简单的项目中,我们启动 VPC 并在其中创建两台 EC2 作为开发和生产环境。我们将使用 vpc/example.tf 文件定义 VPC,并使用 environment/example.tf 文件来管理 EC2 的 terraform 代码。

将 .gitlab-ci.yml 文件放置在项目的根目录中。

├── environment
│   ├── example.tf
├── vpc
│     └── example.tf
├──.gitlab-ci.yml

用于terraform的代码

vpc/例子.tf

这是用于 VPC 构建的 Terraform 代码。

locals {
  name = "tf-for-gitlab"
}

terraform {
  backend "s3" {
    bucket = "t-horikoshi-bucket"
    key    = "example.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  tags {
    Name = "${local.name}"
  }
}

resource "aws_security_group" "example" {
  name        = "${local.name}"
  vpc_id      = "${aws_vpc.example.id}"
  tags {
    Name = "${local.name}"
  }
}

output "security-group-ids" {
  value = ["${aws_security_group.example.id}"]
}

output "vpc_id" {
  value = "${aws_vpc.example.id}"
}

在创建 EC2 实例时,需要 VPC 的相关信息,因此将 VPC 的 ID 和安全组 ID 作为输出,输出到 example.tfstate 文件中。

在backend上指定了tfstate文件保存在S3上的信息。(请先假设S3存储桶已经事先创建。)

环境/示例.tf

以下是使用 Terraform 的代码来在 VPC 中启动 EC2 实例。

locals {
  stage  = "${terraform.workspace == "prod" ? "prod" : "dev"}"
}

data "terraform_remote_state" "example" {
  backend = "s3"
  config {
    bucket = "t-horikoshi-bucket"
    key = "example.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_subnet" "example-a" {
  cidr_block = "10.0.1.0/24"
  vpc_id = "${data.terraform_remote_state.example.vpc_id}"
  tags {
    Name = "example-a"
  }
}

resource "aws_instance" "example" {
  ami = "${var.ami}"
  instance_type = "t2.micro"
  subnet_id = "${aws_subnet.example-a.id}"
  vpc_security_group_ids = ["${data.terraform_remote_state.example.security-group-ids}"]
  tags {
    Name = "tf-for-gitlab-${local.stage}"
  }
}

variable "ami" {
  type ="string"
  default = "ami-0a2de1c3b415889d2"
}

这次我们将使用 terraform workspace 来实现 dev 和 prod 两个环境的划分。
我们将通过读取 locals 的 stage 变量来选择工作空间。

为了能够读取在之前创建 VPC 时设置的 S3 和 tfstate 文件的信息,将其配置。

将aws_subnet中的vpc_id和aws_instance中的security-group-ids分别进行配置。

.gitlab-ci.yml 的中文翻译如下:

image:
  name: hashicorp/terraform:0.11.11
  entrypoint: [""]

.artifacts: &artifacts
  paths:
    - 'vpc/.terraform'
    - 'environment/.terraform'

stages:
  - fmt
  - init
  - plan
  - apply

fmt:
  stage: fmt
  script:
    - cd vpc && terraform fmt -check=true
    - cd ../environment && terraform fmt -check=true

init:
  stage: init
  script:
    - cd vpc && terraform init
    - cd ../environment && terraform init
  artifacts: *artifacts

plan_vpc:
  stage: plan
  script:
    - cd vpc && terraform plan
  artifacts: *artifacts

.plan_env_job: &plan_env_job
  stage: plan
  script:
    - cd environment
    - terraform workspace new $ENV && terraform workspace select $ENV && terraform plan
  artifacts: *artifacts

plan_env_dev:
   <<: *plan_env_job
   variables:
     ENV: dev

plan_env_prod:
  <<: *plan_env_job
  variables:
    ENV: prod

apply_vpc:
  stage: apply
  script:
    - cd vpc && terraform apply -auto-approve
  when: manual
  artifacts: *artifacts
  only:
    - master

.apply_env_job: &apply_env_job
  stage: apply
  script:
    - cd environment
    - terraform workspace select $ENV && terraform apply -auto-approve
  when: manual
  artifacts: *artifacts

apply_env dev:
  <<: *apply_env_job
  variables:
    ENV: dev

apply_env prod:
  <<: *apply_env_job
  variables:
    ENV: prod
  only:
    - master

从下面开始,我们将详细查看。

图片
image:
  name: hashicorp/terraform:0.11.11
  entrypoint: [""]

指定 HashiCorp 管理的 Docker 镜像。

默认情况下,entrypoint 指定了 terraform,因此无法在容器内运行 Pipeline 的工作。因此,我们需要进行覆盖。

由于Terraform更新迅速,建议指定版本。

艺术品
.artifacts: &artifacts
  paths:
    - 'vpc/.terraform'
    - 'environment/.terraform'

这是为了使 vpc 和 environment 的成果在 stage 之间可以被使用而进行的设置。我们指定了 terraform init 和 terraform apply 之后的成果物将被输出到 .terraform 目录中。

阶段
stages:
  - fmt
  - init
  - plan
  - apply

在Pipeline中设置每个阶段。
这是terraform项目,所以它的结构是fmt > init > plan > apply。

格式化
fmt:
  stage: fmt
  script:
    - cd vpc && terraform fmt -check=true
    - cd ../environment && terraform fmt -check=true

这个阶段是用来检查Terraform代码格式的。
我们通过使用-check=true来确保如果有格式问题,会使其失败。

开始
init:
  stage: init
  script:
    - cd vpc && terraform init
    - cd ../environment && terraform init
  artifacts: *artifacts

这是一个用于初始化 VPC 和环境的 stage。

计划
plan_vpc:
  stage: plan
  script:
    - cd vpc && terraform plan
  artifacts: *artifacts

.plan_env_job: &plan_env_job
  stage: plan
  script:
    - cd environment
    - terraform workspace new $ENV || terraform workspace select $ENV && terraform plan
  artifacts: *artifacts

plan_env_dev:
   <<: *plan_env_job
   variables:
     ENV: dev

plan_env_prod:
  <<: *plan_env_job
  variables:
    ENV: prod

此阶段正在执行terraform plan。

由于只有一个vpc,所以只有一个作业。但是在环境中,我们希望将开发和生产环境分开建立。因此,我们定义了plan_env_dev和plan_env_prod两个作业。

通过使用YAML锚点功能,创建了一个名为.plan_env_job的共享工作。
使用ENV使每个工作区能够执行工作。

申请
apply_vpc:
  stage: apply
  script:
    - cd vpc && terraform apply -auto-approve
  when: manual
  artifacts: *artifacts
  only:
    - master

.apply_env_job: &apply_env_job
  stage: apply
  script:
    - cd environment
    - terraform workspace select $ENV && terraform apply -auto-approve
  when: manual
  artifacts: *artifacts

apply_env dev:
  <<: *apply_env_job
  variables:
    ENV: dev

apply_env prod:
  <<: *apply_env_job
  variables:
    ENV: prod
  only:
    - master

基本上,環境分為不同部分並且使用錨點定義作業等,與計劃的機制相同。

当运行 terraform apply 时,实际的配置将会开始部署,为了手动执行,我们使用了 when: manual 指令。

另外,我們限定了只能在主分支(master)上執行工作並指定了 “only”。

在Gitlab中设置环境变量。

因为不希望将 AWS 凭证等安全信息提交到代码中,所以将其配置到 Gitlab 的环境变量中。

スクリーンショット 2018-12-15 17.33.03.png

已完成的工作流程

将此前的代码推送到 git 仓库后,会创建如下所示的 Pipeline。

スクリーンショット 2018-12-15 17.45.08.png

总结

這次介紹的 Gitlab 的 CI/CD 功能還只是初步接觸而已。因為還有其他看起來很實用的功能,所以希望可以善用並掌握。

另外,手动管理基础设施的麻烦是众所周知的事实,但是如果有代码管理,就会感到放心。

那么,请享受基础设施即代码吧!

广告
将在 10 秒后关闭
bannerAds