Terraform
构建基础设施
安装 Terraform 后,您就可以创建您的第一个基础设施了。
在本教程中,您将回顾您 Docker 容器的先前配置。
先决条件
本教程假定您正在继续使用之前的教程。 如果不是,请在继续之前按照以下步骤操作。
安装 Terraform CLI(0.15+)和 Docker,如上一教程中所述。
创建一个名为 learn-terraform-docker-container 的目录。
$ mkdir learn-terraform-docker-container
进入该目录。
$ cd learn-terraform-docker-container
创建一个文件来定义您的基础设施。
$ touch main.tf
在您的文本编辑器中打开 main.tf,粘贴以下配置,然后保存文件。
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.1"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.image_id
name = "tutorial"
ports {
internal = 80
external = 8000
}
}
查看配置
用于描述 Terraform 基础设施的一组文件被称为 Terraform 配置。
每个 Terraform 配置都必须位于自己的工作目录中。您之前在 learn-terraform-docker-container 中创建了一个工作目录。查看 main.tf 文件。
这是一个完整的配置,您可以使用 Terraform 部署它。在本教程中,您将更详细地了解您之前部署的此文件的每个区块。
Terraform 块
terraform {} 块包含 Terraform 设置,包括 Terraform 将用于配置您的基础设施的必需的提供程序。对于每个提供程序,source 属性定义了一个可选的主机名、一个命名空间和提供程序类型。Terraform 默认从 Terraform Registry 安装提供程序。在本示例配置中,docker 提供程序的 source 被定义为 kreuzwerker/docker,这是 registry.terraform.io/kreuzwerker/docker 的简写形式。
您还可以为在 required_providers 块中定义的每个提供程序设置版本约束。 version 属性是可选的,但我们建议使用它来约束提供程序版本,以防止 Terraform 安装与您的配置不兼容的提供程序版本。如果您没有指定提供程序版本,Terraform 将在初始化期间自动下载最新版本。
要了解更多信息,请参考 提供器源文档。
提供程序
provider 块配置指定的提供程序,在本例中是 docker。 提供程序是 Terraform 用于创建和管理您的资源的插件。
您可以在 Terraform 配置中使用多个提供程序块来管理来自不同提供程序的资源。 甚至可以将不同的提供程序一起使用。 例如,您可以将 Docker 镜像 ID 传递给 Kubernetes 服务。
资源
使用 resource 块定义您的基础设施组件。 资源可以是物理或虚拟组件,例如 Docker 容器,也可以是逻辑资源,例如 Heroku 应用程序。
资源块在块之前有两个字符串:资源类型和资源名称。 在此示例中,第一个资源类型是 docker_image,名称是 nginx。 类型的前缀映射到提供程序的名称。 在示例配置中,Terraform 管理 docker_image 资源与 docker 提供程序。 资源类型和资源名称共同构成资源的唯一 ID。 例如,您的 Docker 镜像的 ID 是 docker_image.nginx。
资源块包含参数,您可以使用这些参数来配置资源。 参数可以包括机器大小、磁盘镜像名称或 VPC ID 等。 我们的 提供程序参考 记录了每个资源的必需和可选参数。 对于您的容器,示例配置将 Docker 镜像设置为您的 docker_container 资源的镜像源。
初始化目录
当您创建新的配置或从版本控制中检出现有配置时,需要使用 terraform init 初始化目录。
初始化配置目录会下载并安装配置中定义的提供程序,在本例中为 docker 提供程序。
如果您尚未部署上一教程中的快速入门步骤,请立即初始化目录。
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "~> 3.0.1"...
- Installing kreuzwerker/docker v3.0.1...
- Installed kreuzwerker/docker v3.0.1 (self-signed, key ID BD080C4571C6104C)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Terraform 会下载 docker 提供程序并将其安装到当前工作目录的隐藏子目录中,名为 .terraform。 terraform init 命令会打印已安装的提供程序版本。 Terraform 还会创建一个名为 .terraform.lock.hcl 的锁定文件,该文件指定了使用的确切提供程序版本,以便您可以控制何时更新项目使用的提供程序。
格式化并验证配置
我们建议在所有配置文件中使用一致的格式。 terraform fmt 命令会自动更新当前目录中的配置,以提高可读性和一致性。
格式化您的配置。Terraform 会打印出它修改过的文件的名称(如果有)。在本例中,您的配置文件已经正确格式化,因此 Terraform 不会返回任何文件名。
$ terraform fmt
您还可以使用 terraform validate 命令确保您的配置在语法上有效且内部一致。
验证您的配置。上述提供的示例配置是有效的,因此 Terraform 将返回一条成功消息。
$ terraform validate
Success! The configuration is valid.
创建基础设施
现在使用 terraform apply 命令应用配置。 Terraform 将打印类似于以下内容的输出。 我们省略了一些输出以节省空间。
$ terraform apply
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:
# docker_container.nginx will be created
+ resource "docker_container" "nginx" {
##...
+ ports {
+ external = 8000
+ internal = 80
+ ip = "0.0.0.0"
+ protocol = "tcp"
}
}
# docker_image.nginx will be created
+ resource "docker_image" "nginx" {
+ id = (known after apply)
+ keep_locally = false
+ latest = (known after apply)
+ name = "nginx:latest"
+ output = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
在应用任何更改之前,Terraform 会打印出 执行计划,其中描述了 Terraform 将采取的操作,以使您的基础设施与配置匹配。
输出格式类似于 Git 等工具生成的 diff 格式。输出内容在 docker_container.nginx 旁边有一个 + ,表示 Terraform 将创建该资源。下文展示了将要设置的属性。当显示的值为 (known after apply) 时,表示在创建资源之前无法知道该值。例如,Docker 在创建时为镜像分配随机 ID,因此 Terraform 在应用更改并 Docker 提供程序返回该值之前,无法知道 id 属性的值。
Terraform 现在将暂停并等待您的批准才能继续。如果计划中有任何看起来不正确或危险的内容,可以在此安全地中止,而不会对您的基础设施进行任何更改。
在本例中,该计划是可以接受的,因此在确认提示符处输入 yes 以继续。
Enter a value: yes
docker_image.nginx: Creating...
docker_image.nginx: Still creating... [10s elapsed]
docker_image.nginx: Creation complete after 13s [id=sha256:d1a364dc548d5357f0da3268c888e1971bbdb957ee3f028fe7194f1d61c6fdeenginx:latest]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 2s [id=2834ad6283372ceb61121739ce71d31cb0237ad50f4dc234e3445c9445439181]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
您现在已经使用 Terraform 创建了基础设施!访问您 Web 浏览器中的 localhost:8000 以验证容器是否已启动。
检查状态
当你应用你的配置时,Terraform 会将数据写入名为 terraform.tfstate 的文件中。Terraform 将其管理资源的 ID 和属性存储在此文件中,以便以后可以更新或销毁这些资源。
Terraform 状态文件是 Terraform 跟踪其管理资源并经常包含敏感信息的唯一方式,因此您必须安全地存储状态文件并将访问权限限制为仅需要管理您基础设施的可信团队成员。在生产环境中,我们建议 使用 HCP Terraform 或 Terraform Enterprise 远程存储您的状态。Terraform 还支持多个其他 远程后端,您可以使用它们来存储和管理您的状态。
使用 terraform show 检查当前状态。
$ terraform show
# docker_container.nginx:
resource "docker_container" "nginx" {
attach = false
command = [
"nginx",
"-g",
"daemon off;",
]
cpu_shares = 0
entrypoint = [
"/docker-entrypoint.sh",
]
env = []
gateway = "172.17.0.1"
hostname = "2834ad628337"
id = "2834ad6283372ceb61121739ce71d31cb0237ad50f4dc234e3445c9445439181"
image = "sha256:d1a364dc548d5357f0da3268c888e1971bbdb957ee3f028fe7194f1d61c6fdee"
init = false
ip_address = "172.17.0.2"
ip_prefix_length = 16
ipc_mode = "private"
log_driver = "json-file"
logs = false
max_retry_count = 0
memory = 0
memory_swap = 0
must_run = true
name = "tutorial"
network_data = [
{
gateway = "172.17.0.1"
global_ipv6_address = ""
global_ipv6_prefix_length = 0
ip_address = "172.17.0.2"
ip_prefix_length = 16
ipv6_gateway = ""
network_name = "bridge"
},
]
network_mode = "default"
privileged = false
publish_all_ports = false
read_only = false
remove_volumes = true
restart = "no"
rm = false
security_opts = []
shm_size = 64
start = true
stdin_open = false
tty = false
ports {
external = 8000
internal = 80
ip = "0.0.0.0"
protocol = "tcp"
}
}
# docker_image.nginx:
resource "docker_image" "nginx" {
id = "sha256:d1a364dc548d5357f0da3268c888e1971bbdb957ee3f028fe7194f1d61c6fdeenginx:latest"
keep_locally = false
latest = "sha256:d1a364dc548d5357f0da3268c888e1971bbdb957ee3f028fe7194f1d61c6fdee"
name = "nginx:latest"
}
当 Terraform 创建此容器时,它还从 Docker 提供程序收集资源的元数据,并将元数据写入状态文件。稍后,您将修改配置以引用这些值来配置其他资源和输出值。
手动管理状态
Terraform 具有一个名为 terraform state 的内置命令,用于高级状态管理。使用 list 子命令列出项目状态中的资源。
$ terraform state list
docker_container.nginx
docker_image.nginx
下一步
既然您已经使用 Terraform 创建了您的第一个基础设施,请继续 下一个教程 来修改您的基础设施。
有关此教程中使用的概念的更多详细信息
- 在 Terraform 文档中了解有关 Terraform 配置语言的更多信息。
- 了解更多关于 Terraform 提供程序的信息。
- 在文档的 用例部分中找到 Terraform 其他用途的示例。
- 阅读 Docker provider 文档 以了解更多信息。
- 有关
terraform state命令以及用于从状态中移动或删除资源的子命令的更多信息,请参阅 CLIstate命令文档。