概要
ECS CLI を使って Rails をデプロイする方法を書いています。
ECS の起動タイプには FARGATE を指定します。
デプロイするアプリには Rails の前にリバースプロキシとして Nginx も含んでいます。
ECS CLI の設定
まず、クラスターを作成するために ECS CLI の設定をします。
CLI から AWS API を呼び出せるように認証情報が必要です。
ecs-cli configure profile --access-key AWS_ACCESS_KEY_ID --secret-key AWS_SECRET_ACCESS_KEY --profile-name rails-app
そしてクラスター設定を作成します。
ecs-cli configure --cluster rails-app --default-launch-type FARGATE --config-name rails-app --region ap-northeast-1
クラスターの作成
クラスターの作成は ecs-cli up
コマンドを使用します。
ここで ECS の起動タイプに FARGATE を指定しています。
ecs-cli up --cluster-config rais-app --ecs-profile rails-app
コマンドを実行すると、新しく VPC と 2 つのサブネットが作成されます。
これらの ID はのちに構成ファイルを作るときに必要になるので控えておきましょう。
また、デプロイしたアプリにアクセスできるように VPC のセキュリティグループの設定を変更してポート 80 からの接続を許可しておきます。
セキュリティグループの ID を調べるには以下のコマンドを実行します。
aws ec2 describe-security-groups --filters Name=vpc-id,Values=VPC_ID --region ap-northeast-1
上記で調べたセキュリティグループのポート 80 への接続を許可するには以下のコマンドを実行します。
aws ec2 authorize-security-group-ingress --group-id SECURITY_GROUP_ID --protocol tcp --port 80 --cidr 0.0.0.0/0 --region ap-northeast-1
Docker イメージの作成
次にデプロイに使用する Docker イメージを作成します。
作成するのは Rails と Nginx の 2 つです。
Rails
イメージをビルドするためのファイルを用意します。
まずは Ruby のイメージを使ってコンテナの中に入ります。
docker run --rm -it -v ${PWD}:/usr/src/app ruby:2.7 bash
コンテナの中に入ったら rails new
でファイルを生成します。
cd /usr/src/app
gem install rails
rails new webapp --skip-bundle
そして生成したファイルでイメージをビルドします。
以下がビルドに使用する Dockerfile です。
FROM ruby:2.7
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt update -yqq && apt install -yqq yarn
WORKDIR /usr/src/app
COPY Gemfile Gemfile
RUN bundle install
COPY . /usr/src/app
RUN bin/rails webpacker:install
EXPOSE 3000
CMD ["bin/rails", "s", "-b", "0.0.0.0"]
cd webapp
docker build . -t webapp
Nginx
Nginx へのアクセスを Rails へ振り分けるために設定ファイル nginx.conf
を作成します。
アクセスログやエラーログの指定は行なっていません。
これは Docker イメージのデフォルトではそれぞれログの出力先が標準出力と標準エラー出力になっているためです。
FARGATE では同じタスクに属するコンテナは localhost 経由で接続できるようになっています。
よって、proxy_pass
では localhost で通信先を指定しています。
user nobody nogroup;
worker_processes 5;
events {
worker_connections 4096; ## Default: 1024
}
http {
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nopush on;
server {
listen 80;
location / {
proxy_pass http://localhost:3000;
}
}
}
こちらも以下のような Dockerfile を作成してビルドします。
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
docker build . -t proxy
ECR へイメージをプッシュ
作成したイメージを ECR へプッシュします。
ECR へのプッシュは ecs-cli push
で行えます。
ecs-cli push webapp --ecs-profile rails-app
ecs-cli push proxy --ecs-profile proxy
コマンドを実行してプッシュに成功すると、イメージ名の前にプレフィックスとして AWS のアカウント ID が含まれているイメージタグが出力されます。
このイメージタグは ECS の構成ファイルを作成するときに使用します。
ECS の構成ファイルを作成
デプロイ用の構成ファイルを作成していきます。
まずは docker-compose.yml
から。
version: "3"
services:
proxy:
image: <AWS_ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/proxy
ports:
- 80:80
logging:
driver: awslogs
options:
awslogs-group: rails-app
awslogs-region: ap-northeast-1
webapp:
image: <AWS_ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/webapp
logging:
driver: awslogs
options:
awslogs-group: rails-app
awslogs-region: ap-northeast-1
logging でドライバーに awslogs を指定することで標準出力されたログが CloudWatchLogs へ書き込まれるようになります。
そして、ECS 固有の設定ファイルである ecs-params.yml
を作成します。
subnets や security_groups のところにはクラスター作成のときに出力された ID をそれぞれ入力してください。
version: 1
task_definition:
task_execution_role: ecsTaskExecutionRole
ecs_network_mode: awsvpc
task_size:
mem_limit: 0.5GB
cpu_limit: 256
run_params:
network_configuration:
awsvpc_configuration:
subnets:
- "subnet ID 1"
- "subnet ID 2"
security_groups:
- "security group ID"
assign_public_ip: ENABLED
クラスターへデプロイ
これですべての準備が完了しました。
最後に、 ecs-cli compose service up
コマンドを実行してデプロイします。
ecs-cli compose service up --create-log-groups --cluster-config rails-app --ecs-profile rails-app