AWS入門 - AWS CDK 使ってみる
AWSを使う必要が出てきたので、色々と試してみる。
ここでは、AWS CDK を試す。
AWS CDK
AWS CDK とは CloudFormation を通じて、リソースを定義できる仕組みである。
特にTypeScriptなどのプログラミング言語で、プログラムとして記述できる特徴がある。
CLI
AWS CDK を使ってアプリケーションリソースを定義してみるので、CLIをインストールする。
$ npm install aws-sdk -g
$ cdk --version
1.128.0 (build 1d3883a)
CDKアプリケーション
CDKアプリケーションを作成するため、インストールしたCLIから新規作成用のコマンドを実行する。
これによって、CDKでリソースを記述するための雛形が作成される。
$ cdk init app --language typescript
$ tree -L 1 .
.
├── README.md
├── bin
├── cdk.json
├── jest.config.js
├── lib
├── node_modules
├── package-lock.json
├── package.json
├── test
└── tsconfig.json
スタック
デプロイ可能な単位のことをCDKではStackと呼ぶらしい。
lib/ec2-chat-stack.ts
にStackを記述できるので、追記していく。
内容はシンプルで、EC2インスタンスを立ち上げる、ために必要な情報を記述していく。
import * as cdk from '@aws-cdk/core';
import * as ec2 from "@aws-cdk/aws-ec2"; // Allows working with EC2 and VPC resources
import * as iam from "@aws-cdk/aws-iam"; // Allows working with IAM resources
import * as keypair from "cdk-ec2-key-pair"; // Helper to create EC2 SSH keypairs
export class Ec2ChatStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// デフォルトで用意されているVPCを選択
const vpc = ec2.Vpc.fromLookup(this, "VPC", {
isDefault: true,
});
// EC2用のSSH鍵を作成
// --> Secrets Manager で作成・保存される
const key = new keypair.KeyPair(this, "KeyPair", {
name: "cdk-keypair",
description: "Key Pair created with CDK Deployment",
});
key.grantReadOnPublicKey;
// EC2用のセキュリティグループを作成
// --> SSHとHTTPでアクセスするためのポートを許可する
const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", {
vpc,
description: "Allow SSH and HTTP in",
allowAllOutbound: true,
});
securityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(22),
"Allow SSH Access"
);
securityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
"Allow HTTP Access"
);
// EC2用のロールを作成
// --> EC2インスタンスから各AWSサービスにアクセス出来る権限を付与する
// --> 細かい意味は別途確認してみる
const role = new iam.Role(this, "ec2Role", {
assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
});
role.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
);
// EC2用のインスタンスタイプ・マシンイメージ
// --> t2.micro を指定
// --> Amazon Linux 2 を指定
// --> セキュリティグループ・SSH鍵・ロールも指定
const ec2Instance = new ec2.Instance(this, "Instance", {
vpc,
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T2,
ec2.InstanceSize.MICRO
),
machineImage: new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
cpuType: ec2.AmazonLinuxCpuType.X86_64,
}),
securityGroup: securityGroup,
keyName: key.keyPairName,
role: role,
});
// ---------- //
new cdk.CfnOutput(this, "IP Address", {
value: ec2Instance.instancePublicIp,
});
new cdk.CfnOutput(this, "Download Key Command", {
value: "aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text > cdk-key.pem && chmod 400 cdk-key.pem",
});
new cdk.CfnOutput(this, "ssh command", {
value: `ssh -i cdk-key.pem -o IdentitiesOnly=yes ec2-user@${ec2Instance.instancePublicIp}`,
});
}
}
Bootstrap
CDKで利用するアカウント情報を設定する。
bin/ec2-chat.ts
でコメントアウトされている部分を解除する。
これで、AWS CLI で設定したIDとリージョンが使われるようになる。
そして、cdk bootstrap
コマンドを実行すると、CDKを使用するための下準備が行われる。
関連ファイルを保存するためのS3を用意したり、必要なIAMを設定したりしてくれるらしい。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { Ec2ChatStack } from '../lib/ec2-chat-stack';
const app = new cdk.App();
new Ec2ChatStack(app, 'Ec2ChatStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
デプロイ
そして、cdk deploy
コマンドを実行すると、記述した内容をもとにリソースが作成される。
$ cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
IAM Statement Changes
┌───┬──────────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${EC2-Key-Pair-Manager-Role.Arn} │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
├───┼──────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${ec2Role.Arn} │ Allow │ sts:AssumeRole │ Service:ec2.amazonaws.com │ │
└───┴──────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬──────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼──────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${EC2-Key-Pair-Manager-Role} │ ${EC2-Key-Pair-Manager-Policy} │
│ + │ ${EC2-Key-Pair-Manager-Role} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
├───┼──────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${ec2Role} │ arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore │
└───┴──────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
Security Group Changes
┌───┬──────────────────────────┬─────┬────────────┬─────────────────┐
│ │ Group │ Dir │ Protocol │ Peer │
├───┼──────────────────────────┼─────┼────────────┼─────────────────┤
│ + │ ${SecurityGroup.GroupId} │ In │ TCP 22 │ Everyone (IPv4) │
│ + │ ${SecurityGroup.GroupId} │ In │ TCP 80 │ Everyone (IPv4) │
│ + │ ${SecurityGroup.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴──────────────────────────┴─────┴────────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Do you wish to deploy these changes (y/n)? y
Ec2ChatStack: deploying...
[0%] start: Publishing afe67465ec62603d27d77795221a45e68423c87495467b0265ecdadad80bb5e2:current
[100%] success: Published afe67465ec62603d27d77795221a45e68423c87495467b0265ecdadad80bb5e2:current
Ec2ChatStack: creating CloudFormation changeset...
✅ Ec2ChatStack
Outputs:
Ec2ChatStack.DownloadKeyCommand = aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text > cdk-key.pem && chmod 400 cdk-key.pem
Ec2ChatStack.IPAddress = 54.178.111.86
Ec2ChatStack.sshcommand = ssh -i cdk-key.pem -o IdentitiesOnly=yes ec2-user@54.178.111.86
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:111111111111:stack/Ec2ChatStack/f6763df0-332a-11ec-b117-0e64b831f3c9
Secrets Manager
作成したSSH鍵はSecrets Managerに登録されている。
ec2-ssh-key/cdk-keypair/private
という名前で登録されている。
これをAWS CLIとかで参照して、SSH時に指定すればインスタンス内にアクセスできる。
$ aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text > cdk-key.pem
リソース削除
作成したリソースはcdk destroy
コマンドを実行すると、削除できる。
$ cdk destroy
Are you sure you want to delete: Ec2ChatStack (y/n)? y
Ec2ChatStack: destroying...
✅ Ec2ChatStack: destroyed
****************************************************
*** Newer version of CDK is available [1.129.0] ***
*** Upgrade recommended (npm install -g aws-cdk) ***
****************************************************
まとめ
プログラムとして定義できるのは良い。
特に開発・検証・本番のように、複数かつ同等のAWS環境を構築するのが非常に楽になるはず。
Amazon EC2 でウェブアプリケーションをデプロイする
Discussion