LogChance
今回は LogChance というアプリケーションを Fargate を使ってデプロイしようかと思います。
普通のブラウザアプリなんですが、自分のアプリをデプロイすることに意味があると思ってるんですよね、モチベーション的に。
実際にデプロイに移る前に LogChance って何?って話を軽くしておきます。
私はもともと大学で物理学科に所属していたのですが、物理学科では成績評価におけるテストの比重が非常に高かったんです。
で、テスト前日とかはサイゼ○アに皆集まってテスト勉強をしていたわけです。(サイ◯オール部という団体を築き上げました)
でも、テスト勉強とはいえ、人が集まれば会話は生まれるんですよね。そして会話をしていればいずれ誰かがスベることになる、と。
ある日、誰かがスベった時の対処をどうしようか、という議題が上がったんです。
飲みの場であればお酒を飲めば良いだけなのですが、テスト勉強中なのでそれは難しい…。
「そうだ、ストック制にしよう!」
皆の背中に稲妻が走った瞬間でした。
そうか、誰かがスベったらその行いをストックとして記録しておき、テスト期間終了後の打ち上げでストックを消費すれば良いんだ。
その制度が生まれてからは皆どんどんストックを貯めてゆきました。
「はい今のストック〜w」
「うーん、今のはひどすぎるし、流石に 3 ストックものでしょ」
みたいな会話が繰り広げられ、深夜テンションも相まってテスト勉強会はより盛り上がりを見せてきました。
ところがある問題が生まれたんです。
そう、一回で付与されるストックの数がインフレを始めたんです。
「1億ストック」などという無謀な数がストックとして付与されるようになってきました。
でもお酒を1億杯飲むのは現実的じゃないですよね。
そこで LogChance という制度が生まれました。
LogChance は 1/2 の確率で今の自分のストック数に対して底が 10 の対数を取れる、という素晴らしい制度です。(少数繰り上げです)
例えば 100000000 ストックある状態で LogChance に成功すると自分のストックは 8 になります。
皆の目に希望の光が戻りました。
「これに成功すれば打ち上げで1億杯飲まなくて済む…!」
しかしもちろん無条件に対数が取れるわけではありません。1/2 の確率で失敗すると、ストックは据え置きとなり、且つその場でグラスワインを1杯飲まなければいけないというルールがあります。
自分の単位がかかっているテスト勉強中にグラスワインを飲むのはかなりリスクが高い行為です。それでも1億杯という途方も無いストックを抱えるよりは..と考え皆この LogChance に全てをかけました。
上記の制度をシステム化したものが LogChance アプリです。
構成としては、フロントが js、バックエンドが php -> DynamoDB みたいな簡単且つ典型的な Web アプリです。
ちなみに「そもそも勉強中にお酒が飲めないからストック制度が生まれたのでは…?」とかいうツッコミは一切受け付けません。
また、その後皆の単位がどうなったのかについては、触れないでおきます。
ECR にイメージを Push
まずは、ECR にイメージを Push します。
Dockerfile はこんな感じ。
$ cat Dockerfile
FROM centos:7
MAINTAINER "yuki"
# install apache2.4
RUN yum -y install httpd
# install php5.6
RUN yum -y install epel-release
RUN rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum remove php-*
RUN yum -y install --enablerepo=remi,remi-php56 php php-devel php-mbstring php-mysql php-pdo php-gd
RUN yum -y install git
WORKDIR /root/
RUN git clone [GitHub Repository]
RUN cp -r /root/LogChance/* /var/www/html/
ADD 10-php.conf /opt/docker/etc/httpd/conf.d/
# enable service.
RUN systemctl enable httpd
で、docker build して、既に作成してあった ECR レポジトリにイメージを Push します。
$ docker build -t logchance LogChance
$ $(aws ecr get-login --no-include-email --region us-west-2)
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker tag logchance:latest xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/logchance:latest
$ docker push xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/logchance:latest
The push refers to repository [xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/logchance]
7a7fbb2202e5: Pushed
ca318149f993: Pushed
ec3688a20c1e: Pushed
888f1887b6da: Pushed
218bb42aae1d: Pushed
e36614699bec: Pushed
e9e7a8f0e618: Pushed
b0c1680ff46e: Pushed
47ae0adf67db: Pushed
40b463ba2ba2: Pushed
d69483a6face: Pushed
latest: digest: sha256:f91c26a73d4d15fc1788a4b00464231da97cab0a3694cd2b7edbf38aeef846f4 size: 2635
完了!
タスク実行ロールの作成
Fargate を用いる場合、ECR からイメージを Pull してきたり、awslogs ログドライバーを使用したりするには、タスク実行ロールが必要となるので、それを作っておく。
まずは、以下のファイルを作成。
$ cat task-execution-assume-role.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
で、ロールを作ってポリシーをアタッチ。
$ aws iam --region us-east-1 create-role --role-name ecsTaskExecutionRole --assume-role-policy-document file://task-execution-assume-role.json
$ aws iam --region us-east-1 attach-role-policy --role-name ecsTaskExecutionRole --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
クラスター及び設定ファイルの作成
いよいよクラスターを作成。
まずは、ECS CLI を設定して、クラスターを作成し、ついでセキュリティグループも作っておく。
$ ecs-cli configure --cluster LogChance --region us-west-2 --default-launch-type FARGATE --config-name LogChance
INFO[0000] Saved ECS CLI cluster configuration LogChance.
$ ecs-cli configure profile --access-key XXXXXXXXXXXXXXXXXXXXXX --secret-key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx --profile-name LogChance
INFO[0000] Saved ECS CLI profile configuration LogChance.
$ ecs-cli up --cluster LogChance --vpc vpc-xxxxxxxxxxxxxxxxxxx --subnets subnet-xxxxxxxxxxxxxxxx,subnet-xxxxxxxxxxxxxxxx --security-group sg-xxxxxxxxxxxxxxxx --launch-type FARGATE --region us-west-2 --ecs-profile LogChance
INFO[0000] Created cluster cluster=LogChance region=us-west-2
INFO[0000] Waiting for your cluster resources to be created...
INFO[0000] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS
Cluster creation succeeded.
$ aws ec2 create-security-group --group-name "logchance-sg" --description "Security Group for LogChance" --vpc-id vpc-03577906fb4ee5ae8 --region us-west-2
{
"GroupId": "sg-xxxxxxxxxxxxxxxxxx"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxxxxxxxxxxxx --protocol tcp --port 80 --cidr 0.0.0.0/0 --region us-west-2
次に、以下の docker-compose.yml 及び ecs-param.yml を用意する。
ecs-param.yml では VPC 周りの設定やタスクに割り当てる Computing resource 等の設定を行う。
$ cat docker-compose.yml
version: "2"
services:
frontend:
image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/logchance
ports:
- "80:80"
command: bash -c "/usr/sbin/httpd -DFOREGROUND"
logging:
driver: awslogs
options:
awslogs-group: LogChance
awslogs-region: us-west-2
awslogs-stream-prefix: frontend
$ cat ecs-param.yml
version: 1
task_definition:
ecs_network_mode: awsvpc
task_execution_role: ecsTaskExecutionRole
task_size:
cpu_limit: 512
mem_limit: 2GB
services:
web:
essential: true
run_params:
network_configuration:
awsvpc_configuration:
subnets:
- subnet-xxxxxxxxxxxxxxxxx
- subnet-xxxxxxxxxxxxxxxxx
security_groups:
- sg-xxxxxxxxxxxxxxxxxxx
assign_public_ip: ENABLED
なお、今回は Frontend と Backend それぞれにサービスを作ることにしました。そのため docker-compose.yml の services の部分や awslogs-stream-prefix は frontend -> backend に変更している。
(本当はこの場合タスクで分けるべきなんだろうけど、あえてサービスを 2 つという構成に…)
サービスの開始
ここまで来たら、後はサービスを開始するだけ。
なお、今回は事前に作成しておいた ALB (Target Group) を使用している。また、CloudWatch Logs にログが出力されるように、—create-log-groups オプションもつけておく。
$ ecs-cli compose --project-name logchance-frontend --cluster LogChance --cluster-config LogChance service up --target-group-arn arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxxxxxx:targetgroup/logchance-frontend/xxxxxxxxxxxxxxxx --container-name frontend --container-port 80 --launch-type FARGATE --create-log-groups
INFO[0000] Using ECS task definition TaskDefinition="logchance-frontend:2"
WARN[0000] Failed to create log group LogChance in us-west-2: The specified log group already exists
WARN[0000] No log groups to create; no containers use 'awslogs'
INFO[0000] Auto-enabling ECS Managed Tags
INFO[0000] Created an ECS service service=logchance-frontend taskDefinition="logchance-frontend:2"
INFO[0000] Updated ECS service successfully desiredCount=1 force-deployment=false service=logchance-frontend
INFO[0015] (service logchance-frontend) has started 1 tasks: (task 2937be539ebd4c6d8ea076f86da4a74c). timestamp="2019-03-17 13:44:22 +0000 UTC"
INFO[0060] Service status desiredCount=1 runningCount=1 serviceName=logchance-frontend
INFO[0060] (service logchance-frontend) registered 1 targets in (target-group arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxxxxxx:targetgroup/logchance-frontend/xxxxxxxxxxxxxxxx) timestamp="2019-03-17 13:45:06 +0000 UTC"
INFO[0060] ECS Service has reached a stable state desiredCount=1 runningCount=1 serviceName=logchance-frontend
バックエンド側は DynamoDB にアクセスする必要があるので、タスク用の IAM ロールを渡してる。
$ ecs-cli compose --project-name logchance-backend --cluster LogChance --cluster-config LogChance --task-role-arn arn:aws:iam::xxxxxxxxxxxx:role/ECSTaskRole service up --target-group-arn arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:targetgroup/logchance-backend/xxxxxxxxxxxx --container-name backend --container-port 80 --launch-type FARGATE --create-log-groups
INFO[0000] Using ECS task definition TaskDefinition="logchance-backend:2"
WARN[0000] Failed to create log group LogChance in us-west-2: The specified log group already exists
WARN[0000] No log groups to create; no containers use 'awslogs'
INFO[0000] Auto-enabling ECS Managed Tags
INFO[0000] Created an ECS service service=logchance-backend taskDefinition="logchance-backend:2"
INFO[0000] Updated ECS service successfully desiredCount=1 force-deployment=false service=logchance-backend
INFO[0015] (service logchance-backend) has started 1 tasks: (task ba3e8d51a75e46e392b69b6de47f10f8). timestamp="2019-03-17 13:57:20 +0000 UTC"
INFO[0061] Service status desiredCount=1 runningCount=1 serviceName=logchance-backend
INFO[0061] ECS Service has reached a stable state desiredCount=1 runningCount=1 serviceName=logchance-backend
で、DNS 設定してデプロイ完了!
実際のアプリはこんな感じです。
サービスのスケール
ECS CLI を使えばサービスのスケールも簡単に行えます。
$ ecs-cli compose --project-name logchance-frontend --cluster LogChance service scale 3
INFO[0000] Updated ECS service successfully desiredCount=3 force-deployment=false service=logchance-frontend
INFO[0000] Service status desiredCount=3 runningCount=1 serviceName=logchance-frontend
INFO[0015] (service logchance-frontend) has started 2 tasks: (task 52b3a2a98e2f4f41a26de543a6a568e0) (task 1e118bd8ca1f429da5b337b30aa23b7d). timestamp="2019-03-17 14:11:53 +0000 UTC"
INFO[0060] Service status desiredCount=3 runningCount=3 serviceName=logchance-frontend
INFO[0060] (service logchance-frontend) registered 1 targets in (target-group arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:targetgroup/logchance-frontend/xxxxxxxxxxxxxxxx) timestamp="2019-03-17 14:12:35 +0000 UTC"
INFO[0060] ECS Service has reached a stable state desiredCount=3 runningCount=3 serviceName=logchance-frontend
$ ecs-cli compose --project-name logchance-backend --cluster LogChance service scale 3
INFO[0000] Updated ECS service successfully desiredCount=3 force-deployment=false service=logchance-backend
INFO[0000] Service status desiredCount=3 runningCount=1 serviceName=logchance-backend
INFO[0015] (service logchance-backend) has started 2 tasks: (task de34041681534ef7a1be71d5e4e5ea03) (task bccb252d8a0346e1a3d5a95fadb3d296). timestamp="2019-03-17 14:17:16 +0000 UTC"
INFO[0060] Service status desiredCount=3 runningCount=3 serviceName=logchance-backend
INFO[0060] (service logchance-backend) registered 2 targets in (target-group arn:aws:elasticloadbalancing:us-west-2:xxxxxxxxxxxx:targetgroup/logchance-backend/xxxxxxxxxxxxxxxx) timestamp="2019-03-17 14:18:11 +0000 UTC"
INFO[0060] ECS Service has reached a stable state desiredCount=3 runningCount=3 serviceName=logchance-backend