この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どーもsutoです。
最近データ分析や機械学習のワークフローやバッチジョブのためにAirflowを勉強しています。また検証環境の構築に、AWSのマネージドサービスとしてリリースされたAmazon Managed Workflow for Apache Airflow(MWAA)を触っています。
MWAAの特徴や料金の概要については以下のブログがわかりやすいです。
しかし、構築した環境は時間で課金され、Webサーバ用インスタンスも一時停止できる機能はありません。(本来の運用では24時間稼働しておくものだから当然ですけどね) 料金体系も最小構成で「$0.49/hour」なので、環境を作っただけで放置しておくと決して安くはない費用が発生します。
毎日の業務で使用するわけではないので、検証で使用する時のみ環境を立ち上げ/削除を行っているのですが、手動でやるのはさすがに手間になるので、必要なリソースを自動構築するCloudFormationテンプレートを作成しました。
また、今回は既存VPCを利用して環境を構築してみようと思いますので、MWAA環境におけるVPCの要件や全体のAWS料金について抑えるべきポイントを含めてご紹介していきます。
MWAA環境のためのVPC要件と料金の話
公式ドキュメントによると、MWAA環境用のVPCには以下の要件があります。
- 同じリージョン内の2つの異なるアベイラビリティーゾーンにある2つのプライベートサブネット。
- また、次のいずれかが必要になります。
- 上記プライベートサブネットがインターネットに接続するためのNAT Gatewayを配置した2つのパブリックサブネット。
- 以下のVPCエンドポイント(AWS Private Link)が作成されていること
- Amazon CloudWatch
- CloudWatch Logs
- Amazon ECR
- Amazon S3
- Amazon SQS
- AWS Key Management Service
ここで、NAT GatewayもVPCエンドポイントも時間による課金が発生することにご注意ください。
つまり、MWAAの環境立ち上げた際のAWS料金は、
- MWAA環境料金 + MWAAワーカー料金 + メタデータストレージ料金 + (NAT Gateway料金 or PrivateLink(6つ)料金)
となり、最小構成の概算見積でも月額で$500〜はかかることになりそうです。
MWAAのメリットと課題
(2021/3/24時点のものとなりますが)
メリット
- マネージドサービスのため環境の維持が楽
- Dag、Pligin、RequirementsはS3バケットで管理
- airflow.cfgの設定がコンソールで直接管理できる
- IAMの機能でログインユーザ管理ができる
課題と制約
- スケジューラ、ワーカー、またはWebサーバーインスタンスにSSHで接続することはできない
- 各種ログはCloudwatch Logsに出力されます
- メタデータデータベースに直接アクセスしてDAG情報を照会することはできない。また、メタデータをエクスポートする機能はまだ実装されていない
- DAG関連の情報はUIメニューからAPIを利用してアクセス可能
- Airflowのバージョンが限定されている
- AWSは以前のAirflowバージョンでセキュリティ上の懸念を認識していたため、MWAAは最新の安定バージョンのみをサポートしているとのこと
- 2.0はまだ未対応
- Webサーバインスタンスの一時停止はできない
その他によくある質問にもいろいろ記載されていますのでご参照ください。
既存VPC上にMWAA環境を構築してみた
では実際に既存VPCを利用してMWAA環境をCloudFormationで構築してみましょう。
※MWAA環境用VPCを新規で構築する場合は公式のテンプレートでVPCを自動構築できますのでご参照ください。
- 以下のような、既存VPCがあることを前提とします
- 異なるAZにあるパブリックサブネット2つと、プライベートサブネット2つ
- インターネットゲートウェイがアタッチ済
- 各ルートテーブルに1つのサブネットが関連付け
- MWAA用のセキュリティグループは作成済(デフォルトのSGでも可)
ネットワーク要件で不足しているリソースを一緒に追加構築するので、今回はCloudFormationで以下のリソースを構築します。
- MWAA環境
- MWAAの実行IAMロール
- NAT Gateway2台
- EIP2つ(NAT Gatewayアタッチ用)
※今回のMWAAのUIへのアクセスは パブリック
とします。
※※プライベートの場合は環境構築後、プロキシサーバ構成またはELB構成などの追加のネットワーク設定が必要ですが本記事では紹介しません(参考)
テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Resources creates an Amazon Managed Workflows for Apache Airflow (MWAA) environment
Parameters:
MWAAName:
Description: The version of Apache Airflow.
Type: String
Default: MyAirflowEnvironment
Version:
Description: The version of Apache Airflow.
Type: String
Default: 1.10.12
BucketName:
Description: The name of the S3 bucket that your environment accesses
Type: String
Default: bucket-name
DagS3Path:
Description: The relative path to the DAGs folder after your S3 bucket name.
Type: String
Default: /dags
PluginS3Path:
Description: The relative path to the plugins.zip file after your S3 bucket name.
Type: String
Default: /plugins.zip
RequirementsS3Path:
Description: The relative path to the requirements.txt file after your S3 bucket name.
Type: String
Default: /requirements.txt
EnvClass:
Description: The environment class name.
Type: String
Default: mw1.small
AllowedValues:
- mw1.small
- mw1.medium
- mw1.large
Accessmode:
Description: The environment class name.
Type: String
Default: PUBLIC_ONLY
AllowedValues:
- PUBLIC_ONLY
- PRIVATE_ONLY
MaxWorkerServer:
Type: Number
Default: 5
MaintenanceWindow:
Description: 'format is DAY:HH:MM.'
Type: String
Default: 'SUN:03:00'
PublicSubnetId1:
Type: String
PublicSubnetId2:
Type: String
PrivateSubnetId1:
Type: String
PrivateSubnetId2:
Type: String
MWAASGId:
Type: String
PrivateRouteTableId1:
Type: String
PrivateRouteTableId2:
Type: String
Resources:
# MWAA Environment
MWAA:
Type: 'AWS::MWAA::Environment'
Properties:
AirflowVersion: !Ref Version
SourceBucketArn: !Sub 'arn:aws:s3:::${BucketName}'
DagS3Path: !Sub 's3://${BucketName}${DagS3Path}'
PluginsS3Path: !Sub 's3://${BucketName}${PluginS3Path}'
RequirementsS3Path: !Sub 's3://${BucketName}${RequirementsS3Path}'
EnvironmentClass: !Ref EnvClass
ExecutionRoleArn: !GetAtt MWAARole.Arn
LoggingConfiguration:
TaskLogs:
Enabled: true
LogLevel: INFO
SchedulerLogs:
Enabled: false
LogLevel: WARNING
WebserverLogs:
Enabled: false
LogLevel: WARNING
WorkerLogs:
Enabled: false
LogLevel: WARNING
DagProcessingLogs:
Enabled: false
LogLevel: WARNING
MaxWorkers: !Ref MaxWorkerServer
Name: !Ref MWAAName
NetworkConfiguration:
SecurityGroupIds:
- !Ref MWAASGId
SubnetIds:
- !Ref PrivateSubnetId1
- !Ref PrivateSubnetId2
WebserverAccessMode: !Ref Accessmode
WeeklyMaintenanceWindowStart: !Ref MaintenanceWindow
# IAM Role
MWAARole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub '${MWAAName}-MWAA-role'
Path: /service-role/
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- airflow-env.amazonaws.com
- airflow.amazonaws.com
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: !Sub 'MWAA-${MWAAName}-Execution-Policy'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: 'airflow:PublishMetrics'
Resource:
- !Sub "arn:aws:airflow:${AWS::Region}:${AWS::AccountId}:environment/${MWAAName}"
- Effect: Deny
Action: 's3:ListAllMyBuckets'
Resource:
- !Sub 'arn:aws:s3:::${BucketName}'
- !Sub 'arn:aws:s3:::${BucketName}/*'
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:GetBucket*'
- 's3:List*'
Resource:
- !Sub 'arn:aws:s3:::${BucketName}'
- !Sub 'arn:aws:s3:::${BucketName}/*'
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:CreateLogGroup'
- 'logs:PutLogEvents'
- 'logs:GetLogEvents'
- 'logs:PutLogEvents'
- 'logs:GetLogRecord'
- 'logs:GetLogGroupFields'
- 'logs:GetQueryResults'
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:airflow-${MWAAName}-*'
- Effect: Allow
Action: 'logs:DescribeLogGroups'
Resource: '*'
- Effect: Allow
Action: 'cloudwatch:PutMetricData'
Resource: '*'
- Effect: Allow
Action:
- 'sqs:ChangeMessageVisibility'
- 'sqs:DeleteMessage'
- 'sqs:GetQueueAttributes'
- 'sqs:GetQueueUrl'
- 'sqs:ReceiveMessage'
- 'sqs:SendMessage'
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:*:airflow-celery-*'
- Effect: Allow
Action:
- 'kms:Decrypt'
- 'kms:DescribeKey'
- 'kms:GenerateDataKey*'
- 'kms:Encrypt'
NotResource:
- !Sub 'arn:aws:kms:*:${AWS::AccountId}:key/*'
Condition:
StringLike:
'kms:ViaService':
- sqs.ap-northeast-1.amazonaws.com
# NAT Gateway, EIP
DefaultPrivateRoute1:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref PrivateRouteTableId1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway1
PrivateSubnet1RouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PrivateRouteTableId1
SubnetId: !Ref PrivateSubnetId1
DefaultPrivateRoute2:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref PrivateRouteTableId2
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway2
PrivateSubnet2RouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PrivateRouteTableId2
SubnetId: !Ref PrivateSubnetId2
NatGateway1EIP:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
NatGateway2EIP:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
NatGateway1:
Type: 'AWS::EC2::NatGateway'
Properties:
AllocationId: !GetAtt NatGateway1EIP.AllocationId
SubnetId: !Ref PublicSubnetId1
NatGateway2:
Type: 'AWS::EC2::NatGateway'
Properties:
AllocationId: !GetAtt NatGateway2EIP.AllocationId
SubnetId: !Ref PublicSubnetId2
これで作成したまま放置すると課金が発生するリソースを一括で作成・削除ができますね。入力したパラメータはクイックリンクを生成しておけば楽だし、CDKで管理するようにしてもOKですね。
まとめ
今回は既存VPCにMWAA環境を構築するテンプレートと、MWAAの特徴、課題点、VPC要件についてのご紹介でした。
Airflow2.0の対応やメタデータのエクスポート機能辺りは今後のアップデートに期待したいところです。スモール構成でいくつか簡単なジョブを動かしてみましたが、パフォーマンスはちょっとモッサリな印象でした。(あくまで主観です)
ですが、GCPのCloud Composerと違い、ワーカーがAutoscalingするという利点も加えて、Airflowの環境維持に関する負担は非常に軽減されると思います。