LoginSignup
2
0

More than 3 years have passed since last update.

CDK for Terraformが発表されたので試してみた!

Last updated at Posted at 2020-07-17

はじめに

2020/7/16にCDK for Terraformが発表されました!

https://aws.amazon.com/jp/blogs/developer/introducing-the-cloud-development-kit-for-terraform-preview/
https://www.hashicorp.com/blog/cdk-for-terraform-enabling-python-and-typescript-support/

Python と TypeScript がサポートのようなので、TypeScriptの環境を構築してみました。

実行バージョン

  • node version: v12.18.2
  • npm version: 6.14.6

インストール

npm i -g cdktf-cli

初期化

mkdir vpc-example
cd vpc-example
cdktf init --template=typescript --local

今回は検証のためTerraform Cloudを使わずにいきます。

実行状態みてみると、ローカルにインストールしていたyarnが使われましたね。

生成ディレクトリの確認

├── .gen
│   └── providers
│       └── aws
│        ├── accessanalyzer-analyzer.ts
│        ├── # omitted for clarity
│        └── xray-sampling-rule.ts
│   └── modules
├── .terraform
├── cdktf.json
├── help
├── main.d.ts
├── main.js
├── main.ts
├── package.json
└── tsconfig.json

.genの中にリソースなどのクラスファイルが生成されています。
例えば .gen/providers/aws/vpc.ts を確認してみると以下のような構造になっていました。

import { Construct } from 'constructs';
import { TerraformResource } from 'cdktf';
import { TerraformMetaArguments } from 'cdktf';

export interface VpcConfig extends TerraformMetaArguments {
  readonly assignGeneratedIpv6CidrBlock?: boolean;
  readonly cidrBlock: string;
  readonly enableClassiclink?: boolean;
  readonly enableClassiclinkDnsSupport?: boolean;
  readonly enableDnsHostnames?: boolean;
  readonly enableDnsSupport?: boolean;
  readonly instanceTenancy?: string;
  readonly tags?: { [key: string]: string };
}

export class Vpc extends TerraformResource {

  // ===========
  // INITIALIZER
  // ===========

  public constructor(scope: Construct, id: string, config: VpcConfig) {
    super(scope, id, {
      terraformResourceType: 'aws_vpc',
      terraformGeneratorMetadata: {
        providerName: 'aws'
      },
      provider: config.provider,
      dependsOn: config.dependsOn,
      count: config.count,
      lifecycle: config.lifecycle
    });
    this._assignGeneratedIpv6CidrBlock = config.assignGeneratedIpv6CidrBlock;
    this._cidrBlock = config.cidrBlock;
    this._enableClassiclink = config.enableClassiclink;
    this._enableClassiclinkDnsSupport = config.enableClassiclinkDnsSupport;
    this._enableDnsHostnames = config.enableDnsHostnames;
    this._enableDnsSupport = config.enableDnsSupport;
    this._instanceTenancy = config.instanceTenancy;
    this._tags = config.tags;
  }

  // methods
}

なるほど、Vpcのコンストラクタで、

  • scope
  • id
  • config

を渡す感じですね。

configはVpcConfig interfaceになっているので、エディタで補完できますね。これは楽そうです。

実装

早速公式を参考に実装してみましょう。

import { Construct } from 'constructs';
import { App, TerraformStack, Token } from 'cdktf';
import { AwsProvider, Subnet, Vpc } from './.gen/providers/aws';

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

    new AwsProvider(this, 'aws', {
      region: 'ap-northeast-1'
    });

    const vpc = new Vpc(this, 'my-vpc', {
      cidrBlock: '10.0.0.0/16'
    })

    new Subnet(this, 'my-subnet', {
      vpcId: Token.asString(vpc.id),
      cidrBlock: '10.0.0.0/24'
    })
  }
}

const app = new App();
new MyStack(app, 'vpc-example');
app.synth();

npm run synth

でjsonを生成してくれます。

./cdktf.out/cdk.tf.json

環境を増やす

環境を増やしたい場合は愚直に新しいインスタンスを作成すればその分jsonへ吐き出されます。

TerraformStackやAppを増やしても、最後に定義したものしか生成されないようでした。

import { Construct } from 'constructs';
import { App, TerraformStack, Token } from 'cdktf';
import { AwsProvider, Subnet, Vpc } from './.gen/providers/aws';

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

    new AwsProvider(this, 'aws', {
      region: 'ap-northeast-1'
    });

    const vpcProduction = new Vpc(this, 'production-vpc', {
      cidrBlock: '10.0.0.0/16'
    })

    new Subnet(this, 'production-subnet', {
      vpcId: Token.asString(vpcProduction.id),
      cidrBlock: '10.0.0.0/24'
    })

    const vpcStaging = new Vpc(this, 'staging-vpc', {
      cidrBlock: '10.1.0.0/16'
    })

    new Subnet(this, 'staging-subnet', {
      vpcId: Token.asString(vpcStaging.id),
      cidrBlock: '10.1.0.0/24'
    })
  }
}

const app = new App();
new MyStack(app, 'vpc-example');

app.synth()

TypeScriptでかけるので、例えばVpcとSubnetの組み合わせを出力する関数作ったりとかできそうですね。

こんな風にしてみたり。

import { Construct } from 'constructs';
import { App, TerraformStack, Token } from 'cdktf';
import { AwsProvider, Subnet, Vpc } from './.gen/providers/aws';

function createVpcAndSubnet(scope: Construct, vpcCidr: string, baseName: string) {
  const vpc = new Vpc(scope, `${baseName}-vpc`, {
    cidrBlock: vpcCidr
  })

  const subnetBits: number = 24
  const subnetNetwork: string = vpcCidr.split('/')[0]

  new Subnet(scope, `${baseName}-subnet`, {
    vpcId: Token.asString(vpc.id),
    cidrBlock: subnetNetwork + '/' + subnetBits
  })
}

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

    new AwsProvider(this, 'aws', {
      region: 'ap-northeast-1'
    });

    createVpcAndSubnet(this, '10.0.0.0/16', 'production')
    createVpcAndSubnet(this, '10.1.0.0/16', 'staging')
  }
}

const app = new App();
new MyStack(app, 'vpc-example');

app.synth()

tfを直接書くよりめちゃくちゃ楽そうです。

反映

./cdktf.out/cdk.tf.json は Terraform JSON configuration fileになっているので

cd cdktf.out
terrafrom init
terraform plan
terraform apply

とかしていけば反映できますね!

今回はAWS環境を用意していないので試しません。

cdkを使って直接デプロイもできるようです。

cdktf deploy

まとめ

もとからTypeScriptかける方でしたら、導入コストは低く、TypeScriptの恩恵を得られそうです。

すでに動いているものを移植するのは結構苦労しそうですね。。。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0