cdktfをOpenStackでつかってみた
はじめに
プロジェクトでAWS CDKを使う機会が増えています。linterやテストコード書いてCI回したり、静的型付けを実施できたりと、今までインフラの世界では通用しなかった高級言語のナレッジが適用できるようになって嬉しいですよね! そこで、自宅で立てているOpenStackでも同様の恩恵が得られないかと調べていたところ、cdktfで取り急ぎ高級言語化できそうだったので、今回試してみました。。。
実際に使ってみた
cdktfはterraformをcdkフレームワークにくるんだプロダクトです。terraformにはOpenStackのプロバイダも用意されているので、このプロバイダを使ってOpenStackもcdkの世界につれてくることができます!
まずはcdktfプロジェクトを作成しましょう。
$ mkdir cdk-openstack $ cd cdk-openstack $ npm install -g cdktf-cli $ npx cdktf init --template="typescript" --local Note: By supplying '--local' option you have chosen local storage mode for storing the state of your stack. This means that your Terraform state file will be stored locally on disk in a file 'terraform.tfstate' in the root of your project. We will now set up the project. Please enter the details for your project. If you want to exit, press ^C. Project Name: (default: 'cdk-openstack') Project Description: (default: 'A simple getting started project for cdktf.') npm notice created a lockfile as package-lock.json. You should commit this file. + cdktf@0.0.18 + constructs@3.2.51 added 4 packages from 4 contributors and audited 4 packages in 0.482s found 0 vulnerabilities npm WARN eslint-plugin-react@7.21.5 requires a peer of eslint@^3 || ^4 || ^5 || ^6 || ^7 but none is installed. You must install peer dependencies yourself. + cdktf-cli@0.0.18 + @types/node@14.14.10 + typescript@4.1.2 added 226 packages from 142 contributors and audited 231 packages in 8.713s 54 packages are looking for funding run `npm fund` for details found 0 vulnerabilities > cdk-openstack@1.0.0 build /home/ubuntu/workspaces/gitlab-com/cdk-openstack > cdktf get && tsc Generated typescript constructs in the output directory: .gen ======================================================================================================== Your cdktf typescript project is ready! cat help Print this message Compile: 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 cdktf get and compile typescript Synthesize: cdktf synth Synthesize Terraform resources from stacks to cdktf.out/ (ready for 'terraform apply') Diff: cdktf diff Perform a diff (terraform plan) for the given stack Deploy: cdktf deploy Deploy the given stack Destroy: cdktf destroy Destroy the stack Upgrades: npm run get Import/update Terraform providers and modules (you should check-in this directory) npm run upgrade Upgrade cdktf modules to latest version npm run upgrade:next Upgrade cdktf modules to latest "@next" version (last commit) Use Prebuilt Providers: You can add one or multiple of the prebuilt providers listed below: npm install -a @cdktf/provider-aws npm install -a @cdktf/provider-google npm install -a @cdktf/provider-azurerm npm install -a @cdktf/provider-docker npm install -a @cdktf/provider-github npm install -a @cdktf/provider-null Check for an up to date list here https://github.com/terraform-cdk-providers ======================================================================================================== $
できたプロジェクト内部はこんな感じです。
$ ls cdktf.json help main.d.ts main.js main.ts node_modules package-lock.json package.json tsconfig.json $
cdktf.json
をのぞいてみると、awsプロバイダしか定義されていないのがわかります。
{ "language": "typescript", "app": "npm run --silent compile && node main.js", "terraformProviders": [ "aws@~> 2.0" ], "context": { "excludeStackIdFromLogicalIds": "true", "allowSepCharsInLogicalIds": "true" } }
なので、 terraformProviders
から aws
を削除し、terraform-provider-openstack/openstack@1.33.0
を追加し、cdktf get
を叩きます。
{ "language": "typescript", "app": "npm run --silent compile && node main.js", "terraformProviders": [ "terraform-provider-openstack/openstack@1.33.0" ], "context": { "excludeStackIdFromLogicalIds": "true", "allowSepCharsInLogicalIds": "true" } }
$ npx cdktf get Generated typescript constructs in the output directory: .gen $
さて、そうしたら実際にインフラコードを書いていきましょう! main.ts
をのぞいてみると、、、
import { Construct } from 'constructs'; import { App, TerraformStack } from 'cdktf'; class MyStack extends TerraformStack { constructor(scope: Construct, name: string) { super(scope, name); // define resources here } } const app = new App(); new MyStack(app, 'cdk-openstack'); app.synth();
とにもかくにもopenstackモジュールをimportしましょう。以下のimport文を追加します。
import * as openstack from './.gen/providers/openstack';
そうしたら、 // define resources here
以降に認証情報やOpenStackリソースを定義していきます。まずは認証情報から、以下のように与えます。
new OpenstackProvider(this, "openstack-provider", { userName: process.env.OS_USERNAME, password: process.env.OS_PASSWORD, tenantName: process.env.OS_PROJECT_NAME, userDomainName: process.env.OS_USER_DOMAIN_NAME, projectDomainName: process.env.OS_PROJECT_DOMAIN_NAME, authUrl: process.env.OS_AUTH_URL, cacertFile: process.env.OS_CACERT });
openrc認証情報を使えるように、環境変数でパラメータを与えておきます。
次に、リソース定義をこんな感じで定義していきますー。
// define network for octavia const octaviaNetwork = new openstack.NetworkingNetworkV2(this, "OctaviaVlanProviderNetwork", { name: "lb-mgmt-net", external: true, shared: true, mtu: 1450, segments: [ { physicalNetwork: "octavia_vlan_provider", segmentationId: 121, networkType: "vlan" } ] }); // define subnet for octavia const octaviaSubnetCidr = "192.168.121.0/24"; new openstack.NetworkingSubnetV2(this, "OctaviaVlanProviderNetworkSubnet", { name: "lb-mgmt-subnet", cidr: octaviaSubnetCidr, networkId: octaviaNetwork.id, allocationPool: [ { start: "192.168.121.100", end: "192.168.121.254" } ], gatewayIp: "192.168.121.1" }); // define security group for amphora const amphoraSecurityGroup = new openstack.NetworkingSecgroupV2(this, "AmphoraSecurityGroup", { name: "amphora-sg", }); const amphoraSgIngressMaps = [ { protocol: "tcp", portRangeMax: 22, portRangeMin: 22, remoteIpPrefix: "0.0.0.0/0" }, { protocol: "tcp", portRangeMax: 9443, portRangeMin: 9443, remoteIpPrefix: octaviaSubnetCidr }, { protocol: "tcp", portRangeMax: 5555, portRangeMin: 5555, remoteIpPrefix: octaviaSubnetCidr } ]; for (const [index, amphoraSgIngressMap] of amphoraSgIngressMaps.entries()) { new openstack.NetworkingSecgroupRuleV2(this, `AmphoraSgRules${index}`, { securityGroupId: amphoraSecurityGroup.id, protocol: amphoraSgIngressMap.protocol, portRangeMax: amphoraSgIngressMap.portRangeMax, portRangeMin: amphoraSgIngressMap.portRangeMin, remoteIpPrefix: amphoraSgIngressMap.remoteIpPrefix, ethertype: "IPv4", direction: "ingress" }); }
あとは、openrc認証情報ファイルを読み込んで、npm run build
および cdktf deploy
を実行します。
$ npm run build > cdk-openstack@1.0.0 build /home/ubuntu/workspaces/gitlab-com/cdk-openstack > cdktf get && tsc Generated typescript constructs in the output directory: .gen $ $ npx cdktf deploy Deploying Stack: cdk-openstack Resources ✔ OPENSTACK_NETWORKING OctaviaVlanProvider openstack_networking_network_v2.OctaviaVlanProviderNetwork ✔ OPENSTACK_NETWORKING AmphoraSgRules02 openstack_networking_secgroup_rule_v2.AmphoraSgRules0 ✔ OPENSTACK_NETWORKING AmphoraSgRules12 openstack_networking_secgroup_rule_v2.AmphoraSgRules1 ✔ OPENSTACK_NETWORKING AmphoraSgRules22 openstack_networking_secgroup_rule_v2.AmphoraSgRules2 ✔ OPENSTACK_NETWORKING AmphoraSecurityGrou openstack_networking_secgroup_v2.AmphoraSecurityGroup ✔ OPENSTACK_NETWORKING OctaviaVlanProvider openstack_networking_subnet_v2.OctaviaVlanProviderNetworkSubnet Summary: 6 created, 0 updated, 0 destroyed. $
ちゃんとデプロイされました!!
所感
terraform providerが用意されているプラットフォームについてはこれで一応インフラコードを高級言語化できそうで良い感じですね! linterは少なくともGitLab CIで実行できるようにしておきたいものです。。。