本記事は、BIPROGY / ユニアデックス社内AWSコミュニティ「BIPROGY AWS SPARK」の定期投稿企画第1回目の記事です。
他の定期投稿企画の記事はインデックスページをご覧ください。
1. はじめに
BIPROGYの豊田です。
今回は、AWS SPARKの活動の一環として、AWSに関する記事を投稿します。
この記事の対象者
- IaCの基本的な概念を理解している方
- IaCを実装したことがある方
- IaCを導入したものの、再利用まで十分に取り組めていない方
- これからIaCを導入してみたい方
本記事では、IaCそのものの基本的な説明は省略します。
私の所属する組織では、現在もGUIを前提としたインフラ構築がメインであり、IaCはあまり利用されていません。
その背景には、IaCに関する次のような考えがあります。
GUIで構築できるものを、なぜコードで書く必要があるのか。
コーディングや検証が増える分、IaCのほうが工数がかかるのではないか。
一つの環境を一度だけ構築するのであれば、GUIのほうが早い場合はあると思います。私もすべての開発においてIaCを利用すべきとは考えていません。
ただ、現状IaCの重要な特徴である再利用性が考慮されておらず、そういった点を考慮せずにただIaCは工数がかかるという判断をするのは検討不足かなと考えています。
IaCの工数削減の正体
IaC工数削減は、最初の構築をGUIより早く終わらせることだけではなく、一度作成した構成を別の環境やプロジェクトでも利用し、同じ設計や実装を繰り返さずに済む点にあると考えています。
しかし、ただコードを作成すれば、そのまま再利用できるわけではありません。プロジェクト内だけで使い終えてしまえば、次のプロジェクトでも同じようなコードを作ることになります。こうなってしまうと、結局「GUIでいいよね」という話になります。
ここは実装編でも触れるつもりですが、再利用できるようStackとConstructの設計が重要になります。
私自身もIaCの導入を進めるなかで、まずはプロジェクト内でコードを完成させることに意識が向いていました。作成したコードを次のプロジェクトでどう活用するかまでは、十分に整理できていませんでした。
そこで、本記事ではAWS CDKを題材として、次の問いを考えます。
AWS CDK(IaC)は、本当に工数削減につながるのか。
また、再利用するためにはどうすればよいのか。
今回は概念編として、App、Stack、Construct、Propsの役割と、独自に作成したConstructを別のプロジェクトから再利用する方法を整理します。
続く実装編では、実際に独自のConstructを作成し、Propsを渡して利用します。さらに、作成したConstructをパッケージ化し、別のプロジェクトから再利用してみます。
2. AWS CDKはコードをどのような単位で整理するのか
前章では、IaCによる工数削減の効果を得るためには、作成したコードを再利用できる形に整理する必要があると述べました。
AWS CDKでは、Appを起点として、その配下にStack、さらにStackの配下にConstructを配置します。この構造はコンストラクトツリーと呼ばれています。
App
└─ Stack
├─ Construct
└─ Construct
App
AppはCDKアプリケーションの起点。
Appの配下には、デプロイするStackを配置する。
一つのAppに複数のStackを配置することも可能。
App
├─ NetworkStack
└─ ApplicationStack
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { NetworkStack } from '../lib/hello-cdk-stack';
import { ApplicationStack } from '../lib/hello-cdk-stack';
//以下の部分がAppに該当する部分、プロジェクトのエントリーポイント
const app = new cdk.App();
//作成したいStackを定義
new NetworkStack(app, 'HelloNetworkStack', {
});
new ApplicationStack(app, 'HelloApplicationStack', {
});
Appでは、どのStackを利用するかを定義し、Stackの生成に必要な設定値を渡す。
Stack
Stackは、AWS CloudFormationのStackとして合成・デプロイされる単位。
Stackの配下には、構築するリソースを表すConstructを配置する。
Stackでは、デプロイ対象となる構成に応じて必要なConstruct(部品)を組み合わせる。
App
└─ ApplicationStack
├─ NetworkConstruct
├─ StorageConstruct
└─ MonitoringConstruct
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class ApplicationStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 使用するConstructを記載
}
}
Construct
Constructは、AWS CDKにおいてAWSリソースやその構成を表現する基本的な単位。
一つのAWSリソースを表すこともあれば、複数のAWSリソースをまとめて一つの構成としてコーディングすることも可能。
また、Construct HubからConstructをインポートしたり既存のConstructを組み合わせてカスタムすることも可能。
Props
StackやConstructを生成する際には、設定値をPropsとして渡す。
PropsはStackやConstructを利用する側から、必要な設定値を渡すためのオブジェクト。
Propsに渡す値をシステムやプロジェクトの要件に応じてカスタマイズすることで同じStackやConstructを利用する場合でも環境名やリソース名などの設定値を変えることが可能。
DevelopmentStack
└─ StorageConstruct
└─ 開発環境用のProps
ProductionStack
└─ StorageConstruct
└─ 本番環境用のProps
AWS CDKではこのような単位でコードを整理します。どれもCDKを扱ううえで重要な要素ですが、再利用という観点では、特にConstructとPropsが重要になります。共通化させたい構成や設定をConstructとして定義し複数のStackから呼び出す際に、環境やプロジェクトごとに異なる値をPropsとして渡せるためです。
次章では、このConstructとPropsを利用して、AWS CDKのコードをどのように再利用するのかを整理します。
3. AWS CDKではどのようにコードを再利用するのか
前章では、AWS CDKにおけるApp、Stack、Construct、Propsの役割を整理しました。
同じプロジェクト内であれば、定義したConstructを複数のStackから呼び出せます。また、環境ごとに異なる設定値をPropsとして渡すことで、同じConstructの定義を利用しながら、環境ごとに設定を変えられます。
一方、別のプロジェクトでも同じConstructを利用する場合は、Constructをプロジェクト固有のコードから外出しし、複数のプロジェクトから参照できる形にします。
TypescriptでAWS CDKを利用する場合は、独自に定義したConstructをnpmパッケージとして管理します。
共通Constructのパッケージ
└─ StorageConstruct
↓
├─ Project A
├─ Project B
└─ Project C
各プロジェクトでは、共通Constructのパッケージをインストールし、必要なConstructをインポートします。利用する環境やプロジェクトによって異なる設定値はPropsとして渡します。
Project A
└─ StorageConstruct
└─ Project A用のProps
Project B
└─ StorageConstruct
└─ Project B用のProps
この形にすることで、各プロジェクトへConstructのファイルをコピーするのではなく、複数のプロジェクトから同じConstructの定義を利用できます。
AWS CDKの再利用を実現するための概念と再利用の方法について整理しました。
続く実装編では、概念編で整理した流れに沿って、実際に独自のConstructを作成し、Propsを渡して利用します。さらに、作成したConstructをパッケージ化し、別のプロジェクトから再利用してみます。
4. 番外編:AWS CDKとTerraformを比べてみた
筆者はもともとTerraformを利用していました。
この章では、そんな筆者がAWS CDKを実際に扱ってみて感じたメリット・デメリットについて、軽く語っていきます。
これからIaCを学んでみたい方や、TerraformとAWS CDKのどちらを使うか迷っている方の参考になればと思います。
メリット:可読性が高い
コンストラクトツリーの構造があり、それぞれの層で扱うべき内容がある程度決まっている
そして各層で渡したい値はPropsで渡す。
基本的に上から下に流していくイメージです。
そしてTypescriptであればインタフェースを利用した型定義を行うことでコーディングの時点で実装ミスに気付ける点もよいなと思いました。
Terraformだとモジュール間でのパラメータの受け渡しはOutputを定義し、ルートモジュール(main.tf)で受け取り、各モジュールに値を渡すといった感じになります。
モジュールが多くなってくるとOutputで扱うパラメータも多くなり受け渡しの流れも複雑になり可読性が低くなってしまうことがよくありました。
各パラメータがmain.tfを親としてモジュールを子として上下に流れるイメージです。
ルートモジュール
├─ NWモジュール
│ └─ リソースA
├─ DBモジュール
│ └─ リソースB
└─ Monitorモジュール
└─ リソースC
上記のような構成だとリソースAからリソースBに値を渡したいときはmain.tfを経由しなければならず、値の流れが非常にわかりづらい….
これに関しては私のTerraformのモジュール設計が下手なだけかもしれませんが……
デメリット:学習コストがかかる
恥ずかしながら筆者はコーディングに苦手意識があります。
そういった筆者からすると、Terraformには宣言型(?)のわかりやすさがありました。作成したいリソースと設定値を記述していくため、「何をどうやって作りたいのか」がコードから直感的に分かりやすく、比較的学びやすいと感じました。
CDKではまず使用するプログラミング言語について基本的な理解が必要です。今回使用したTypescriptであれば、クラス、インスタンス、オブジェクト、インターフェース、型などを理解する必要があります。
そのうえで、App、Stack、Construct、PropsといったCDK固有の概念も学ぶ必要があります。
コーディングに慣れている人、AWS CDKが対応している言語の経験がある人であれば問題ないのかもしれませんが、筆者のようにコーディングに苦手意識がある人にとっては、学習コストは高いのかなと感じました。
デメリット:AWSでしか扱えない
当たり前といえば、当たり前ですが。
AWS CDKはAWSでしか利用できません。
その点はTerraformのほうはマルチクラウド対応しており圧倒的に便利です。
業務でAWSだけでなくGCPやAzureも扱うという人にはTerraformのほうがおすすめかもしれません。
所感としてはAWS CDKはほかのIaCと比べて学習コストがより高い分、便利かつ読みやすい点があるかなと思いました。
ことAWSにおいてはどちらを選べばよいのか悩ましいですね。IaC初心者であればTerraform、ある程度プログラミングの経験や自信があればAWS CDKといった感じでしょうか。
最後に、ここまで読んでいただきありがとうございました。
それでは実装編でまた会いましょう。
BIPROGYグループの技術への取り組み
We Are Hiring!