目次
はじめに
こんにちは、半田(@handy)です。
Azureを利用している環境でソースコード管理をするとなった際に、使用されるサービス候補の一つとしてAzure Reposがあります。
Azure ReposはAzure Pipelineと統合されているので、比較的シンプルに他のAzureサービスにアプリケーションをデプロイをすることができます。
そのため、App Serviceへのデプロイであればそこまで手間なくできるかもしれませんが、少し条件を変えて、Azure ReposからApp Serviceと同等のサービスと言われているAWSのBeanstalkに対してデプロイする構成を試してみました。
AWS Beanstalkがどのようなサービスかというと、AWSドキュメントには以下のような説明がされています。
Elastic Beanstalk を使用すると、アプリケーションを実行しているインフラストラクチャについて知識を得なくても、AWS クラウドでアプリケーションのデプロイと管理を簡単に行うことができます。Elastic Beanstalk は、選択肢を狭めたり制御を制限したりすることなく、管理の複雑さを軽減します。アプリケーションをアップロードするだけで、Elastic Beanstalk は容量のプロビジョニング、ロードバランシング、スケーリング、およびアプリケーション状態モニタリングといった詳細を自動的に処理します。
通常、EC2で何かしらのアプリケーションを実行する場合、アプリケーション以外にもEC2自体の管理が必要になってきます。AWS Beanstalkのサービスを利用すると、EC2の管理作業をユーザー側で実施する必要はなく、AWS側でパッチ当てやマイナーバージョンアップ等を行ってくれるため、ユーザーはアプリケーションの管理に集中することができます。
いわゆるPaaSと呼ばれるサービスに位置づけされています。
※厳密にはランタイムのメジャーバージョンアップ等の作業はユーザー側で必要だったりするので、完全に管理が不要になるかというとそこまでではありません。
構築構成
実際に構築した構成は以下になります。
AWS Beanstalk側はシンプルにALB+EC2での高可用構成とし、アウトバウンド用にNAT GatewayをPublic Subnetに配置しています。
Azure側からはS3とBeanstalkの権限を付与したIAMユーザーのアクセスキーとシークレットアクセスキーを使用してデプロイが行われるようにしています。
Azure PipelineでS3へのソースコードのアップロードを行い、Beanstalkのアプリケーションバージョンの更新とデプロイを実施させる構成になります。
構築方法
今回は久々のBeanstalkを使うのと、あまり経験がないAzure Pipelineサービスを使うため、敢えて手動で構築しました。
Tearraformなどでコードで構築するのも良いのですが、使用経験が少ないサービスの場合はどのような設定項目があるかをGUI上で確認できたほうがイメージがしやすいので、私はまずコンソールから構築するようにしています。
前提
前提として、以下の作業は既に実施済みになります。
AWS関連
- ネットワーク回り(VPC/Subnet/IGW/NAT Gateway)の構築
- HTTPS通信のための証明書作成(ACM)とドメイン登録(Route 53)
- AWS Beanstalkで使用するS3バケットの作成
- Azure Pipelineで利用するIAMユーザーの作成
Azure関連
- Azure DevOps OrganizationとProjectの作成
- Azure Reposにリポジトリの作成
事前準備
構築に入る前に、以下の作業を事前に行います。
AWS関連
- AWSドキュメントに記載されているPythonのサンプルアプリケーション(FlaskやGjangoを使用していないほう)をダウンロードします。
- Azure Pipelineは構築済みのAWS Beanstalkの環境に対してデプロイを行うため、事前に手動で構築しておく必要があります。そのために先ほどダウンロードしたZipファイルをBeanstalkから参照させるS3に配置しておきます。(ファイル名はBeanstalkで使用する名前に修正してます)
Azure関連
- ダウンロードしたPython.zipファイルをPC上で解凍して、そのファイルをAzure Reposリポジトリにアップロード、または手動作成します。
※以下図の「azure-pipeline.yml」ファイルはAzure Pipelineを作成したときに自動で作成されるため、この時点では作成する必要はありません。
- Azure PipelineからBeanstalk のデプロイで使用するIAMユーザーのアクセスキーとシークレットアクセスキーを登録しておきます。Azure PipelineのProject Settingsから設定できます。
- Azure PipelineからBeanstalk に直接デプロイするために、Azure DevOpsに「AWS Toolkit for Azure DevOps」というExtentionsをインストールしておきます。
実作業
Beanstalk作成
最初にコンソールからBeanstalkを作成しておきます。
「sample-web-app」というアプリケーションと「Sample-web-app-env-1」という環境を構築しました。
Beanstalkは設定項目が多いので、いくつか抜粋してご説明します。
最初に環境枠はウェブサーバー環境を選択します。
プラットフォームは「Python 3.9 running on 64bit Amazon Linux 2023」を選択します。
ここで注意が必要なのは、最初にダウンロードしたPython.zipファイル内のPythonバージョンが3.6で定義されているので、一部ファイルを書き換える必要があります。
※「EBSampleApp-Python.iml」ファイルのjdkNameの部分を3.6→3.9へ修正しておきます。
アプリケーションコードでは、S3にアップロードしたファイルのオブジェクトURLを設定します。バージョンラベルには適当にv1を設定しておきます。
プリセットでは、ALB+EC2を構築するために高可用性を選択します。
インスタンスの設定ではPrivateSubnetを選択します。AZ分散するように2つ設定します。
EC2セキュリティグループでは、ALBにアタッチするSGからのHTTPインバウンド通信を許可するように設定してあるものを指定します。
ALBからEC2にアクセスできないとヘルスチェックに失敗します。
ALBの構築先サブネットはIGWが設定されたPublic Subnetを指定します。
ALBにはHTTPSのリスナーを追加しておきます。この時事前に準備したACM上の証明書を指定します。HTTPS化していなければここは特に作業不要です。
残りの項目はデフォルトかお好みで修正して最後まで入力出来たら送信ボタンを押下してBeanstalkを構築します。
Route 53設定
Beanstalkが正常にデプロイされるとALBが作成されているので、Route 53のホストゾーンにALBを対象としたAレコードを追加します。
そこまでできたらブラウザからホストゾーンに登録しているドメインにアクセスして、サンプルアプリが表示されることが確認できます。
Azure Pipeline構築
Beanstalkの構築ができたら次はAzure Pipelineの構築を行います。
Azure Pipelineの画面「New pipeline」から新しくパイプラインを作成します。
ソースコードには「Azure Repos Git」を指定します。
事前に作成したリポジトリ名を選択します。
次に実行するパイプラインのテンプレートを選択します。
ただ、AWS Beanstalkにデプロイするテンプレートは容易されていないため、ここでは適当に「Python package」などを選択して、後でコードを直接修正します。
「Python package」テンプレートが設定されたazure-pipeline.ymlファイルが作成されます。この時点ではまだパイプラインを実行しないので、「Save and run」ではなく「Save」を行います。
作成したパイプラインを選択し、「Edit」ボタンを押下します。
以下のようにパイプラインの編集画面が表示されます。
azure-pipeline.ymlファイルの中身を以下の内容で上書きします。
「$()」で囲われた文字列はAzure Pipelineの環境変数で定義します。
# Python to Linux Web App on Azure
# Build your Python project and deploy it to Azure as a Linux Web App.
# Change python version to one thats appropriate for your application.
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
trigger:
- main
variables:
eb-app-ver: ''
pool:
vmImage: ubuntu-latest
steps:
- task: Bash@3
inputs:
targetType: 'inline'
script: |
DATETIME=`date +%Y%m%d%H%M%S%3N`
echo "##vso[task.setvariable variable=eb-app-ver;]${DATETIME}"
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.Repository.LocalPath)'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(ArchiveFileName)'
- task: S3Upload@1
inputs:
awsCredentials: '$(AwsCredentials)'
regionName: '$(RegionName)'
bucketName: '$(SourceBucket)'
sourceFolder: '$(Build.ArtifactStagingDirectory)'
globExpressions: '$(ArchiveFileName)'
targetFolder: '$(TargetFolder)'
- task: BeanstalkDeployApplication@1
inputs:
awsCredentials: 'ecr-push-iam-user'
regionName: '$(RegionName)'
applicationName: '$(ApplicationName)'
environmentName: '$(EnvironmentName)'
applicationType: 's3'
versionLabel: 'v$(eb-app-ver)'
deploymentBundleBucket: '$(SourceBucket)'
deploymentBundleKey: '$(TargetFolder)/$(ArchiveFileName)'
修正出来たら右上のVariablesを押下して、
以下の環境変数を設定します。
設定内容
- ApplicatiionName:Beanstalkのアプリケーション名
- ArchiveFileName:Beanstalkで読み込むZipファイル名(拡張子付き)
- AwsCredentials:最初の方の手順で設定したデプロイ用の認証情報の名前
- EnvironmentName:Beanstalkのアプリケーション環境名
- RegionName:Beanstalkがデプロイされているリージョン名
- SourceBucket:出力先のS3バケット名
- TargetFolder:出力先のS3プレフィックス名
最後に「Save」ボタンを押下すると、Azure ReposリポジトリのmainブランチにCommitされて、実際にパイプラインが実行されます。
※私はmainブランチを修正する度にパイプラインが動くのが煩わしかったので、敢えて"release/dev"ブランチにしているので、説明とキャプチャが少し異なっています。
作成したパイプラインが実行され、S3へのアップロードとBeanstalkのデプロイが行われます。
Beanstalkのコンソールから、アプリケーションバージョンを見ると、実行時刻のラベルが作成されてデプロイが成功していることがわかります。
デプロイ検証
デプロイパイプラインの構築が完了したので、Azure Reposからアプリケーションを更新してみます。
表示されるページの"Congratulations"の文字を"Congratulations Test"に変えてみます。
application.pyから該当の箇所を確認して修正し、Commitします。
デプロイが成功したことを確認します。
ブラウザを再読み込みしてみると、修正した内容が反映されていることが確認できました。
まとめ
無事Azure ReposからAWS Beanstalkにデプロイするところまで構築することができました。
クラウドを横断してデプロイするのはあまり経験がなかったので、良い知見になりました。
個人的には、AzureよりもBeanstalkのほうが設定項目が多く、想定外の設定項目でエラーが出たりしてたので、Beanstalkのほうが知識を深められた気がしました。
この記事がどなたかの参考になれば幸いです。