- AWS のサーバー構築
- Terraform の欠点
- AWS CDK の登場
- CDK for Terraform の登場
- AWS CDK を使ってみる
- AWS CDK のメリット/デメリット
- CDK for Terraform を使ってみる
- CDK for Terraform のメリット/デメリット
- まとめ: 結局何を採用するのがいいのか
AWS のサーバー構築
これまで、AWS のサーバー構築には Terraform を使うことが多かったかと思います。
しかし最近では、 AWS CDK を使うという選択肢も出てきています。
そして先日、 CDK for Terraform が Generally Available、つまり、正式版公開という記事が出ました。
Terraform の欠点
Terraform の唯一の欠点が、 HCL (HashiCorp Configuration Language) という独自の記述言語でした。
AWS だけでなく、 GCP や Azure といった様々なクラウドに対応している Terraform ですが、HCL を書くのが非常に大変でした。プログラミング言語ほどの記述能力が無いため、しばし記述が冗長になったり、書きづらかったり、ということがありました。
AWS CDK の登場
ここで登場したのが、AWS CDK です。
AWS CDK は、 AWS CloudFormation を改善したようなものです。
AWS CloudFormation は、VPCやSubnet、EC2などのAWSリソースの情報を YAML 形式で記述すると、書いたとおりに AWS のリソースを作成してくれるものなのですが、 YAML で記述する必要があるため、 Terraform 同様、記述能力が低く、書きづらい、読みづらい、ということがありました。
これを、 YAML ではなく TypeScript で書けるようにしたのが AWS CDK でした。
書き慣れた「プログラミング言語」で書けるということで、非常に書きやすいです。表現能力も高いため、インフラの記述がスッキリします。
唯一、デメリットとしては、 CloudFormation をベースにしているため、 AWS でしか使えないことでした。
CDK for Terraform の登場
そこで CDK Terraform の登場。
これは、 AWS CDK を参考にして、 TypeScript で Terraform が書けるようにしたものです。AWS CDK と Terraform のいいとこ取りで、これが最強なのでは?という感じです。
AWS CDK を使ってみる
CDK for Terraform を使う前に、僕はそもそも AWS CDK を使ったことがないので、使ってみます。
ちなみに、 Terraform と AWS CloudFormation は使ったことがあります。
AWS CDK コマンドラインツールのインストール
npm を使ってインストールするのがオススメです。node.js はPCにインストールされている前提です。
また、 AWS CLI も必要ですが、すでに設定済みという前提で進めます。
$ npm install -g aws-cdk $ cdk --version 2.35.0 (build 5c23578)
AWS CDK で S3 を立ててみる
# aws cdk プロジェクトを作成する # ディレクトリを作成して、その中に入ってから cdk init をする # カレントディレクトリに package.json などが作成されるというなかなかロックな仕様 $ mkdir cdk-sample-s3-app $ cd cdk-sample-s3-app $ cdk init app --language=typescript
init コマンドの第3引数には app / lib / sample-app が指定できる。ライブラリの開発をする時には lib を指定するが、通常は app を指定する。
言語は TypeScript が推奨っぽいので TypeScript を選択する。
コマンドを叩くと色々生成されるが、重要なファイルは以下
bin/アプリ名-stack.ts
- エントリーポイント。ここからプログラムの実行が開始される。
lib/アプリ名-stack.ts
- ここに構成を記述していくイメージ
コード
今回は cdk-sample-s3-app
というアプリ名にしたので、 lib/cdk-sample-s3-app-stack.ts
にコードを実際に書いていく。
import { aws_s3, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleS3AppStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // cdk-bucket と書いたつもりが、dck と typo してた。が、気にせずすすめる const bucket = new aws_s3.Bucket(this, 'sakamoto-aws-dck-bucket', { bucketName: 'sakamoto-aws-dck-bucket', }) } }
デプロイ
まず最初に bootstrap をする。これは、プロジェクトを作成した時に1回だけ実行したらよい。
$ cdk bootstrap ⏳ Bootstrapping environment aws://038863151084/ap-northeast-1... Trusted accounts for deployment: (none) Trusted accounts for lookup: (none) Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize. CDKToolkit: creating CloudFormation changeset... ✅ Environment aws://038863151084/ap-northeast-1 bootstrapped.
これをすると、AWS CloudFormation にスタックが作成され、CloudFormation の実行履歴などを記録するための S3 バケットが作成される。
スタックの名前はデフォルトだと CDKToolkit となっている。多分これは設定で変えられるはずなので、本番で運用するときは名前をちゃんとつけたほうがいい。AWS CDKを複数使っている場合に名前が被らないようにする必要がある。
続いてデプロイ。 cdk diff
をすると、差分が表示されるので、本番でデプロイする時は diff を見てからデプロイするといい。今回は実験なのでいきなりデプロイすることにする。
$ cdk deploy ✨ Synthesis time: 3.46s CdkSampleS3AppStack: deploying... [0%] start: Publishing ea5f8f26e4fd714c8ac8e056ce25d59da72ac19555e4a1fa77081dc899140d50:current_account-current_region [100%] success: Published ea5f8f26e4fd714c8ac8e056ce25d59da72ac19555e4a1fa77081dc899140d50:current_account-current_region CdkSampleS3AppStack: creating CloudFormation changeset... ✅ CdkSampleS3AppStack ✨ Deployment time: 38.01s Stack ARN: arn:aws:cloudformation:ap-northeast-1:038863151084:stack/CdkSampleS3AppStack/5c29bec0-1722-11ed-a0fc-060fd357ab39 ✨ Total time: 41.47s
これで AWS 上に sakamoto-aws-dck-bucket
というバケットが作成された。
リソースの全削除
作ったリソースを全部削除したい場合は、cdk destroy
コマンドを実行すれば良い。この場合、CloudFormation のスタックは残ったままで、リソースが削除される。
また、 AWS コンソールの AWS CloudFormation から、「削除」をすると、スタックごと消すことができる。全部なかったことにしたい場合はこちらが良い。
AWS CDK のメリット/デメリット
CDK for Terraform と比較した時のメリット/デメリットです。もちろん、通常の Terraform と比べたら TypeScript を使える分書きやすいのですが、それは CDK for Terraform と比べてメリットにはならないので除きます。
- メリット
- CLIの出力結果が見やすい
- AWS CDK が AWS 公式のツールであるという安心感
- AWS の Web のコンソールから CloudFormation の状態(実行履歴とか)が見られるのが良い
- 環境のセットアップが簡単
- デメリット
- AWS でしか利用できない
唯一のデメリットが、 AWS にしか対応していない(GCP や Azure に対応していない)点です。今は AWS しか利用していないプロダクトだとしても、将来的に、 Google Cloud Platform に移動したくなったり、一部 Azure の機能を使いたくなる、といった可能性もあるので、そういった場合に AWS CDK では管理できないのがデメリットです(別途 Terraform を用意するなどして構築する必要がでています)。
CDK for Terraform を使ってみる
続いて、 CDK for Terraform を使ってみます。
CDK for Terraform コマンドラインツールのインストール
CDK for Terraform をインストールする前に、 terraform コマンドをインストールしておく必要があります。私の PC にはもう terraform コマンドがインストールされていたので、今回は省略します。
また、 AWS CLI も必要ですが、すでに設定済みという前提で進めます。
こちらも、AWS CDK 同様、 npm を使ってインストールするのがオススメです。
$ npm install --g cdktf-cli@latest $ cdktf --version 0.12.0
CDK for Terraform で S3 を立ててみる
プロジェクトの作成
AWS CDK の時と同様に、ディレクトリを作成して、 init します。
$ mkdir cdktf-sample-app $ cd cdktf-sample-app
そして init するのですが、 AWS CDK と異なり、設定が少し煩雑です。
Terraform Cloud remote state management というのを利用するかどうか聞かれましたが、今回は No を選択しました。AWS CDK の場合は、 S3 に勝手にバケットが作成されて、そこで状態管理や実行結果の記録がされていましたが、 CDKTF では、 デフォルトだと Terraform Cloud を使うようです。CDKTF でも同様に S3 で管理したいなと思っていたので、今回は No にしました。
$ cdktf init --template=typescript Welcome to CDK for Terraform! By default, cdktf allows you to manage the state of your stacks using Terraform Cloud for free. cdktf will request an API token for app.terraform.io using your browser. If login is successful, cdktf will store the token in plain text in the following file for use by subsequent Terraform commands: /Users/yoshiyuki_sakamoto/.terraform.d/credentials.tfrc.json Note: The local storage mode isn't recommended for storing the state of your stacks. ? Do you want to continue with Terraform Cloud remote state management? No ? Project Name cdktf-sample-app ? Project Description A simple getting started project for cdktf. ? Do you want to start from a Terraform project? No ? Do you want to send crash reports to the CDKTF team? See https://www.terraform.io/cdktf/create-and-deploy/configuration-file#enable-crash-reporting-for-the-cli for more information No npm notice created a lockfile as package-lock.json. You should commit this file. + constructs@10.1.70 + cdktf@0.12.0 added 53 packages from 27 contributors and audited 53 packages in 1.624s 5 packages are looking for funding run `npm fund` for details found 0 vulnerabilities + ts-node@10.9.1 + @types/node@18.6.4 + ts-jest@28.0.7 + @types/jest@28.1.6 + jest@28.1.3 + typescript@4.7.4 added 300 packages from 263 contributors and audited 353 packages in 20.376s 35 packages are looking for funding run `npm fund` for details found 0 vulnerabilities ======================================================================================================== Your cdktf typescript project is ready! cat help Print this message Compile: npm run get Import/update Terraform providers and modules (you should check-in this directory) npm run compile Compile typescript code to javascript (or "npm run watch") npm run watch Watch for changes and compile typescript in the background npm run build Compile typescript Synthesize: cdktf synth [stack] Synthesize Terraform resources from stacks to cdktf.out/ (ready for 'terraform apply') Diff: cdktf diff [stack] Perform a diff (terraform plan) for the given stack Deploy: cdktf deploy [stack] Deploy the given stack Destroy: cdktf destroy [stack] Destroy the stack Test: npm run test Runs unit tests (edit __tests__/main-test.ts to add your own tests) npm run test:watch Watches the tests and reruns them on change Upgrades: npm run upgrade Upgrade cdktf modules to latest version npm run upgrade:next Upgrade cdktf modules to latest "@next" version (last commit) Use Providers: You can add prebuilt providers (if available) or locally generated ones using the add command: cdktf provider add "aws@~>3.0" null kreuzwerker/docker You can find all prebuilt providers on npm: https://www.npmjs.com/search?q=keywords:cdktf You can also install these providers directly through npm: npm install @cdktf/provider-aws npm install @cdktf/provider-google npm install @cdktf/provider-azurerm npm install @cdktf/provider-docker npm install @cdktf/provider-github npm install @cdktf/provider-null You can also build any module or provider locally. Learn more https://cdk.tf/modules-and-providers ========================================================================================================
cdktf/provider-aws のインストール
Terraform は、 AWS だけでなく、 GCP、Azure などの複数のプラットフォームに対応しているため、そのプラットフォームに対応する provider をインストールする必要があります。
npm install @cdktf/provider-aws
コード
main.ts
が本体です。早速 S3 バケットを作成してみます。記述した感じは AWS CDK とほぼ変わりません。Terraform を書き慣れている人だと書きやすいと思います。
import { Construct } from "constructs"; import { App, TerraformStack } from "cdktf"; import { AwsProvider } from "@cdktf/provider-aws"; import { S3Bucket } from "@cdktf/provider-aws/lib/s3"; class MyStack extends TerraformStack { constructor(scope: Construct, name: string) { super(scope, name); new AwsProvider(this, 'aws', { region: 'ap-northeast-1', }) new S3Bucket(this, 'cdftf-test') } } const app = new App(); new MyStack(app, "cdktf-sample-app"); app.synth();
デプロイ
cdktf deploy
コマンドを叩くと、差分が表示されたうえで、デプロイするかどうか問われます。 Approve を選択するとデプロイされます。
慣れないと差分が見づらいと思いますが、 Terraform に慣れた人ならおなじみの差分表示です。 ただ、なぜかインデントがぶっ壊れていて、見づらいです。この辺はまだ発展途上という感じがします。
適用前に差分を見せてくれたうえで、デプロイするかどうか聞いてくれるのは親切ですね。
$ cdktf deploy cdktf-sample-app Initializing the backend... cdktf-sample-app Initializing provider plugins... cdktf-sample-app - Reusing previous version of hashicorp/aws from the dependency lock file cdktf-sample-app - Using previously-installed hashicorp/aws v4.24.0 cdktf-sample-app 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. cdktf-sample-app 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: cdktf-sample-app # aws_s3_bucket.cdftf-test (cdftf-test) will be created + resource "aws_s3_bucket" "cdftf-test" { + acceleration_status = (known after apply) + acl = (known after apply) + arn = (known after apply) + bucket = (known after apply) + bucket_domain_name = (known after apply) + bucket_regional_domain_name = (known after apply) + force_destroy = false + hosted_zone_id = (known after apply) + id = (known after apply) + object_lock_enabled = (known after apply) + policy = (known after apply) + region = (known after apply) + request_payer = (known after apply) + tags_all = (known after apply) + website_domain = (known after apply) + website_endpoint = (known after apply) + cors_rule { + allowed_headers = (known after apply) + allowed_methods = (known after apply) + allowed_origins = (known after apply) + expose_headers = (known after apply) + max_age_seconds = (known after apply) } + grant { + id = (known after apply) + permissions = (known after apply) + type = (known after apply) + uri = (known after apply) } + lifecycle_rule { + abort_incomplete_multipart_upload_days = (known after apply) + enabled = (known after apply) + id = (known after apply) + prefix = (known after apply) + tags = (known after apply) + expiration { + date = (known after apply) + days = (known after apply) + expired_object_delete_marker = (known after apply) } + noncurrent_version_expiration { + days = (known after apply) } + noncurrent_version_transition { + days = (known after apply) + storage_class = (known after apply) } + transition { + date = (known after apply) + days = (known after apply) + storage_class = (known after apply) } } + logging { + target_bucket = (known after apply) + target_prefix = (known after apply) } + object_lock_configuration { + object_lock_enabled = (known after apply) + rule { + default_retention { + days = (known after apply) + mode = (known after apply) + years = (known after apply) } } } + replication_configuration { + role = (known after apply) + rules { + delete_marker_replication_status = (known after apply) + id = (known after apply) + prefix = (known after apply) + priority = (known after apply) + status = (known after apply) + destination { + account_id = (known after apply) + bucket = (known after apply) + replica_kms_key_id = (known after apply) + storage_class = (known after apply) + access_control_translation { + owner = (known after apply) } + metrics { + minutes = (known after apply) + status = (known after apply) } + replication_time { + minutes = (known after apply) + status = (known after apply) } } + filter { + prefix = (known after apply) + tags = (known after apply) } + source_selection_criteria { + sse_kms_encrypted_objects { + enabled = (known after apply) } } } } + server_side_encryption_configuration { + rule { + bucket_key_enabled = (known after apply) + apply_server_side_encryption_by_default { + kms_master_key_id = (known after apply) + sse_algorithm = (known after apply) } } } + versioning { + enabled = (known after apply) + mfa_delete = (known after apply) } + website { + error_document = (known after apply) + index_document = (known after apply) + redirect_all_requests_to = (known after apply) + routing_rules = (known after apply) } } cdktf-sample-app Plan: 1 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for cdktf-sample-app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop
CDK for Terraform のメリット/デメリット
AWS CDK と比較した場合のメリット/デメリットを書きます。
- メリット
- AWS 以外にも対応している
- AWS 公式でないとはいえ、サポート範囲はかなり広い
- なんだかんだ AWS CDK でも対応していない AWS リソースはあったりする。それに比べて CDKTF のベースになっている Terraform は対応範囲が広い。普段使う分には AWS CDK でほぼ問題ないと思うが、サポート範囲の広さを重視したいなら CDK for Terraform が選択肢にあがる。
- デメリット
- CloudFormation のような Web UI や、AWS上の良い感じのシステムなのか無い
- 初期設定が少し複雑
- AWS CDK だと AWS 一択なので、初期設定の手間が非常に少ないが、CDKTF は選択肢が多い分初期設定がちょっとむずい
まとめ: 結局何を採用するのがいいのか
AWS しか使わないなら AWS CDK、そうでないなら CDK for Terraform がいいかなと思いました?
AWS CDK は Web 上から色々見たり操作できるメリットが
CDK for Terraform が発展途上のため、CDK を使わない Terraform を採用したくなるケースもあるかもしれませんが、Terraform は個人的にはかなり書きづらいため、Terraform を採用するなら CDK for Terraform を採用するのが良いかなと思いました。