koboriakira.com

はじめに

Amazonが提供する現代的なウェブアプリケーションの構築を読み進めることにした。

なお実践はCloud9ではなくローカル端末で試すことにした。

また請求が発生する可能性があるため、早めに済ませること。EC2でめちゃくちゃお金がかかった。

モジュール1「静的ウェブサイトの構築」

(前提)AWS CLIの設定

AWS CLIを使う必要があるのでaws configureでAWSの設定ファイル(.aws)を作成した。アクセスキーが古くなってきたので新しくした。

(前提)S3とは

S3 は、保存されたオブジェクトをHTTP経由で直接提供できる、耐久性と可用性に優れた、低コストのオブジェクトストレージサービスです。

「ファイルをHTTPで転送できる」というのがポイント。つまりWebサイトにもなりうる。

S3バケットの作成

aws s3 mbコマンドでS3バケットを作成した。バケット名はaws-modern-application-workshop-koboriにしたので、具体的には次のコマンドを打つ。

bash aws s3 mb s3://aws-modern-application-workshop-kobori ### S3バケットの設定静的ウェブサイトのホスティングができるように、「ウェブサイトとして利用」と「外部からのアクセスを許可」の設定をする。

ホスティング

aws s3 websiteコマンドで静的Webサイトのホスティング設定をする。--index-documentオプションはindex.htmlを指定。

外部からのアクセスを許可

バケットを作成した時点ではプライベート(外部からはアクセスできない)ため、S3バケットポリシーを変更する必要がある。

バケットポリシーは一般的にはJSONファイルを定義して、これをaws s3api put-bucket-policyコマンドで送るのがいいみたい。そのためJSONファイルを次のように送ったbash aws s3api put-bucket-policy --bucket aws-modern-application-workshop-kobori --policy file://JSONファイルJSONファイルの中身は下記の通り。

json {"Id": "MyPolicy","Version": "2012-10-17","Statement": [{"Sid": "PublicReadForGetBucketObjects","Effect": "Allow","Principal": "*","Action": "s3:GetObject","Resource": "arn:aws:s3:::aws-modern-application-workshop-kobori/*"}]}### index.htmlをデプロイ最後に実際に利用されるindex.htmlをS3バケットに配置する。これはaws s3 cpコマンドで設定。

cpコマンドと同じなので、具体的には次のようにした。

bash aws s3 cp ローカルのindex.html s3://aws-modern-application-workshop-kobori/index.html これでウェブサイトが構築できた。というかこんなに簡単なのか。心配なのは金額だけ。

調子がよかったので「モジュール 2: ウェブサーバーでのアプリケーションのホスト」もちょっと読んでみよう。実際のメモは明日以降に。

モジュール2「静的ウェブサイトの構築」

(前提)各サービス、用語の概要

  • AWS CloudFormation: Amazon Web Servicesリソースのモデル化およびセットアップのサービス。インフラストラクチャ管理を簡略化する。

  • NLB: Network Load Balancer * Amazon ECR: Elastic Container Registry、完全マネージド型のDockerコンテナレジストリです。このレジストリを使うと、開発者はDockerコンテナイメージを簡単に保存、管理、デプロイできます。

  • Amazon ECS: Elastic Container Service、フルマネージド型のコンテナオーケストレーションサービスです。

  • AWS CodeCommit: Gitベースのリポジトリをセキュアにホストする完全マネージド型のソース管理サービスです。

  • AWS CodeBuild: ソースコードをコンパイルし、テストを実行し、デプロイ可能なソフトウェアパッケージを作成できる完全マネージド型のビルドサービスです。

  • AWS CodePipeline: 完全マネージド型の継続的デリバリーサービスで、素早く確実性のあるアプリケーションとインフラストラクチャのアップデートのための、パイプラインのリリースを自動化します### モジュール2A: CloudFormationのテンプレートをデプロイするaws cloudformation create-stackコマンドで、ローカルにあるテンプレートのymlとIAMリソースをつかってスタックを作成する。

bash aws cloudformation create-stack --stack-name MythicalMysfitsCoreStack --capabilities CAPABILITY_NAMED_IAM --template-body file://module-2/cfn/core.yml スタックとは、

スタックは、単一のユニットとして管理できる AWS リソースのコレクションです。 つまり、スタックを作成、更新、削除することで、リソースのコレクションを作成、更新、削除できます。 … リソースが作成できない場合、AWS CloudFormation はスタックをロールバックし、作成されたリソースを自動的に削除します。

ちなみにスタックをつくるときにIAMロール(ポリシー)でつまづいた。EC2とIAMに関してフルアクセスの権限を付与して解決したが、ベストプラクティスがわからない。このあたりを勉強すべきか迷う。

モジュール2B: サービスをNLB経由でデプロイ・公開する

aws ecr create-repositoryコマンドでリポジトリを作成する。AmazonEC2ContainerRegistryFullAccessの権限を付与して実行した(FullAccessがベストではない気がするのだが、コマンドとポリシー、パーミッションの関係が見つけられない)。

このあとDockerログインをするのだが、aws ecr get-loginコマンドはセキュリティの関係から(コマンド履歴にパスワードが残る)使えなくなっていた。そのためこちらを参考にして、aws ecr get-login-passwordコマンドでdocker loginを進めた。IssueかPRを出せるといいな。

つぎにECRにプッシュしたイメージをECSにデプロイする。

aws ecs create-clusterでサーバのクラスター、aws logs create-log-groupでロググループをそれぞれ作成する。

与えられたテンプレートを使って、aws ecs register-task-definitionコマンドでECSタスク定義を登録する。

つぎにサービススタックに必要なインフラストラクチャをプロビジョニングする。

プロビジョニングとは、必要に応じてネットワークやコンピューターの設備などのリソースを提供できるよう予測し、準備しておくことです
https://www.idcf.jp/words/provisioning.html

ただ単純に公開するのではなくNLBをかませることで、実際のサービスのスケールイン/スケールアウトを容易にできる。

というわけでaws elbv2 create-load-balancerコマンドでロードバランサーを作成する。サブネットはCloudFormationで作成したスタックから利用。

次にaws elbv2 create-target-groupコマンドでNLBターゲットグループ、aws elbv2 create-listenerコマンドでNLBロードバランサーのリスナーをそれぞれ作成。これで80番ポートが受信したリクエストをターゲットグループに登録されているターゲットに転送することをロードバランサーに知らせる。あまり意味はわかっていないけど、とりあえず書いておこう。

よくわからないけど、はじめてECSを利用する場合はaws iam create-service-linked-role --aws-service-name ecs.amazonaws.comが必要なよう。

ECSで実際のサービスを作成するため、aws ecs create-serviceコマンドを実行するaws ecs create-service --cli-input-json file://service-definition.json これで実際のサービス(Flask)にNLBを介してアクセスできるようになった。NLBのDNSでcurlを飛ばしてみると、実際にレスポンスが帰ってくる。

ちなみに最初に時間がかかったのはコンテナを作成・起動しているからか。2度目は一瞬だったので。

このサービスを利用するようにフロントエンドのindex.htmlを修正して、モジュールBは終了。

モジュール2C: CD/CIの設定

上記のまま開発を続けると、デプロイする際にはイメージを更新、プッシュして、またタスク定義を更新しないといけなさそう(その方法はチュートリアルにない)。

そのためCD/CIを設定する。

まずCI/CDアーティファクト用のS3バケットをつくる。バケットポリシーはチュートリアル側で用意してくれたものを使う。GETとPUTを許可しているみたい。

つぎにaws codecommit create-repositoryでCodeCommitリポジトリ、aws codebuild create-projectでCodeBuildプロジェクトを作成。いろんな値をコピペするので忘れても調べられるようにしないといけないな。

最後に、CodeBuildプロジェクトを使用してCodeCommitリポジトリを継続的に統合することと、新しくビルドされたアーティファクトをECSのサービスに継続的に提供するサービスとして、AWS CodePipelineをつくる。

aws codepipeline create-pipelineコマンドで、CodePipelineのパイプラインを作成。

そしてCodeBuildがECRリポジトリにアクセスできるよう設定する。具体的にはaws ecr set-repository-policyコマンドでECRリポジトリのポリシーを設定する。

これで使えるようになったのでテストをする。gitの認証まわりに関する設定を行った後、codecommitの空リポジトリをクローンして、今回のアプリケーションのソースをcommitしてpush。

CodePipelineのコンソールで自動ビルドが行われていることを確認して完了。

モジュール3「情報の保存」

テーブル、データの追加

aws dynamodb create-tableコマンドでデータベースを作成。aws dynamodb scanコマンドでテーブルの中身が見れる(見れるということは作成に成功している証拠)。

aws dynamodb batch-write-itemコマンドでレコードを追加する。scanして追加されたことを確認。

ウェブサイトの更新

つぎにこのDBを使うようにアプリを直してcommit, pushしたのだが、403エラーで失敗してしまった。

どうやらHTTPSでやるとMacのキーチェーンの問題があるようなので、SSHを使って回避するようにした。具体的には、

  1. IAMユーザの「AWS CodeCommit の SSH キー」に公開鍵を設定する
  2. SSHキーIDが発行されるので、これを使った~/.ssh/configを設定(下記参照)
  3. ssh git-codecommit.ap-northeast-1.amazonaws.comで疎通確認

~/.ssh/config Host git-codecommit.*.amazonaws.com User <SSHキーID>IdentityFile ~/.ssh/id_rsa またフロントのindex.htmlも更新。

パイプラインが成功したらサイトを確認。API、DBを使ってリストを描画していることを確認して終了。

モジュール4「ユーザ登録の設定」

(前提)Amazon Cognitoとは

ウェブアプリケーションおよびモバイルアプリに素早く簡単にユーザーのサインアップ/サインインおよびアクセスコントロールの機能を追加する。

ユーザプールの作成

aws cognito-idp create-user-poolコマンドで、Cognitoユーザープールを作成する。オプションも入れると次の通り。

bash aws cognito-idp create-user-pool --pool-name MysfitsUserPool --auto-verified-attributes email またユーザプールとセットで、aws cognito-idp create-user-pool-clientコマンドで、ユーザープールクライアントも作成する。

bash aws cognito-idp create-user-pool-client --user-pool-id <ユーザプールのID> --client-name MysfitsUserPoolClient “Id”: “ap-northeast-1_RoHXOwkFB”,“Arn”: “arn:aws:cognito-idp:ap-northeast-1:365487138721:userpool/ap-northeast-1_RoHXOwkFB”{“UserPoolClient”: {“UserPoolId”: “ap-northeast-1_RoHXOwkFB”,“ClientName”: “MysfitsUserPoolClient”,“ClientId”: “71gov86tiiphs9amjmd6kjopje”,“LastModifiedDate”: “2020-09-20T09:36:05.872000+09:00”,“CreationDate”: “2020-09-20T09:36:05.872000+09:00”,“RefreshTokenValidity”: 30,“AllowedOAuthFlowsUserPoolClient”: false }}### REST APIとAmazon API Gatewayの設定NLBの前にAmazon API Gatewayをはさんで、GatewayがCognitoを利用するようにする。またGatewayがNLBとプライベートで疎通するように、API Gateway VPCリンクも必要となる。

まずaws apigateway create-vpc-linkコマンドでNLBへのVPCリンクを作成。


Kobori Akira

IT業界の社会人。音楽、パッカーズ、スワローズ、ポーカー。
読む価値のある記事は Qiitanote に投稿します。
過去人気だったブログ記事はこちらから。