1. AWS リソースの作成

Fargate を CI/CD パイプラインを使ってデプロイするためのリソースを作成していきます。

1.1. 本ハンズオン環境(Jupyter notebook コンテナ)の確認

まずは AWS CLI が正しく利用できることを確認しましょう。


In [ ]:
aws --version

応答例)

aws-cli/1.15.61 Python/3.6.3 Linux/4.9.87-linuxkit-aufs botocore/1.10.60

意図した IAM ユーザー で環境が動作していることを確認します。


In [ ]:
aws sts get-caller-identity | jq .

応答例)

{
  "UserId": "AKIAIOSFODNN7EXAMPLE",
  "Account": "111111111111",
  "Arn": "arn:aws:iam::111111111111:user/admin"
}

git を扱うためのユーザー情報が環境変数に設定されていることを確認します。


In [ ]:
echo "User:  ${GIT_USER_NAME}"
echo "Email: ${GIT_EMAIL_ADDRESS}"

応答例)

User:  foo
Email: foo@bar.com

Docker も正常に動作することを確認します。


In [ ]:
docker version

応答例)

Client:
 Version:      18.03.1-ce
 API version:  1.37
 ..

Server:
 Engine:
  Version:      18.03.1-ce
  API version:  1.37 (minimum version 1.12)
  ..

この Jupyter notebook コンテナ起動時に個別に割り当てられた、プロジェクト ID を確認します。


In [ ]:
echo "${PROJECT_ID}"

応答例)

56333cb5-a2d0-442d-92fb-4e26f9b5a3dc

1.2. AWS リソースの作成

AWS 上に git リポジトリや CI/CD パイプライン、Fargate の基盤となる VPC などを作成します。

今回はパイプラインのデプロイ先として、Edge と呼ぶ 開発用環境 を想定した Fargate を作ります。
git リモートリポジトリの master ブランチにソースコードが push される度に 更新されるものです。

1.2.1. S3 バケットの作成

AWS リソース作成に必要な設定値をローカルファイルに保存し、


In [ ]:
cat << EOT >> ~/config/.env 
export S3_BUCKET_NAME=fargate-handson-${PROJECT_ID}
export BASE_STACK_NAME="fargate-handson-base"
export EDGE_STACK_NAME="fargate-handson-edge-env"
EOT

CI 成果物などを保持するための S3 バケットを作成します。


In [ ]:
source ~/config/.env

aws s3 mb "s3://${S3_BUCKET_NAME}"

成功時応答例)

make_bucket: fargate-handson-56333cb5-a2d0-442d-92fb-4e26f9b5a3dc

1.2.2. サービス基盤となる VPC や CI/CD パイプラインの作成

CloudFormation を使って AWS リソースを作成します。
適用されるテンプレートは こちら です。まずは内容を検証しましょう。


In [ ]:
aws cloudformation validate-template --template-body file://infrastructure/sam.yaml

成功時応答例)

{
    "Description": "A fargate application with a CI/CD pipeline",
    "Parameters": [
        {
            "ParameterKey": "ProjectID",
            "NoEcho": false
        },
    ..

テンプレートに不正がないことを確認できましたか?

テンプレートには 通知のための Lambda 関数 も含まれているため、SAM としてパッケージングします。


In [ ]:
aws cloudformation package \
    --template-file infrastructure/sam.yaml \
    --output-template-file infrastructure/cfn.yaml \
    --s3-bucket "${S3_BUCKET_NAME}" \
    --s3-prefix "cloudformation"

成功時応答)

Uploading to cloudformation/0e64849e597b443d9a1349275098ab43  766 / 766.0  (100.00%)
Successfully packaged artifacts and wrote output template to file infrastructure/cfn.yaml
..

パッケージングもできたらリソースの作成を開始しましょう、3 分ほどで以下のリソースが作られます。

- VPC
- SecurityGroup
- CodePipeline
- CodeBuild プロジェクト
- SNS Topic
- Lambda 関数
- CodeCommit リポジトリー
- ECR リポジトリー
- IAM ロール * 3


In [ ]:
aws cloudformation deploy \
    --stack-name "${BASE_STACK_NAME}" \
    --template-file infrastructure/cfn.yaml \
    --parameter-overrides \
        ProjectID="${PROJECT_ID}" \
        S3BucketName="${S3_BUCKET_NAME}" \
        EdgeStackName="${EDGE_STACK_NAME}" \
        ApprovalEmail="${GIT_EMAIL_ADDRESS}" \
    --capabilities CAPABILITY_IAM

成功時応答)

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - fargate-handson-base

1.2.3. SES からのメール送信を許可

このタイミングで、git ユーザーのメールアドレス宛に Amazon SES から確認メールが来ます
矢印部分のリンクをクリックし、メールを受け付ける許可をしてください。

1.2.4. サービスである Fargate を起動する

Fargate へ、初期サンプルとして dockercloud/hello-world をデプロイしてみます。
適用されるテンプレートは こちら、2 分ほどで以下のリソースが作られます。

- CloudWatch Logs ロググループ
- ECS クラスター
- ECS タスク定義
- ECS サービス
- IAM ロール * 2


In [ ]:
DOCKER_IMAGE=dockercloud/hello-world

aws cloudformation deploy \
    --stack-name "${EDGE_STACK_NAME}" \
    --template-file application/deploy/cfn-master.yaml \
    --parameter-overrides \
        ProjectID="${PROJECT_ID}" \
        DockerImage="${DOCKER_IMAGE}" \
    --capabilities CAPABILITY_IAM

成功時応答)

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - fargate-handson-edge-env

以下のコマンドで Fargate に割り当てられたパブリック IP アドレスを取得し、
起動した Fargate にブラウザから接続してみましょう!


In [ ]:
cluster_name=$( aws cloudformation describe-stacks \
    --stack-name "${EDGE_STACK_NAME}" --output text \
    --query 'Stacks[*].Outputs[?OutputKey==`Cluster`].OutputValue' )
task_id=$( aws ecs list-tasks --cluster "${cluster_name}" \
    --family "${EDGE_STACK_NAME}" | jq -r '.taskArns[0]' )
eni_id=$( aws ecs describe-tasks --cluster "${cluster_name}" --task "${task_id}" \
    | jq '.tasks[0].attachments[0].details[]' \
    | jq -r 'select( .name | contains("networkInterfaceId")).value' )
public_ip=$( aws ec2 describe-network-interfaces \
    --network-interface-ids ${eni_id} \
    | jq -r '.NetworkInterfaces[].Association.PublicIp' )

echo "http://${public_ip}"

成功時応答例)

http://xxx.yy.zzz.xx

以下のような画面が確認できれば、Fargate が正常に動作しています!