CDKとterraformの使い分け

こんにちは、 kotamat です。

少し前から、CDKを用いた環境整備を行いました。今までterraformで構築してきたので、それとの差分をメモ代わりに書こうと思います。

TL; DR

使い分けとしては下記のようになるかなと思っています

  • CDK
    • ベストプラクティスを簡単に構築したい場合。
    • ビルドプロセスなど、動的にインフラ構成を構築したい場合
  • terraform
    • サービスの基盤となるインフラを構築したい場合
    • 同等の環境を、異なるVPCなどで構築したい場合

CDK

とは

AWS クラウド開発キット (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースをモデル化およびプロビジョニングするためのオープンソースのソフトウェア開発フレームワークです。

https://aws.amazon.com/jp/cdk/

簡単に言うと、TypeScript、PythonJava、および .NET でCluodFormation(AWS専用のIaCサービス)用のパターンファイルを生成してくれるものとなります。 いつも使い慣れた言語を使うことができるため、サーバーサイドのエンジニアが手軽にインフラの構築を実現できるものとなります。

使用感

今回はTypeScriptを用いたのですが、型推論がしっかり効いていたため、どのリソースにどのようなパラメータが設定可能なのかを、コードをみるだけである程度推測することが可能で、流れるようにコードを書くことができました。

const app = new cdk.App()
new ApiStack(app, 'Api', {
  env: {
    account: 'account',
    region: 'ap-northest-1'
  }
})
app.synth()

class ApiStack extends cdk.Stack {
  constructor(parent: cdk.App, name: string, props: cdk.StackProps) {
    super(parent, name, props)

    const vpc = Vpc.fromVpcAttributes(
      this,
      'Vpc',
      {
        vpcId: 'vpc-8932jkdw',
        availabilityZones: ['ap-northeast-1a', 'ap-northeast-1c'],
        publicSubnetIds: ['subnet-8302sba', 'subnet-32890231'],
        privateSubnetIds: ['subnet-9042389fdjosa', 'subnet-re032109jifds']
      })

    const cluster = Cluster.fromClusterAttributes(this, 'Cluster', {
      clusterName: 'api-cluster-name',
      vpc,
      securityGroups: []
    })
  }
}

このように、<リソース名>.from<設定するアトリビュート>()とすると、現在のリソースから情報を取得し、その取得した結果を別のリソース作成時に使い回すといったことができます。

実行時は下記のようにTypeScriptをJS化した上で通常のJavaScriptを実行するだけなので、環境変数の注入など、動的に指定することが可能です。

cdk synth --app 'node index.js' > ../template.yml

いいところ

上記で紹介したとおり、環境変数などを用いて動的にパラメータを注入できるわけですが、それが生きるポイントとしては、 何かをビルドしたときにインフラを用意する というユースケースが考えられます。

CDKを使っているということは必然的にAWSを用いているということになるわけですが、例えばあるリポジトリでCodeBuildで環境を整備しようとしたときにbuildspec.ymlを配置すると思うのですが、そちらに下記のように指定することによって、dockerイメージを作成したあとにそのイメージを使って環境を作るといったことが可能になります。

phases:
  install:
    commands:
      - npm install -g npm@6.12.0 aws-cdk@1.14.0

  build:
    commands:
    # ... docker build
      - npm ci
      - npm run build
      - cdk synth --app 'node index.js' > template.yml
artifacts:
  files:
    - template.yml

こちらのartifactsを使ってCloudFormationを立ち上げるといった具合です。 この際、例えばCodeBuildに対して特定の条件を分岐させるような環境変数を提供し、それをコード化することによって必要な環境をよしなに作ることができます。

const vpc = Vpc.fromVpcAttributes(
  this,
  'Vpc',
  {
    vpcId: 'vpc-8932jkdw',
    availabilityZones: ['ap-northeast-1a', 'ap-northeast-1c'],
    publicSubnetIds: ['subnet-8302sba', 'subnet-32890231'],
    privateSubnetIds: ['subnet-9042389fdjosa', 'subnet-re032109jifds']
  })
if(process.env.SOME_CONDITION){
  Cluster.fromClusterAttributes() //...ECSを立ち上げる
} else {
  Repository.fromRepositoryName() //... ECRからなにか取る
}

相性のいい環境

上記のようによしなに分岐ができるため、例えば特定の環境のみを再現したい場合の プレビュー環境 や、単純に日頃使い慣れている言語で、サクッと環境を作りたい サーバーサイドのエンジニア などがこの昨日を使うといいかもしれません。

相性が良くない環境

CDKは、 @aws-cdk/aws-ecs-patternsApplicationLoadBalancedFargateService など、便利な関数を呼び出す形で組み立てていきます。 型である程度中を推論できるものの、ハードコーディングされているオプションなどがあり、細かいチューニングには向かないかなと思いました。

Terraform

Use Infrastructure as Code to provision and manage any cloud, infrastructure, or service

https://www.terraform.io/

Terraformのサイトから引用したのですが、文字通り、AWS以外のクラウドインフラにおいて使えるIaCのツールとなります。

使用感

下記のように、独自のDSLを用いて記述していきます。 HashiCorpプラグインなどを使うことによって、設定できるパラメータが何があるかと言うのをある程度推論してくれます。

resource "aws_alb" "default" {
  name = local.alb_name

  security_groups = [
    aws_security_group.alb.id,
  ]

  subnets = data.aws_subnet_ids.main.ids
}

resource "aws_alb_listener" "http" {
  default_action {
    target_group_arn = aws_alb_target_group.default.arn
    type             = "forward"
  }

  protocol          = "HTTP"
  load_balancer_arn = aws_alb.default.arn
  port              = 80
}

実行は基本的にサイト上にあるバイナリファイルをダウンロードしてきて、それを実行していく形になります。

terraform plan # 仮実行
terraform apply # 本実行

実行後はstateというストレージに環境全体の情報が格納され、次回以降の実行時はこのstateと実際のインフラ環境、コードの状況を比較し、差分のみを実行するといったことを行ってくれます。

いいところ

一つ一つしっかり記述していくため、細かいチューニングができるのが特徴です。 また、バイナリの方でフォーマットのコマンドも用意されているため、基本だれが書いても同じようなコードになります。

また、importという機能があり、Webコンソールなどですでに構築されている環境の状態をstateに持ってくる機能があるため、試しにWebコンソールで環境を作ったあと、importでコード化するということができます。

相性のいい環境

基本的に運用し続ける環境で効果を発揮すると思われます。理由としては、

  • 差分適応による効率的な環境設定ができる点
  • import機能による、コード化の簡易性
  • インフラ構築に特化した、宣言型の実装

というところで、メンテナンスに適しているためです。 また、workspaceを用いることによって、本番環境と同等の環境を手軽に別の環境で作成することができるため、本番適応前の最終確認などが手軽に行えるといった点も評価できるポイントです

相性の悪い環境

すべてのパラメータを宣言的に書くという仕様上、あまり動的に変わるようなインフラ環境には向かないと思われます。 動的に変更したい場合はCDKを検討しましょう

まとめ

CDKとTerraformを比較してきました。それぞれ一長一短あると思いますが、よしなに使い分けていけるといいかなと思っております。

元記事

kotamat.com