Terraform 是 HashiCorp 公司旗下的 Provision Infrastructure 产品, 是 AWS APN Technology Partner 与 AWS DevOps Competency Partner。Terraform 是一个 IT 基础架构自动化编排工具,它的口号是“Write, Plan, and Create Infrastructure as Code”, 是一个“基础设施即代码”工具。
相比于直接使用 Yaml 文件管理 k8s 集群,虽然 yaml 文件也能版本控制,但是可能会存在如下问题:
资源删除/重命名 后,该如何自行执行更新?
以删除资源为例,可能需要通过执行 kubectl delete -f xxx.yaml
来执行删除,而使用 terraform 管理的话,就很简单: terraform apply
.
初始化 为了方便多人协作以及 CI,这里推荐使用 S3 作为 terraform backend,其他 backend 可以查看官方文档 .
以下配置包含了使用 aws s3 作为 state 的存储以及使用 dynamodb 作为 lock.
1 2 3 4 5 6 7 8 9 10 terraform { backend "s3" { bucket = "bucket" key = "k8s/terraform.tfstate" region = "ap-northeast-1" dynamodb_table = "k8s" profile = "profile" } }
配置 k8s provider k8s provider 配置比较简单,只需要配置 kube config 的路径:
1 2 3 provider "kubernetes" { config_path = "~/.kube/xxx" }
如果需要同时管理 Helm,可以同时添加配置:
1 2 3 4 5 provider "helm" { kubernetes { config_path = "~/.kube/xxx" } }
管理资源 通过 Terraform 管理 k8s 资源,在官方文档 已经很详细了,这里我列举几个常见用法.
Secret 以 secret 资源为例,常常需要配置不少不适合提交到代码仓库中的敏感信息,通过 Terraform 我们可以通过参数的形式传入变量,将敏感信息保存在执行跳板机/运维人员本地,来避免提交敏感信息到代码仓库。
以下为配置案例,首先,定义变量:
1 2 3 variable "AWS_SECRET_KEY" { description = "AWS_SECRET_KEY" }
在使用 secret 的地方引用变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 resource "kubernetes_secret" "aws" { metadata { name = "aws" namespace = "prod" } data = { AWS_ACCESS_KEY = var.AWS_ACCESS_KEY AWS_SECRET_KEY = var.AWS_SECRET_KEY } type = "Opaque" }
通过文件存储变量,创建文件/etc/terraform/prod.tfars
并包含如下信息:
1 AWS_SECRET_KEY="secret_key"
执行的时候,可以通过以下命令传入变量:
1 terraform apply -var-file=/etc/terraform/prod.tfars
Config Map 中的文件引用 Config Map 可以用来存储文件信息,并用于 Pod 的 Volume,在 Terraform 我们可以通过直接引用文件的形势,方便的管理 Config Map:
1 2 3 4 5 6 7 8 9 10 resource "kubernetes_config_map" "xxxsrv-conf" { metadata { name = "xxxsesrv" namespace = "prod" } data = { "service.conf" = "${file("data/configmap/xxxsrv.conf")}" } }
Helm 在 Terraform 管理 helm 也是很方便,以安装 cert-manager 为例,我们能通过在 Terraform 中声明好 Helm Chart 的版本,value.yaml 等信息,来方便的管理 helm 资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 resource "helm_release" "cert-manager" { repository = "https://charts.jetstack.io" name = "cert-manager" chart = "cert-manager" namespace = "cert-manager" version = "v1.0.0-alpha.1" values = [ "${file("data/cert-manager.yaml")}" ] }
得利于我们将 Terraform 的 state 信息存放于 s3 等 remote backend, 我们可以方便的在本地以及 CI 中执行 terraform 命令。
由于 secret 存放于执行跳板机,以 Gitlab CI Runner 为例,我们推荐在专门的跳板机上配置好相关 tfvars 文件,并将相关 runner 用于对应的 Terraform 仓库。
完整的.gitlab-ci.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 # Official image for Hashicorp's Terraform. It uses light image which is Alpine # based as it is much lighter. # # Entrypoint is also needed as image by default set `terraform` binary as an # entrypoint. image: name: registry.gitlab.com/gitlab-org/gitlab-build-images:terraform entrypoint: - "/usr/bin/env" - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Default output file for Terraform plan variables: PLAN: plan.tfplan JSON_PLAN_FILE: tfplan.json ARGS: -var-file=/etc/terraform/prod.tfvars cache: paths: - .terraform before_script: - shopt -s expand_aliases - alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'" - terraform --version - terraform init stages: - validate - build - test - deploy validate: stage: validate tags: - ops - terraform script: - terraform validate plan: stage: build script: - terraform plan $ARGS -out=$PLAN - terraform show --json $PLAN | convert_report > $JSON_PLAN_FILE tags: - ops - terraform artifacts: name: plan paths: - $PLAN reports: terraform: $JSON_PLAN_FILE # Separate apply job for manual launching Terraform as it can be destructive # action. apply: stage: deploy environment: name: production script: - terraform apply -input=false $PLAN tags: - ops - terraform dependencies: - plan when: manual only: - master
缺陷 Terraform 目前还不支持 CRD,虽然官方 Blog 有提到在 alpha 测试,但是距离 GA 还有一段时间吧~