はじめに
ECSの概要とECS CLIを使ってアプリのデプロイの仕方について書いていきます。
ECSやその他のサービスに関して、そこまで理解できてないので間違ってる部分も多いと思います。
とりあえず記事通りに作業したらRails6のアプリケーションをECSにデプロイできる様に記事を書きたいと思います。
もしうまくいかなかったらおそらく権限関係なので権限を見直してみてください。
ECSの概要
ECSはdockerのコンテナをそのままaws上にデプロイできるサービスです。
docker-hubやecrなどのdockerイメージのレジストリからイメージを持ってきてコンテナを作成してデプロイできます。
自分がやった場合、下記の様になりました。
ECSはクラスターと言うEC2のインスタンス群みたいなのをまず作ります。
このクラスター内にEC2があり、その中にECSのタスクと言うのを作ります。
このタスク上でdockerのコンテナが起動される形になります。
dockerコンテナの起動に関してはecsにタスク定義を作成してこのタスク定義を元にdockerコンテナを作成していくことになります。
dockerコンテナの起動に必要なdockerイメージに関してはdockerイメージレジストリから取ってきます。
docker hubの場合は誰でも見れてしまうのでecrを使うのが良いと思います。
作成したコンテナはALBを通して公開されます。
ALBを使うことで負荷がかかった時に新しくタスクの作成し負荷を分散できます。
作成したコンテナに関してはec2インスタンスにkeypairを使ってそこからdockerコンテナにアクセスする形になります。
ちなみにFargateを使う場合は確かコンテナにアクセスできなかった気がします。
デプロイ
前提として
- PCはMac
- ローカルPCにdockerとmysqlがインストールされていること
Railsアプリの作成
まずRailsアプリの作成をします。
適当なフォルダを作成してそこに Dockerfile docker-compose.yml Gemfile Gemfile.lock を作成します。
内容は下記の様にします。
Dockerfile
FROM node:13.5-alpine as node
RUN apk add --no-cache bash curl && \
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1
FROM ruby:2.6.5-alpine
COPY --from=node /usr/local/bin/node /usr/local/bin/node
COPY --from=node /opt/yarn-* /opt/yarn
RUN ln -fs /opt/yarn/bin/yarn /usr/local/bin/yarn
RUN apk add --no-cache git build-base libxml2-dev libxslt-dev postgresql-dev postgresql-client tzdata bash less && \
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN apk add --no-cache alpine-sdk \
mysql-client \
mysql-dev
ENV APP_ROOT /app
RUN mkdir $APP_ROOT
WORKDIR $APP_ROOT
RUN gem update --system && \
gem install --no-document bundler:2.1.4
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock
RUN bundle install
ADD . $APP_ROOT
version: "3"
services:
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_PASSWORD: password
MYSQL_USER: myuser
MYSQL_DATABASE: ecs_development
ports:
- "3306:3306"
web:
build: .
command: bash -c "yarn install && rails db:migrate && rails s -p 3000 -b '0.0.0.0'"
ports:
- "3000:3000"
volumes:
- .:/app
tty: true
links:
- db
Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem 'rails', '~> 6.0.2', '>= 6.0.2.2'
Gemfile.lockは中身は空でOK
ファイルが作成できたら
docker-compose run --rm web rails new . --database=mysql --skip-bundle --skip-test
このコマンドを実行します。
そうするとrailsのファイルがローカルに作成されていると思います。
config/database.ymlのdevelopmentの部分を下記の様に変更します。
development:
<<: *default
host: db
username: myuser
password: password
database: ecs_development
そしたら
docker-compose up --build
コマンドを実行します。
コンテナが起動したらrails6はwebpackerを使っているので下記コマンドを実行します。
docker-compose exec web rails webpacker:install
そうするとlocalhost:3000にアクセスすると見慣れた画面が表示されると思います。
scaffoldでuserのcrudを作ります。
docker-compose exec web rails generate scaffold user name:string age:integer
docker-compose exec web rails db:migrate
config/routes.rbにroutesを追加します。
root to: "users#index"
これでlocalhost:3000にアクセスすると
この画面が表示されると思います。
とりあえずこれでアプリのベースの作成は終わりです。
aws-cli ecs-cliのインストール
デプロイに使うツールをインストールします。
brew install awscli
brew install amazon-ecs-cli
aws configureの設定
aws configureを設定します。
まずIAMユーザーを作る必要があるのでAWSコンソールにアクセスします。
IAMの画面を表示してユーザーの追加ボタンをクリックします。
プログラムによるアクセスにチェックをつけ次へボタンを押します。
ポリシーのアタッチ画面にて
- AmazonECS_FullAccess
- AmazonEC2ContainerRegistryFullAccess
を追加します。
そのまま次へボタンを押していくと最後にユーザーのアクセスキーとシークレットキーが表示されるので保存しておきます。
そしたらaws configureの設定をします。
コマンドラインで
aws configure
と入力して
access_keyとsecret_keyの入力
regionはap-northeast-1と入力します。
これで aws configureの設定は終わりです。
IAMユーザーの権限は不足しているので後々追加していきます。
クラスターの作成
クラスターの作成時にec2のキーペアを設定するのでまずキーペアの作成を行います。
EC2の画面を表示するとそのサイドメニューにキーペアと言うものがあります。
このキーペアをクリックしてキーペアを作成し、pemファイルをローカルpcにおきます。
自分の場合はホーム直下にaws-keypairフォルダを作成してそこに置いています。
ファイルに関しては権限を変更しておく必要があります。
自分の場合は下記の上になります。
chmod 400 aws-keypair/qiita-tutorial.pem
ファイルのパスは自分の環境のものに変更してください。
それではECSのクラスターを作成していきます。
クラスターの作成に関してはECS_FullAccessで付与されないが必要な権限が結構あるので別途追加する必要があります。
IAMのポリシーからポリシー作成をクリックします。
ビジュアルエディタでサービス、アクションを選択していきます。
まずIAMに関しては
- AddRoleToInstanceProfile
- CreateInstanceProfile
- CreateRole
- DeleteInstanceProfile
- DeleteRole
- PassRole
- RemoveRoleFromInstanceProfile
- AttachRolePolicy
- DetachRolePolicy
を追加します。
次にEC2に関して
- DeleteInternetGateway
- DeleteRouteTable
- DeleteSecurityGroup
を追加します。
最終的に下記の画像の様になればOKです。
ポリシーの作成をしたら作成したポリシーをユーザーにアタッチします。
IAMのユーザーから作成したユーザーをクリックしてアクセス権限の追加をクリックします。
そしたら既存のポリシーを追加をクリックして作成したポリシーを追加します。
ポリシーの追加が終わったら
下記のコマンドを実行します。
アクセスキーとシークレットキーに関してはIAMユーザーを作成したときの物を利用してください。
キーペアの名前も自分が作成したキーペアの名前に変更してください。
ecs-cli configure --cluster qiita-tutorial --default-launch-type EC2 --config-name qiita-tutorial --region ap-northeast-1
ecs-cli configure profile --access-key access_key --secret-key secret_key --profile-name qiita-tutorial-profile
ecs-cli up --keypair qiita-tutorial --capability-iam --size 1 --instance-type t2.micro --cluster-config qiita-tutorial --ecs-profile qiita-tutorial-profile
実行するとクラスターの作成が行われます。
--size 1 と設定しているのでec2インスタンスが一つ立ち上がっているはずです。
これでクラスターの作成は終わりです。
RDSの作成
デプロイの準備は整いましたがデータベースにrdsを使うのでrdsの作成を行なっていきます。
rdsの画面を表示してデータベースの作成をクリックします。
簡単作成、MySQL,無料利用枠を選択します。
DB インスタンス識別子、マスターユーザー名、パスワードを設定して作成します。
作成できたら作成したrdsをクリックすると接続とセキュリティの部分にエンドポイントが記載されています。
ローカルPCからrdsへアクセスができる様にするためにRDSの変更をクリックして
パブリックアクセシビリティ をありにします。
またセキュリティーグループの設定も必要なので行います。
作成したrdsのセキュリティーと接続の部分にVPC セキュリティグループの欄があります。
クリックできる様になっているのでクリックします。
rdsのセキュリティーグループが表示されると思います。
インバウンドルールの部分をクリックします。
タイプはMYSQL/Auroraを選択します。
ソースの設定は下記の画像の様にしましたが細かい設定を行いたい場合は適宜行なってください。
そしたらローカルPCから下記コマンドでrdsに接続します。
mysql -h rdsのエンドポイント -u rdsのユーザー名 -p
これでパスワードを入力するとrdsに接続できるはずです。
そしたらデータベースの作成を行います。
CREATE DATABASE ecs_development default character set utf8;;
これでrdsにデータベースの作成ができました。
database.ymlの修正
host,username,passwordを環境変数を見る様に修正します。
development:
<<: *default
host: <%= ENV['MYSQL_HOST'] %>
username: <%= ENV['MYSQL_USER'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
database: ecs_development
ALBの設定
次にALBの設定を行なっていきます。
EC2の画面の再度メニューからロードバランサーをクリックします。
そしたらロードバランサー作成をクリックします。
そしたらApplication Load Balancerの作成をクリックします。
まず名前を入力します。
リスナーはそのままで大丈夫です。
vpcの設定ですがecsのec2インスタンスのvpcを選択しなくてはいけません。
確認の仕方はクラスターのタスクのコンテナインスタンスをクリックします。
ec2インスタンスがあるのでクリックします。
ec2インスタンスが表示されます。
したの説明の部分にvpcのidが記載されています。
確認したらそのvpcをロードバランサーの作成の部分のvpcの選択でそれを選択します。
セキュリティーグループは新しいセキュリティーグループを作成をクリックします。
そして下記の画像の様に設定します。
ターゲットグループの設定の部分で新しいターゲットグループを選択して名前を入力します。
ターゲットはインスタンスを選択します。
次へいくとec2インスタンスの選択画面が出るのでecsで使うec2インスタンスを選択して登録済みに追加ボタンをクリックします。
あとは次へを押して作成すればOKです。
config/environment/development.rbの修正
rails6ではhost名を明示的に記載しないと起動しません。
なのでconfig/environment/development.rbに下記を追加します。
config.hosts << ALBのdns名を記載
ecrにイメージの登録
ecsで利用するイメージをecrに登録していきます。
ecrの画面を開きレポジトリの作成をクリックします。
適当に名前を入力して作成します。
レポジトリの作成が終わったらローカル環境でdockerイメージをビルドしてpushします。
まず
docker build . -t ecrのURI
を実行します。
そしたら次に下記コマンドでecrにpushします。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ecrのURI
docker push ecrのURI
これでecrへのpushはOKです。
デプロイ
デプロイの準備ができたのでデプロイします。
まずデプロイ用のdocker-compose.ymlを作成します。
名前はdocker-compose-deploy.ymlとします。
version: '3'
services:
web:
image: rdsのURI
command: bash -c "yarn install && rails db:migrate && rm /app/tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
environment:
MYSQL_USER: rdsのuser名
MYSQL_PASSWORD: rdsのpassword
MYSQL_HOST: rdsのエンドポイント
TZ: "Japan"
ports:
- "80:3000"
logging:
driver: awslogs
options:
awslogs-group: ecs-tutorial
awslogs-region: ap-northeast-1
awslogs-stream-prefix: web
そしたら
ecs-cli compose -f docker-compose-deploy.yml up --create-log-groups --cluster-config qiita-tutorial --ecs-profile qiita-tutorial-profile
このコマンドを実行します。
そうするとタスクが起動します。
ecsの画面で実行中のタスクに1と書いてあればOKです。
もしうまくいかない場合はcloud watchにログが出されていると思うのでそちらを確認してください。
確認
これでデプロイできているはずなのでALBのdns名をurlに貼り付けます。
そうすると....
無事開けました。
もちろんデータの登録もできます。
コンテナにアクセス
とりあえずこれでデプロイはOKですがecsコンテナにアクセスもしてみます。
まずecsで使われているec2インスタンスのセキュリティーグループを確認してインバウンドルールに関して全てのマイIPからの全てのトラフィックを許可します。
ecsコンテナへのアクセスにはsshを使用します。
まずecsで起動しているec2インスタンスのプライベートipをコピーします。
そして
ssh -i keypairのパス ec2-user@ec2インスタンスのパブリックdns
を実行します。
そうするとec2インスタンスにssh接続できるので
docker ps
を実行します。
そうするとコンテナが起動しているので
docker exec -i -t コンテナID bash
を実行するとbashに入れます。
試しに
rails -v
と実行すると
bash-5.0# rails -v
Rails 6.0.3
こう返ってきました
これでecsで起動したdockerへのアクセスはOKです。
終わり
とりあえずこれで終わりです。
いろいろ問題点あるとは思うのでお気づきの点があれば指摘していただけると助かります。