島根県産SEの備忘録

島根県産のSEがAWSなどのクラウドの技術を中心に記事を書いています。

CDK for Terraform で適当にEC2インスタンスをデプロイしてみた

環境準備

今回の環境は以下の通りです。

$ cat /etc/issue
Amazon Linux AMI release 2018.03

$ node --version
v12.18.2

$ npm --version
6.14.5

$ yarn version
yarn version v1.22.4

$ terraform version
Terraform v0.12.28

$ yarn -s cdktf --version
0.0.12

それでは、上述のサービスのインストール及び、アップグレードの方法から紹介していきます。

node.js / npm

まずはnode.jsとnpmです。
Cloud9のAMI使用していますが、デフォルト入っているnodeのバージョンが0.10だったので、アップグレードしていきます。

// リポジトリの追加
$ sudo su -
> curl -sL https://rpm.nodesource.com/setup_12.x | bash -

// node.jsのアップグレード
> yum update nodejs

// バージョン確認
> node --version
> nom --version

yarn

yarnはインストールされていなかったようなので、インストールしていきます。

// リポジトリの追加
> wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo

// yarnのインストール
>  yum install yarn

// バージョン確認
> yarn version

terraform

Terraformのインストールです。
上述の参考サイトにある通り、terraformがインストールされていない状態で、CDK for Terraform(cdktf-cli)をインストールしようとすると怒られます。

なお、Terraformがインストールされていない環境で実行すると # Terraform CLI not present - Please install a current version https://learn.hashicorp.com/terraform/getting-started/install.html とエラーが表示されます、事前にインストールしておいてください。

AWS CDKでプロバイダーとしてTerraformが使える!!CDK for Terraformが発表されました!! #awscdk | Developers.IO

インストール手順は以下の通りです。

// terraform用のディレクトリを用意
> mkdir /opt/terra_0_12_28/

// zipファイルのダウンロード
> wget https://releases.hashicorp.com/terraform/0.12.28/terraform_0.12.28_linux_amd64.zip

// zipを先に作成したディレクトリに解凍
> unzip -d /opt/terra_0_12_28/ /home/ec2-user/environment/terraform_0.12.28_linux_amd64.zip

// 後ほど/opt/terraformにパスを通すので、シンボリックリンクを作成
> ln -sfn /opt/terra_0_12_28 /opt/terraform

// パスを通す
> vi /etc/profile

    (以下を追記)
    export PATH=$PATH:/opt/terraform/

// /etc/profile読み込み
> source /etc/profile 

// 一般ユーザーでもパスが通っていることを確認
> exit 
$ which terraform

// バージョン確認
$ terraform version

cdktf-cli

ここまで準備できたら、いよいよcdktf-cliのインストールです。
今回は参考サイトにならって、ローカルインストールにしようと思います。

// インストール先ディレクトリの作成
$ mkdir terraform-cdk && cd terraform-cdk

// cdktf-cliのインストール及び、cdktfの初期化(Typescript)
$ npx -p cdktf-cli cdktf init --template=typescript

EC2インスタンスのデプロイ

早速以下の通り、EC2インスタンスをデプロイするように、main.tsファイルを編集してみました。

main.ts

import { Construct } from 'constructs';
import { App, TerraformStack, Token } from 'cdktf';

import { AwsProvider } from './.gen/providers/aws';

import { Vpc } from './.gen/providers/aws/vpc';
import { Subnet } from './.gen/providers/aws/subnet';
import { RouteTable } from './.gen/providers/aws/route-table';
import { RouteTableAssociation } from './.gen/providers/aws/route-table-association';
import { InternetGateway } from './.gen/providers/aws/internet-gateway';

import { Instance } from './.gen/providers/aws/instance';


class MyStack extends TerraformStack {
  constructor(scope: Construct, name: string) {
    super(scope, name);

    new AwsProvider(this, 'Aws', {
      region: 'us-east-1',

    })

    const vpc = new Vpc(this, 'Vpc', {
      cidrBlock: '10.0.0.0/16'
    });
    
    const igw = new InternetGateway(this, 'InternetGateway', {
      vpcId: Token.asString(vpc.id)
    });
    
    const rt = new RouteTable(this, 'RouteTable', {
      vpcId: Token.asString(vpc.id),
      route: [
        {
          cidrBlock: '0.0.0.0/0',
          gatewayId:  Token.asString(igw.id),
          egressOnlyGatewayId:  '',
          instanceId:  '',
          ipv6CidrBlock:  '',
          natGatewayId:  '',
          networkInterfaceId:  '',
          transitGatewayId:  '',
          vpcPeeringConnectionId:  ''
        }
      ]
    });
    
    const sbn = new Subnet(this, 'Subnet', {
      vpcId: Token.asString(vpc.id),
      availabilityZone: 'us-east-1a',
      cidrBlock: '10.0.0.0/24'
    });
    
    new RouteTableAssociation(this, 'RouteTableAssociation', {
      routeTableId: Token.asString(rt.id),
      subnetId: Token.asString(sbn.id)
    });
    
    new Instance(this, 'Instance', {
      ami: 'ami-08f3d892de259504d',
      instanceType: 't2.micro',
      subnetId: Token.asString(sbn.id)
    });
    
  }
}

const app = new App();
new MyStack(app, 'terraform-cdk');
app.synth();


ほとんど参考サイトの記載と同じですね。
少し違うところといえば、IGWや、ルートテーブルの作成をしているところですかね。


ルートテーブルのところについては、地味に詰まってしまいました。
IGWしかルーティングしないため、gatewayIdのみ書いていましたが、以下のようなエラーが出ました。

Inappropriate value for attribute "route": element 0: attributes
"egress_only_gateway_id", "instance_id", "ipv6_cidr_block", "nat_gateway_id",
"network_interface_id", "transit_gateway_id", and "vpc_peering_connection_id"
are required.

解決方法としては上述の通り、今回のルーティング設定には関係ないegressOnlyGatewayIdや、instanceIdなどについても書いてあげる必要がありました。
./.gen/providers/aws/route.ts を確認しても、required じゃないのに何故...


また、各種リソースに指定できるオプションは、./.gen/providers/aws/<リソース名>.tsexport interface <リソース名>Configを見れば確認できます。

e.g.) ./.gen/providers/aws/route.ts

export interface RouteConfig extends TerraformMetaArguments {
  readonly destinationCidrBlock?: string;
  readonly destinationIpv6CidrBlock?: string;
  readonly egressOnlyGatewayId?: string;
  readonly gatewayId?: string;
  readonly instanceId?: string;
  readonly natGatewayId?: string;
  readonly networkInterfaceId?: string;
  readonly routeTableId: string;
  readonly transitGatewayId?: string;
  readonly vpcPeeringConnectionId?: string;
  /** timeouts block */
  readonly timeouts?: RouteTimeouts;
}


順番が少し前後しましたが、デプロイなどの基本的な操作は以下の通りです。

cdktf synth: cdktf.outにcdk.tf.jsonというJSON形式のTerraformのテンプレートファイルを出力する。

e.g.)

$ yarn -s cdktf synth
Generated Terraform code in the output directory: cdktf.out


cdktf deploy: CDKで記載したリソースをTerraformテンプレートに変換してデプロイする。

e.g.)

$ yarn -s cdktf deploy
Deploying Stack: terraform-cdk
Resources
 ✔ AWS_INSTANCE         Instance            aws_instance.terraformcdk_Instance_D75D061F
 ✔ AWS_INTERNET_GATEWAY InternetGateway     aws_internet_gateway.terraformcdk_InternetGateway_12383DC6
 ✔ AWS_ROUTE_TABLE      RouteTable          aws_route_table.terraformcdk_RouteTable_FE93546D
 ✔ AWS_ROUTE_TABLE_ASSO RouteTableAssociati aws_route_table_association.terraformcdk_RouteTableAssociation_6D40008E
 ✔ AWS_SUBNET           Subnet              aws_subnet.terraformcdk_Subnet_D427F1FE
 ✔ AWS_VPC              Vpc                 aws_vpc.terraformcdk_Vpc_DF4745BC

Summary: 6 created, 0 updated, 0 destroyed.


cdktf synth: cdktf deployでデプロイしたリソースを削除する。

e.g.)

$ yarn -s cdktf destroy
Destroying Stack: terraform-cdk
Resources
 ✔ AWS_INSTANCE         Instance            aws_instance.terraformcdk_Instance_D75D061F
 ✔ AWS_INTERNET_GATEWAY InternetGateway     aws_internet_gateway.terraformcdk_InternetGateway_12383DC6
 ✔ AWS_ROUTE_TABLE      RouteTable          aws_route_table.terraformcdk_RouteTable_FE93546D
 ✔ AWS_ROUTE_TABLE_ASSO RouteTableAssociati aws_route_table_association.terraformcdk_RouteTableAssociation_6D40008E
 ✔ AWS_SUBNET           Subnet              aws_subnet.terraformcdk_Subnet_D427F1FE
 ✔ AWS_VPC              Vpc                 aws_vpc.terraformcdk_Vpc_DF4745BC

Summary: 6 destroyed.

まとめ・感想

今まではCDK はCloudFormationを介して操作できるものしか触れませんでしたが、Terraformにも対応したことで、クラウドのリソース管理をするならまずCDKを検討してから のように一気に可能性が広がったような気がします。

感想としては、私自身Terraformに触れるのは初めてでしたが、思ったよりも簡単に操作することができ、面白かったです。
これも、コードがTypescriptで記述されており、なんとなく見たことあるような構文が並んでいるからだと思います。

また、書いている途中ですが、Cloud9の補完がかなり効いててスムーズに編集することができました。素のTerraformのテンプレートファイルの.jsonや、.tf ファイルと比べるとそういった利便性の向上も期待できそうだと感じました。