使用terraform来管理现有的AWS基础架构

太长不看。

    • 既存awsインフラを手動でterraformに起こすのは大変面倒くさい.

 

    • dtan4氏によるterraformingはimport作業をある程度自動化するが,問題もある.

 

    terraformingを改造/手でファイルを書く を併用してimport作業を進めると良いと思う.

使用”terraform import”命令将现有的基础设施导入到terraform中。

    • tfファイルに既存インフラの設定を記述する

 

    tfstateに既存インフラの状態を追加する

需要这件事。

在AWS上将现有的基础架构纳入terraform的管理下,有几种方法。以下是对这些方法的整理。

前提 – 前提条件

    • Terraform v0.11.11+ provider.aws v2.0.0

 

    AWS上には,terraform管理下に置くべきインフラとそうでないインフラが混在している.

目标

将部署在AWS上的生产环境基础架构转化为代码形式,

    1. 使维护更加容易。

 

    将本正式环境(production environment)搭建成与之相同配置的环境(测试环境)尽快完成。

用手动方法执行的方式

以设置vpc为例,考虑将其放入terraform中。有关aws_vpc设置的详细信息,请参阅官方文档。

准备一个tf文件的模板。

创建一个合适的tf文件(在这里称为vpc.tf),首先只需描述设置的框架。

# resource "awsサービス名" "名前(aws上の名前と一致している必要はない)"
resource "aws_vpc" "first_vpc" {

}

如果有多个目标,请准备相应数量的外壳。

导入状态到tfstate。

在这里我们使用Terraform提供的terraform import命令。
基本格式是terraform import <服务名称>.<资源名称> <在AWS上的ID>。
每个服务的import命令的详细信息也可以在官方文档中找到,请参考。例如,对于之前提到的VPC,

terraform import aws_vpc.first_vpc vpc-xxxxxxxxx

这样,first_vpc已经被导入到tfstate中了。

一边查看diff,一边编写tf文件。

terraform import命令可以自动生成tfstate文件,但是tf文件必须手动编写。我们将参考官方文档和AWS控制台,填写vpc.tf文件。首先可以适当地复制粘贴示例用法来创建文件。

在写了一部分之后,我们执行terraform plan命令。这样,将显示当前tf文件与AWS上的配置之间的差异。我们需要在tf文件中添加项目,以将差异降低到零。


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ aws_vpc.first_vpc
      tags.%:      "2" => "0"
      tags.Name:   "first-vpc" => ""
      tags.STATUS: "IN USE" => ""


Plan: 0 to add, 1 to change, 0 to destroy.

------------------------------------------------------------------------

当tf文件中准确描述了所有项目,并且与AWS上的配置没有任何差异时,执行terraform plan的结果应该是一致的。

------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

在中文中,它会显示为“。通过这样做,AWS 基础架构已经纳入Terraform的管理范围内。”

使用地球創造法的方式

最初的方法是对每个基础架构手动编写tf文件,并执行terraform import命令以创建tfstate。 如果基础架构数量只有10个左右,可以通过这种方法来勉强应对,但是当数量增多时,手动编写tf文件将变得非常困难。

因此,我们将使用dtan4提供的terraforming工具。terraforming可以自动化创建tf文件并批量创建tfstate文件,是一款出色的工具。

比如创建aws_vpc的tf文件,可以使用以下命令完成。terraforming的输出将在标准输出上进行,因此当需要将其输出到文件时,请进行重定向。

terraforming vpc > vpc.tf

创建tfstate文件可以使用以下命令进行。

# ---------ディレクトリ内にterraform.tfstateがない場合-----------
terraforming vpc --tfstate > terraform.tfstate
terraform refresh

# ---------ディレクトリ内に既にterraform.tfstateが存在する場合-----------
terraforming vpc --tfstate --merge=terraform.tfstate > tmp.tfstate
cp tmp.tfstate terraform.tfstate
rm tmp.tfstate
terraform refresh

只需要这个操作就可以完成整个VPC的导入。我相信你会发现,与手动编写tf文件并逐个执行terraform import相比,这种方法简单得令人惊讶。

改造terraforming。

我发现使用 terraforming,可以在瞬间创建 tf 文件和 tfstate 文件。但是这并不意味着可以轻松将现有基础设施迁移到 AWS。

在对行星进行地形改造时存在一些问题。

terraform planすると一部のサービスでtfstateとの差分が残る.dtan4/terraformingの最終コミットが2018年9月であり,一部のサービスについてterraform本家のバージョンアップについていけていない.
例)nat_gatewayおよびelastic_ipでtfファイルにtagsが出力されない.
対象アカウント・対象サービスのすべての設定を取り込むため,terraform管理下におく設定項目を自分で指定することができない.
referenceがID直書きされているため,出力されたtfファイルを使って新しい環境にインフラを立てることはできない.
例)internet_gatewayはvpcを参照するが,terraformingで出力されるtfファイルにはvpc_idが直接数字で書き出される.新しい環境にvpcを立てるときは当然vpc_idが異なるので,internet_gatewayからvpcを参照することができない.

因此,我们将改进terraforming以应对这些问题。从dtan4 / terraforming的fork库中可以看出,似乎有一些人已经进行了自己的修改并使用了它。

在着手改造之前,首先让我们来看看地球改造在内部做了什么。

首先,我们来看erb文件。在terraforming/lib/terraforming/resource/目录下,有每个服务对应的rb文件。而在terraforming/lib/terraforming/template/tf/目录下,有每个服务对应的erb文件。

比如,vpc.erb的内容如下所示。

<% vpcs.each do |vpc| -%>
resource "aws_vpc" "<%= module_name_of(vpc) %>" {
    cidr_block           = "<%= vpc.cidr_block %>"
    enable_dns_hostnames = <%= enable_dns_hostnames?(vpc) %>
    enable_dns_support   = <%= enable_dns_support?(vpc) %>
    instance_tenancy     = "<%= vpc.instance_tenancy %>"

    tags {
<% vpc.tags.each do |tag| -%>
        "<%= tag.key %>" = "<%= tag.value %>"
<% end -%>
    }
}

<% end -%>

从这个形式上来看,可以知道erb文件中写有每个服务的tf文件输出。对于存在问题的服务的tf文件输出,可以考虑编辑erb文件。

接下来,让我们来查看terraforming/lib/terraforming/resource/目录中的rb文件。作为示例,我们将查看vpc.rb文件。在文件的某一部分,有关于tfstate的描述。

def tfstate
  vpcs.inject({}) do |resources, vpc|
    attributes = {
      "cidr_block" => vpc.cidr_block,
      "enable_dns_hostnames" => enable_dns_hostnames?(vpc).to_s,
      "enable_dns_support" => enable_dns_support?(vpc).to_s,
      "id" => vpc.vpc_id,
      "instance_tenancy" => vpc.instance_tenancy,
      "tags.#" => vpc.tags.length.to_s,
    }
    resources["aws_vpc.#{module_name_of(vpc)}"] = {
      "type" => "aws_vpc",
      "primary" => {
        "id" => vpc.vpc_id,
        "attributes" => attributes
      }
    }

    resources
  end
end

在进行terraform环境配置时,似乎直接编写JSON文件而不是使用terraform import来创建tfstate。

实际上,没有必要在terraforming中认真制作tfstate的JSON。因为只要具有服务类型和ID等最基本的信息,就可以通过terraform refresh自动修复terraform.tfstate。

要使用Ore Ore永久更改地貌技術

使用rbenv命令切换到不同版本的Ruby,并通过gem安装自定义的terraforming。在terraforming存储库中执行以下命令。

rbenv local <適当なバージョン>
gem uninstall terraforming
gem build terraforming.gemspec
gem install terraforming-0.16.0.gem

填补tf文件中的缺失项目

一旦简要地查看完terraforming的内部情况后,开始进行必要的改造以使terraforming正常运作。

首先,在导出tf文件的时候,添加缺失的项目。举例来说,我们将对nat_gateway进行改进。在原始的terraforming代码中,tags没有被输出到tf文件中,导致在运行terraform plan时会提示有差异。因此,在nat_gateway.erb文件中添加以下代码来补充tags。

<% nat_gateways.each do |nat_gateway| -%>
<% unless nat_gateway.nat_gateway_addresses.empty? -%>
resource "aws_nat_gateway" "<%= module_name_of(nat_gateway) %>" {
    allocation_id = "<%= nat_gateway.nat_gateway_addresses[0].allocation_id %>"
    subnet_id = "<%= nat_gateway.subnet_id %>"
#----追記ここから----
    tags {
<% nat_gateway.tags.each do |tag| -%>
        "<%= tag.key %>" = "<%= tag.value %>"
<% end -%>
    }
#----追記ここまで----
}

<% end -%>
<% end -%>

好像是从AWS SDK中获取实例相关信息。需要边查阅AWS SDK的文档边撰写。

注)<% ~~~ -%>是用于执行用括号括起来的Ruby代码的语法。当将结果作为文本输出时,请使用<%= ~~~ %>。

将tf文件中的id转换为参考形式。

如果只是将现有基础设施转换为代码进行管理,直接在代码中使用id进行引用写入也没有什么问题。但是,如前所述,如果要在另一个环境中建立相同的配置,则需要将tf文件中的引用转换为引用形式。引用形式的示例如下(参考:https://learn.hashicorp.com/terraform/getting-started/dependencies)。

vpc_id = "vpc-xxxxxxxx" #id直書きされた形
vpc_id = "${aws_vpc.example-vpc.id}" #参照形

我們以VPC為例來解釋。為了解決VPC的ID參考形式,我們準備了Terraforming :: Resource :: VPC的name函數。


module Terraforming
  module Resource
    class VPC
      include Terraforming::Util

      def self.name(id, client: Aws::EC2::Client.new)
        self.new(client, []).name(id)
      end

      def name(id)
        v = vpcs.select { |e| e.vpc_id==id }
        if v.length > 0
          "${aws_vpc.#{module_name_of(v[0])}.id}"
        else
          id
        end
      end

    end
  end
end

在erb文件中输出vpc_id的方法如下。(下面的示例是将subnet的vpc_id转换为引用形式。)


vpc_id = "<%= Terraforming::Resource::VPC.name(subnet.vpc_id) %>"

您可以使用相同的方法将ID转换为参考形式,适用于其他服务。

改造地球的示例-地貌改造

對於土地改造的觀點

    • tfファイル出力項目の修正

 

    id直書きを参照形にする

我在GitHub上发布了进行改造的terraforming存储库。我所修改的AWS服务如下:

    • application load balancer

 

    • auto scaling group

 

    • auto scaling schedule(新設)

 

    • ec2 instance

 

    • elastic ip

 

    • internet gateway

 

    • launch configuration

 

    • nat gateway

 

    • route table

 

    • security group

 

    • subnet

 

    vpc

由于我只对使用了terraforming的范围进行了修改,所以即使使用了上述提到的服务,仍可能存在差异。

整理

使用terraform将现有的基础设施纳入管理需要创建tf和tfstate文件,手动操作非常繁琐。我介绍了使用terraforming可以稍微简化一些工作量,但仍存在一些问题,因此我介绍了修改terraforming的方法。

目前来说,将AWS现有基础设施轻松转移到terraform管理下的方法可能还不存在。如果目标基础设施较小,可以手动操作;如果较大,可能需要改造terraforming,逐步完善tf文件和tfstate文件。

terraform 是一个使用广泛的自动化工具,我们认为由于每个人并不会频繁进行现有基础架构的导入工作,因此在这方面自动化的动力较弱,很难出现一个万能的自动化工具。我们是否能期待有一天 hashicorp 推出官方的工具呢?

完成tf和tfstate这两个方面的讨论后,我们将在另一篇文章中进行详述。

bannerAds