FlaskアプリをAWS ACMでSSL化しながらFargateで公開する全ステップ (後編)
FlaskアプリをAWS ACMでSSL化しながらFargateで公開する全ステップの後編です。Flaskアプリ公開まで一気に行きましょう。
アーキテクチャ(再掲)
実装手順(グレーアウト部分は前編で実施済み)
Step | 項目 | 対象サービス | ||
---|---|---|---|---|
1 | ドメイン発行 | Route 53 | ||
2 | 証明書発行 | ACM、Route53 | ||
3 | VPC作成 | VPC | ||
4 | セキュリティグループ作成 | セキュリティグループ | ||
5 | VPCエンドポイント作成 | VPCエンドポイント | ||
6 | ALB作成 | ALB | ||
7 | コンテナイメージ作成 | ローカルマシンなど | ||
8 | レポジトリ作成とイメージアップロード | ECR | ||
9 | コンテナ作成 | ECS/Fargate | ||
10 | ALBのリスナー修正 | ALB | ||
11 | CNAMEレコード登録 | Route 53 | ||
12 | テスト | テスト |
7. コンテナイメージ作成
Flaskのコンテナイメージを作成します。サンプルとしてHello Worldを表示するFlaskのイメージをローカルマシンで作成します。
ディレクトリ構造
flask-testというフォルダを作成し、その中に次のような階層でコードを配置します。
dockerfile
FROM python:3.8.11-slim-buster RUN pip install --upgrade pip RUN pip install flask==2.0.1 RUN pip install pillow==8.00 ENV PORT 80 WORKDIR /app COPY ./app/ /app CMD ["python", "app.py"]
app.py
import os from flask import Flask port = int(os.environ['PORT']) app = Flask(__name__) @app.route('/') def index(): return 'Hello World!!!' if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=port)
dockerをまだ導入していない方は、Docker Desktopを先に導入してください。私の実行環境はMacですが、ターミナルを開いてflask-hwの階層に移動し、以下コマンドを投入してください。
% docker image build -t flask-hw .
% docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-hw latest 2d783442b531 10 seconds ago 146MB
続いて以下コマンドを実行しコンテナを起動させます。
% docker container run --rm -d -p 5000:80 -v ${PWD}/app:/app --name flask-hw flask-hw
ブラウザでlocalhost:5000
と入力すると以下の様にHello Worldが表示されるはずです。今しがた作ったイメージからコンテナを作成し、ポート5000→80と変換しアクセスしています。
無事ローカルでテストできたら、稼働しているコンテナを停止しておきます。
% docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 06f87ee03035 flask-hw "python app.py" 7 minutes ago Up 7 minutes 0.0.0.0:5000->80/tcp, :::5000->80/tcp flask-hw % docker stop 06f87ee03035 06f87ee03035
8. レポジトリ作成とイメージアップロード
ECRのプライベートレポジトリを作成し、7で作成したイメージをアップします。ローカルマシンでAWS CLIを叩く必要があるので、導入されていない方はインストールしてください。
Amazon ECR < リポジトリ < リポジトリを作成から、リポジトリを作成していきます。リポジトリ名は先程作成したイメージに合わせると後の手順が簡単です。イメージスキャンや暗号化は推奨項目ではありますが、今回は主題と逸れるので省略します。
リポジトリが作成できたら「プッシュコマンドの表示」をクリックし、プッシュコマンドを表示します。表示されたコマンドをローカルマシンのターミナルで実行するだけですが、ECRにイメージをプッシュするための権限が必要です。簡単な例として、必要な権限を付与したIAMユーザを作成し、アクセスキーを発行してaws configure
コマンドで設定しておきましょう。
コマンド実行結果はこんな感じです。
% aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded % docker build -t flask-hw . [+] Building 2.2s (12/12) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 177B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/python:3.8.11-slim-buster 2.1s => [auth] library/python:pull token for registry-1.docker.io 0.0s => [1/6] FROM docker.io/library/python:3.8.11-slim-buster@sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0.0s => [internal] load build context 0.0s => => transferring context: 193B 0.0s => CACHED [2/6] RUN pip install --upgrade pip 0.0s => CACHED [3/6] RUN pip install flask==2.0.1 0.0s => CACHED [4/6] RUN pip install pillow==8.00 0.0s => CACHED [5/6] WORKDIR /app 0.0s => CACHED [6/6] COPY ./app/ /app 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0.0s => => naming to docker.io/library/flask-hw 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them % docker tag flask-hw:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/flask-hw:latest % docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/flask-hw:latest The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/flask-hw] xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed xxxxxxxxxxxx: Pushed latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 2417 %
ECR側でもイメージがプッシュされました。
9. コンテナ作成
いよいよアプリが稼働するコンテナを作っていきます。AWSでのコンテナ実行環境としてECSを利用し、ホストマシンの管理が不要なFargateを使っていきます。 ECS<クラスター<クラスターの作成から、クラスターを作成します。Fargateを使いたいので、ネットワーキングのみを選択します。 前編作成したVPCを利用するため、VPCの作成はチェックしません。
続いてタスク定義<新しいタスクの定義を行います。Fargateを選択します。
パラメータを設定していきます。特にコンテナがAWS操作をするわけではないので、タスクロールは不要です。
CPUやメモリをお好みの値を入れて、「コンテナの追加」をクリックします。
ECRへ先程アップしたイメージのURIをコピーして入力します。またALBでSSL終端された後、ALBからコンテナへのアクセスはHTTPとなるためポートマッピングに80(HTTP)を入力しておきます。残りはデフォルトのままとし、コンテナの追加<タスク定義の作成と進みタスク定義作成を完了させます。
作成したタスクをもとにコンテナを作成するためにサービスを作成します。起動タイプはFargateとし、任意のサービス名とタスクの数(コンテナの数)を入力し次に行きます。
続いてネットワーク関連の設定です。前編で作成したVPC、サブネット(コンテナ用なのでプライベートサブネットx2)、SG(ECS用)を選択します。
続いてロードバランサーの設定です。ここが一番わかりにくい。。。ALBを選択するとタスク定義で設定したポート(今回は80番)の設定ができるので、「ロードバランサーの追加」をクリックします。
画像のように設定します。リスナーポートとはインターネットからALBへのアクセスを受け付けるポートのことなので本当はHTTPSなのですが、なぜかACMの証明書が選択できません。一旦HTTPでリスナーポートの設定をし、後ほど設定変更します。
Auto-scalingはスキップし、サービスの作成を完了します。サービス作成が完了すると、サービスで設定した数のタスク(コンテナ)が自動で作成されます。
上手くNW周りの設定が出来ていればタスクがRUNNINGとなります。ここがPENDINGのままになっていたり、何度もタスクの作成削除が繰り返されて不安定になる場合NW周りの設定に問題がある可能性があります。挙動として、VPC内のクラスターがECRやS3にエンドポイント経由でアクセスしイメージを取得してくるので、エンドポイントやSGなどで通信がブロックされているなどが考えられます。
10. ALBのリスナー修正
リスナーポートを443に修正するため、前編で作成したALBを選択し、ECSが作成したリスナーの設定を変更します。
プロトコルがHTTPになっていると思いますのでHTTPSに修正します。
下段のACMの部分で前編で作成したACMの証明書を選択し、変更内容を保存します。
またHTTPでリクエストが有った場合にHTTPSへリダイレクトする処理を追加します。リスナー追加をクリックし次のように設定します。これによりHTTPSでの接続を強制できます。
設定が完了したら、ALBの説明タブの中からDNS名をコピーしておきます。
11. CNAMEレコード登録
さて、いよいよ最後のステップです。Route 53に遷移し、ACMを発行したFlask アプリのドメインをCNAMEレコードでALBのDNS名に紐付けます。
12. テスト
ここまで来たらテストしてみましょう。ステップ11でRoute 53に登録したドメインに対してブラウザで接続してみましょう(https://www.xyz.comなど)。Hello Worldの画面が表示されれば無事設定完了です。