#はじめに
この記事は以前、私が書いた以下記事の改良版となります。
Rails6の環境構築を自動でしてくれるシェルスクリプトを作ってみた ~CircleCI導入編~ (2)
前回は開発環境構築まででしたが、今回はCircleCIによる自動テストまでをできるようにしました。
また、今回は手動で設定するべき項目が結構多いので「構築サポート」してくれるシェルスクリプトとしています。。。
私の環境は以下の通りです。
OS | 環境 |
---|---|
Windows 10 Home 64bit | Ubuntu 18.04(WSL2) |
#構築する環境
構築する環境は以下の通りです。
GitHubにプッシュ → 自動テスト → ESRにイメージプッシュ → ECSにデプロイができるようになることをゴールとします。
項目 | 使用したもの | バージョン |
---|---|---|
言語 | ruby | 2.6.6 |
Webフレームワーク | rails | 6.0.2 |
テストフレームワーク | rspec | 3.9 |
データベース | MySQL | 8.0 |
Webサーバ | Nginx | 1.17.10 |
APサーバ | puma | 4.3.5 |
コンテナ構成は以下の通りです。
appコンテナ |
---|
ruby |
rails |
puma |
dbコンテナ |
---|
MySQL |
webコンテナ |
---|
Nginx |
項目 | 使用したもの |
---|---|
コンテナリポジトリ | ECR |
コンテナオーケストレーション | ECS |
#できること
GitHubへコードをpushしたら、CircleCIがそれを検知して、
自動的テスト → ECRにイメージを自動プッシュ → ECSに自動デプロイ
を実行してくれます。
最終的に目指す構成は以下の通りです。
(ALB
やRoute53
が記載されていますが、必須ではないです。)
今回作成したシェルは以下の通りです。
まずこちらをローカルに落としてきて、[アプリ名]を引数として sudo
で実行します。
この[アプリ名]は後のECS
の設定に使うので覚えておいてください。
実行権限が付与されていない場合はchmod
で実行権限を付与してあげてください。
10分ほど待って、以下状態になったら実行完了です。
app_1 | * Listening on tcp://0.0.0.0:3000
app_1 | * Listening on unix:///myapp/tmp/sockets/puma.sock
app_1 | Use Ctrl-C to stop
自動テストをするために CircleCI ⇔ GitHub のプロジェクト連携が必要です。
CircleCIのアカウントからポチポチすれば簡単に連携できます。
↑↑↑↑↑↑↑↑↑前回はここまで↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
次に、CircleCIの環境変数を追加します。
定義する環境変数としては以下の通りです。
# CircleCI上で指定が必要な環境変数
# AWS_ACCOUNT_ID : AWSのデフォルトリージョン
# AWS_ACCESS_KEY_ID : AWSのアクセスキー
# AWS_SECRET_ACCESS_KEY : AWSのシークレットキー
# AWS_REGION : AWSのデフォルトリージョン
# AWS_ECR_ACCOUNT_URL : AWS ECRリポジトリのURL
次にAWSに各サービスを構築していくのですが、コンテナ関連サービス以外は割愛します。。。
主な作業は以下の通りです。
- VPCの作成
- PublicSubnet、PrivateSubnetの作成
- RDSの構築
- セキュリティグループの設定
ECR
にはあらかじめレポジトリを作成します。
このとき、レポジトリの名前は以下の通り設定します。
- [アプリ名]_app(appコンテナ用)
- [アプリ名]_web(webコンテナ用)
イメージも適当なものをpushしておきます。
ECS
のクラスタを作成します。
クラスタ名は[アプリ名]-cluster
としてください。
それ以外は適当でOKです。
次にECS
のタスク定義を作成していきます。
クラスタ名は[アプリ名]-task
としてください。
タスク定義内、コンテナ名は以下の通り設定してください
- app(appコンテナ用)
- web(webコンテナ用)
また、appコンテナには環境変数を定義する必要があります。
定義する環境変数は以下の通りです。
# AWS上で指定が必要な環境変数
# RAILS_MASTER_KEY : ローカル環境にあるmaster.keyの値
# MYAPP_DATABASE_USER : 本番環境データベースユーザ
# MYAPP_DATABASE_PASSWORD : 本番環境データベースパスワード
次にECS
のサービスを作成していきます。
クラスタ名は[アプリ名]-service
としてください。
今回はALB
を使用したのでターゲットグループが設定されていますが、こちらは必須ではありません。
サービス内のタスク定義が13
であることに注目してください。
自動デプロイを試すためにgithubにpushします。
すると、CirleCI上で処理が始まります。
CircleCIによるテスト → ECRにpush → ECSにdeploy
が自動で行われています。
CircleCI上の処理が終わった後、もう一度ECS
のサービスの状態を見てみると。。
デプロイが成功してタスク定義が15
に置き換わっていることが分かります。
appコンテナ、webコンテナそれぞれデプロイしたため+2
されています。
ECR
のレポジトリも確認すると新しいイメージがpushされていると思います。
#シェルの内容
###前回からの変更点
前回記事からの主な変更点は以下の通りです。
- Dockerfileを開発環境と本番環境で分ける
- CircleCI用のコンフィグファイルを修正
Dockerfileを開発環境と本番環境で分ける
スクリプト内、以下部分で開発用Dockerfile
, 本番用Dockerfile
を分けて作成しています。
# app用のDockerfile 作成(開発用)
echo "make app Dockerfile"
cat << EOF > docker/app/Dockerfile_development
FROM ruby:${RUBY_VERSION}
RUN apt-get update -y && \\
apt-get install -y default-mysql-client nodejs npm sudo && \\
npm install -g -y yarn
RUN mkdir /${APP_NAME}
WORKDIR /${APP_NAME}
COPY ./src/Gemfile Gemfile
COPY ./src/Gemfile.lock Gemfile.lock
RUN bundle install && \\
rails webpacker:install
RUN useradd -Nm -u ${USER} ${USER_NAME} && \\
groupadd -g ${GROUP} ${USER_NAME} && \\
usermod -aG sudo ${USER_NAME} && \\
usermod -u ${USER} -g ${GROUP} ${USER_NAME} && \\
echo ${USER_NAME}:${USER_PASSWORD} | chpasswd
COPY ./src /${APP_NAME}
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
EOF
# app用のDockerfile 作成(本番用)
cat << EOF > docker/app/Dockerfile_production
FROM ruby:${RUBY_VERSION}
RUN apt-get update -y && \\
apt-get install -y default-mysql-client nodejs npm sudo && \\
npm install -g -y yarn
RUN mkdir /${APP_NAME}
WORKDIR /${APP_NAME}
COPY ./src/Gemfile Gemfile
COPY ./src/Gemfile.lock Gemfile.lock
RUN bundle install && \\
rails webpacker:install
COPY ./src /${APP_NAME}
CMD ["bundle", "exec", "puma", "-e", "production", "-C", "config/puma.rb"]
EOF
分けている理由としては
- 本番環境では開発用ユーザが不要であるため
- アプリケーションを本番環境として起動するため
が挙げられます。
本番用Dockerfile
の中身を見てみると、development
ユーザを作成しておらず,
puma
の起動を-e production
というオプションを付けて実行していることが分かります。
また、本番ではRDS
を使うのでdbコンテナ
は使用しません。
加えて本番ではECS
を使うのでdocker-compose
も使用しません。
CircleCI用のコンフィグファイルを修正
以下処理でCircleCIのコンフィグファイルを作成しています。
基本的にCircleCIの公式ドキュメントを参考にしています。
# .circleci/config.yml 作成
echo "make .circleci/config.yml"
mkdir -p .circleci
cat << EOF > .circleci/config.yml
version: 2.1
jobs:
test:
machine:
image: circleci/classic:edge
working_directory: ~/repo
steps:
- checkout
- run:
name: Install Docker Compose
command: |
curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
chmod +x ~/docker-compose
sudo mv ~/docker-compose /usr/local/bin/docker-compose
- run:
name: docker-compose up --build -d
command: docker-compose up --build -d
- run: sleep 30
- run:
name: docker-compose run app rails db:create
command: docker-compose run app rails db:create
- run:
name: docker-compose run app rails db:migrate
command: docker-compose run app rails db:migrate
- run:
name: docker-compose run app bundle exec rspec spec
command: docker-compose run app bundle exec rspec spec
- run:
name: docker-compose down
command: docker-compose down
#
orbs:
aws-ecr: circleci/aws-ecr@6.0.0
aws-ecs: circleci/aws-ecs@0.0.8
workflows:
test:
jobs:
- test
#webコンテナをデプロイ
deploy-web:
jobs:
#webコンテナのイメージをECRにプッシュ
- aws-ecr/build-and-push-image:
filters:
branches:
only: master
account-url: AWS_ECR_ACCOUNT_URL
create-repo: true
dockerfile: docker/web/Dockerfile
repo: "${APP_NAME}_web"
region: AWS_REGION
tag: "\${CIRCLE_SHA1}"
#webコンテナのイメージをECSにデプロイ
- aws-ecs/deploy-service-update:
requires:
- aws-ecr/build-and-push-image
family: "${APP_NAME}-task"
cluster-name: "${APP_NAME}-cluster"
service-name: "${APP_NAME}-service"
container-image-name-updates: "container=web,tag=\${CIRCLE_SHA1}"
#appコンテナをデプロイ
deploy-app:
jobs:
#webコンテナのイメージをECRにプッシュ
- aws-ecr/build-and-push-image:
filters:
branches:
only: master
account-url: AWS_ECR_ACCOUNT_URL
create-repo: true
dockerfile: docker/app/Dockerfile_production
repo: "${APP_NAME}_app"
region: AWS_REGION
tag: "\${CIRCLE_SHA1}"
#webコンテナのイメージをECSにデプロイ
- aws-ecs/deploy-service-update:
requires:
- aws-ecr/build-and-push-image
family: "${APP_NAME}-task"
cluster-name: "${APP_NAME}-cluster"
service-name: "${APP_NAME}-service"
container-image-name-updates: "container=app,tag=\${CIRCLE_SHA1}"
EOF
ECR、ECSのorbsをインポートして、deploy-web
以下の処理でwebコンテナをデプロイ、deploy-app
以下の処理でappコンテナをデプロイしています。
configファイル内にはいくつか変数が使用されていますが、CircleCI側でそれらを定義する必要があります。
「できること」内でも記載したように、CircleCI上で以下環境変数を定義します。
# CircleCI上で指定が必要な環境変数
# AWS_ACCOUNT_ID : AWSのデフォルトリージョン
# AWS_ACCESS_KEY_ID : AWSのアクセスキー
# AWS_SECRET_ACCESS_KEY : AWSのシークレットキー
# AWS_REGION : AWSのデフォルトリージョン
# AWS_ECR_ACCOUNT_URL : AWS ECRリポジトリのURL
以上になります、これでCircleCIによるCI/CDができるようになりました。
何かの参考に慣れば幸いです。
参考記事
以下記事を参考にさせて頂きました。ありがとうございましたm(_ _)m
丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)