この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どーもsutoです。
前回は3部構成でAWS Cloud Development Kit(CDK)を使ってPythonコードVPC+ノートブック構築をやってみました。
作成したノートブックは直接インターネット接続可能な状態で構築しましたが、今回はそれをプライベート通信Onlyの環境で作ってみようと思います。ついでにNATインスタンスにAuto Recovery設定の追加やっちゃいます。
コードは前回記事でデプロイした構成を編集するかたちで作成していきます。前回までのコードの内容は以下をご参照ください。
はじめに
今回やること
- ノートブック〜S3バケットの通信をVPCエンドポイント経由にする
- ノートブック〜外部通信(インターネット)をNATインスタンス経由にする
- NATインスタンスCloudwatch「Auto Recovery」を設定
デプロイ前の注意点
既存でデプロイしているプロジェクトを更新する場合は、サブネットのCIDRが競合してデプロイ時にエラーとなる場合がありますので、その際は、一旦destroyして再度作り直す必要があります。そうなると各インスタンスも一度Terminatedされて再作成となるので必ずリソースのバックアップを取っておきましょう。
CDK環境にSagemakerモジュール追加
前回作成したsage-nw
プロジェクトの仮想環境ディレクトリ内に入っている状態からスタートします。
~ sage-nw % source .env/bin/activate
(.env) ~ sage-nw %
setup.pyの「install_requires」部分を編集して必要なモジュールをインストールします。
install_requires=[
"aws-cdk.core",
"aws-cdk.aws-ec2",
"aws-cdk.aws-sagemaker",
"aws_cdk.aws_lambda",
"aws_cdk.aws_events",
"aws_cdk.aws_events_targets",
"aws_cdk.aws_cloudwatch",
"boto3",
],
pip install -r requirements.txt
コードを記述
「sage_nw」フォルダに移動してsage_nw_stack.py
を書き換えていきます。
コードの主な変更点は、
ec2.Vpc
でサブネットタイプをISOLATED
→PRIVATE
に変更、NATとエンドポイント の指定- NATインスタンスタイプを定義
- Cloudwatch設定を追加
書き換え後のsage_nw_stack.py
は以下となります。
from aws_cdk import (
core,
aws_ec2 as ec2,
aws_cloudwatch as cw
)
from sagemaker_stack import SagemakerStack
from lambda_stack import LambdaStack
class SageNwStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# The code that defines your stack goes here
# 変数の宣言
vpc_cidr = '10.1.0.0/16'
subnet_mask = 24
# 新規VPC作成(NAT構成)
natinstance_type = ec2.InstanceType('t3.micro')
nat_instance = ec2.NatProvider.instance(instance_type=natinstance_type)
vpc = ec2.Vpc(
self,
id="Sage-vpc",
cidr=vpc_cidr,
nat_gateways=1,
max_azs=2,
subnet_configuration=[
ec2.SubnetConfiguration(
cidr_mask=subnet_mask, name="public", subnet_type=ec2.SubnetType.PUBLIC,
),
ec2.SubnetConfiguration(
cidr_mask=subnet_mask, name="private", subnet_type=ec2.SubnetType.PRIVATE,
),
],
gateway_endpoints={
"S3": ec2.GatewayVpcEndpointOptions(
service=ec2.GatewayVpcEndpointAwsService.S3,
subnets=[{"subnet_type": ec2.SubnetType.PRIVATE}]
),
},
nat_gateway_provider=nat_instance,
)
security_group = ec2.SecurityGroup(
self,
id="Sage-sg",
vpc=vpc,
security_group_name="test-sg"
)
security_group.add_ingress_rule(
peer=ec2.Peer.ipv4(vpc_cidr),
connection=ec2.Port.all_traffic(),
)
subnet = vpc.private_subnets[0].subnet_id
sg = [security_group.security_group_id]
# ノートブックインスタンス作成
sagemaker = SagemakerStack(
self,
"Notebook",
subnetid = subnet,
sgid = sg,
)
# Lambda作成
lambda_autostop = LambdaStack(
self,
"AutoStop",
)
# NATインスタンスIDを取得
natinstance_id = vpc.public_subnets[0].node.find_child('NatInstance').instance_id
# Cloudwatch作成
alarm = cw.CfnAlarm(
self,
id='EC2AutoRecovery',
comparison_operator='GreaterThanThreshold',
threshold=0,
period=60,
evaluation_periods = 5,
statistic='Minimum',
alarm_name='nat-autorecovery',
namespace='AWS/EC2',
metric_name='StatusCheckFailed_System',
alarm_actions=["arn:aws:automate:ap-northeast-1:ec2:recover"],
dimensions=[
{
"name": 'InstanceId',
"value": natinstance_id
}
],
)
ec2.NatProvider
の宣言だけで、AWSが提供する最新のNATインスタンス用AMIを指定できるのは便利ですね。そこからNATインスタンスのIDを取得する必要があるので、.find_child
を使ってサブネット内の対象インスタンスを検索しています。
※余談ですが前回記事ではVPCの最大AZ数を指定していなかったので、今回のコードでは”2”を指定しています。
ノートブックインスタンスの通信もVPCエンドポイント およびNATインスタンス経由とするため、sagemaker_stack.py
で直接インターネット接続の設定をDisabledに変更します。
internet_access = 'Disabled'
また、今回のようにCDKからAMIイメージを取得する場合、スタックレベルでアカウント/リージョンを明示的に指定する必要がありますので、app.py
を以下のように書き換えます。
#!/usr/bin/env python3
import os
from aws_cdk import core
from sage_nw.sage_nw_stack import SageNwStack
app = core.App()
SageNwStack(app, "sage-nw", env=core.Environment(
account=os.environ["CDK_DEFAULT_ACCOUNT"],
region=os.environ["CDK_DEFAULT_REGION"]))
app.synth()
これでAWS CLI(.aws/config)に保存しているデフォルトの認証情報を取得できます。スイッチロール先のアカウントにデプロイさせたい場合は、cdkコマンド実行時に--profile
オプションで指定すればOKです。
スタックの確認とデプロイ
cdk synth
、cdk diff
コマンドでデプロイする内容を表示して確認します。
cdk synth
cdk diff sage-nw --profile suto
確認が終わったら以下コマンドでスタックを更新してみます。
(.env) ~ sage-nw % cdk deploy sage-nw --profile suto
スタックが更新されてリソースが作成されていることを確認できました。
まとめ
今回はNATインスタンス、VPCエンドポイント 、CloudWatch設定を構築するコードを書きました。CloudWatchではAlarm
やMetrics
を使った記述もできますが、アラームアクションの作り込みがちょっと難しかったのでCfnAlarm
を使いました。Cfnシリーズは最低限記述するコードが多少長くなるデメリットがある一方で、CloudFormationの定義と比較ができてわかりやすいというメリットがあります。
これまで使ってきて、AWS CDKはCLIでCloudFormationのコマンドをたたくよりもスタックの管理がラクだと感じているためどんどん使っていきたいと思います。