CDK for Terraformでimport機能がリリースされたので試してみた
概要
CDKTFネタ第2弾です。
CDKTF 0.19 から待望のimportやmoveがサポートされるようになったので試してみたいと思います。importからのコード生成やリソースの移動もできるようになってますが、今回はimportのみ。
初期設定
をベースに進めます。今回はmoduleは利用しないので設定は不要です。ただ、今回はtfstateの管理をS3で行う設定で行います。
検証で利用するAuroraはマネージメントコンソールから作成する時にデフォルト指定でできるものを利用します。データベースエンジンはpostgres互換
AuroraCluster: database-1
AuroraClusterInstance: database-1-instance-1
cdktf.json
tfstate ファイルを管理するS3バケットは予め作成しておき、bucketに指定する。 auroraClusterIdは作成したAuroraClusterのIDを指定。projectNameも適宜変更。
tfstate ファイルは 以下のようなパスで管理されるようになります。
XXXXXXXXXXXXXXXXXXXXXXXXXX-terraformstate-bucket/sample/terraform.tfstate
{
"language": "typescript",
"app": "npx ts-node main.ts",
"projectId": "f6bb6b84-3ff3-484f-9620-f031d4666947",
"sendCrashReports": "false",
"terraformProviders": [
"hashicorp/aws@~>4.0"
],
"terraformModules": [],
"context": {},
"terraformBackend": {
"s3": {
"bucket": "XXXXXXXXXXXXXXXXXXXXXXXXXX-terraformstate-bucket",
"key": "terraform.tfstate",
"region": "ap-northeast-1",
"encrypt": true
}
},
"projectName": "sample",
"rdsConfig": {
"auroraClusterId": "database-1",
"engine": "aurora-postgresql",
"instanceClass": "db.t4g.medium"
}
}
main.ts
defaultTagsなどは独自で設定してあるので、適宜環境に合わせてカスタマイズ 特に MyStack の第2引数で指定しているsampleなど
import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { S3Backend } from 'cdktf';
import { AwsProvider } from "@cdktf/provider-aws/lib/provider";
import * as fs from 'fs';
import * as path from 'path';
const configPath = path.join(__dirname, './', 'cdktf.json');
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
// aws provider
import * as aws from '@cdktf/provider-aws';
class MyStack extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id);
// define resources here
// Define AWS provider
new AwsProvider(this, 'aws', {
region: 'ap-northeast-1', // Example: 'us-west-2'
defaultTags: [{
tags: {
environment: id,
IaC: 'cdktf',
BillingGroup: `test/${id}`
}
}]
});
// S3 backend configuration
new S3Backend(this, {
bucket: config.terraformBackend.s3.bucket,
key: `${id}/${config.terraformBackend.s3.key}`,
region: config.terraformBackend.s3.region,
encrypt: true,
});
// Aurora cluster
const auroraClusterId = config.rdsConfig.auroraClusterId; // Aurora cluster ID
new aws.rdsCluster.RdsCluster(this, "auroracluster", {
engine: config.rdsConfig.engine,
}).importFrom(auroraClusterId); // import existing resource
const instanceCount = 1; // インスタンス数
for (let i = 0; i < instanceCount; i++) {
let auroraInstanceName = `${auroraClusterId}-instance-${i + 1}`;
new aws.rdsClusterInstance.RdsClusterInstance(this, `auroraclusterinstance${i + 1}`, {
clusterIdentifier: auroraClusterId,
engine: config.rdsConfig.engine,
instanceClass: config.rdsConfig.instanceClass,
}).importFrom(auroraInstanceName); // import existing resource
}
}
}
const app = new App();
new MyStack(app, "sample");
app.synth();
これで準備はOKです。
実行
この状態でdiffを実行してみます。 第2引数はmain.tsで指定している値を指定します。
cdktf diff sample
出力内容(一部省略しています。)
デフォルト設定から変わる箇所が出力されます。変更しても問題ない場合は引き続きdeploy実行、実際に合わせたい場合はmain.tsを修正します。今回は変更しても問題ない差分なのでそのままdeployを実行します。
Terraform will perform the following actions:
sample # aws_rds_cluster.auroracluster (auroracluster) will be updated in-place
# (imported from "database-1")
~ resource "aws_rds_cluster" "auroracluster" {
allocated_storage = 1
cluster_identifier = "database-1"
cluster_members = [
"database-1-instance-1",
]
~ copy_tags_to_snapshot = true -> false
+ enable_global_write_forwarding = false
engine = "aurora-postgresql"
engine_mode = "provisioned"
engine_version = "14.9"
engine_version_actual = "14.9"
~ skip_final_snapshot = true -> false
storage_encrypted = true
tags = {}
~ tags_all = {
+ "BillingGroup" = "test/sample"
+ "IaC" = "cdktf"
+ "environment" = "sample"
}
}
Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Saved the plan to: plan
To perform exactly these actions, run the following command to apply:
terraform apply "plan"
diff実行時のエラーについて
以下のようなエラーになった場合はインポート対象のリソースが存在しないということなのでimportFromの値と実際のリソース名で差異がないか確認します。
│ Error: Cannot import non-existent remote object
│
│ While attempting to import an existing object to
│ "aws_rds_cluster_instance.auroraclusterinstance0", the provider detected
│ that no object exists with the given id. Only pre-existing objects can be
│ imported; check that the id is correct and that it is associated with the
│ provider's configured region or endpoint, or use "terraform apply" to
│ create a new remote object for this resource.
反映
cdk deploy sample
初期作成時には付与されていなかったタグなどが設定されていることが確認できます。
注意点
この状態でdiffを実行しても差分なしとでるが、main.tsには必須パラメータのみなので再現性が担保されているわけではありません。そのため、削除してしまったりするとパラメータグループやサブネットグループなど元々の設定とは異なる設定になってしまいます。CDKTFでの管理していくということであれば設定内容を確認、main.tsに反映、差分がないことを確認する必要がります。
確認コマンド
terraform -chdir="cdktf.out/stacks/sample" show
Auroraで即時実行したい場合
Auroraの場合、即時反映、メンテナンスウィンドウでの反映をパラメータ指定で行う必要があります。即時実行したい場合はapplyImmediatelyのパラメータ指定でtrueにします。
まとめ
CDKでもterraformでもサポートされているimport機能ですが、CDKTFでも比較的あっさりimportできるようになってIaC体験がよいです。今回の記事には記載しませんでしたが、GitHubActionsに組み込んでプルリクエストトリガーで反映できるようにもしてあるので次回以降にその内容で記事を描きたいと思います。 ではよきIaCライフを!