記事のきっかけ
初学者ながら自身のRailsアプリにCI/CDを入れるぞ❗️と考えました。
最近話題になっているGitHub Actionsってなんだろう❓
GitHubでCI/CDも管理できるらしい。凄い❗️
その気持ちから、他のCI/CDサービスと自分なりに比較選択をし、
GitHub Actionsを選択。実装に突き進みました。
本記事はその時のコード記録と実施内容の忘備録を兼ねて記事にしました。
アプリ開発環境
- Rails v6.0.3.4
- Ruby v2.6.6
- PostgreSQL v12.4
- Docker-compose v1.26.2
- Docker v19.03.12
GitHub Actionsとは
言わずも知れた開発管理必須ツールであるGitHub。
そのGitHubが提供するCI/CDサービス。
GitHubと高度に連携されており、設定によりGitHub上のコードを
自動でビルド・テスト・デプロイが可能。
なぜGitHub Actionsなのか?
私なりにCIを選ぶにあたって他のサービスと検討しました。
他のサービスもありますが、私が比較したのは下記の2つのサービスです。
-
Circle CI
SaaS型のCI/CDサービス。FacebookやCyberAgentでの活用事例がありCI/CDサービス大手
QiitaでもCI/CDの記事が豊富にあり、アプリ作成事例での活用も多いイメージがあります。 -
Code Pipeline
AWSのCI/CDサービス。各種AWSとの連携ができるのが強み
私が選択した理由
①:GitHub Actionsの圧倒的なメリット点
GitHubのリポジトリの場所でCI/CDが実行・確認できる事です。
アプリ開発はGitHubは開発では必然的に使うのでこれは非常に便利です。
またAWSのリソースを触る場合においてアクセスキーを登録する必要がありますが
リポジトリ管理環境とAWSのアクセスキーを一度に管理できるのは、
AWSを使用したデプロイを想定している中で
リポジトリと外部SaaSでCI/CDの管理を分けるより、
進捗及び危機管理しやすい点があると考えました。
②:他のCI/CDとのサービス比較
-
上記でも触れましたが、Circle CIは外部SaaSへの権限移譲の問題などの下記資料も検証し
*GitHub Actions の self-hosted runner と Amazon EKS を使った Docker の Build Pipeline
(freee株式会社)
今後の実務の中でもこの事は問題になる可能性があるなら、CI/CDとして最初に使うのは
GitHub Actionsでもいいのではないか?と考えました。 -
Codepipelineとの比較では今回はAPI側の変更作業が多くなる事が予想されたので
GitHub上でCI/CDを随時実行し確認できた方が作業効率がいいと思われました。
以上を総合判断し、最終的にGitHub Actionsを使用する事としました。
ただこれは初心者が考えた事ですので、間違いやそれぞれのCI/CD側の言い分があるかもしれません。
Circle CIはGithub Actionsより優れていると宣伝してますし(そんな堂々と・・。)
CodepipelineもAWSとの連携をする中では大きなメリットを享受出来る事と思います。
GitHub Actions 作成手順・コード
前置きが長くなりました。早速GitHubActionsでのCI/CDを作成して行きます。
公式サイトは下記のリンク先となります。
GitHub Actionsのドキュメント
1. 作成リスト
今回RailsでのアプリでCI/CDを組み立てます。
- .github/workflows ディレクトリ配下(新規作成)
- linter.yml
- rspec_security.yml
- main.yml
- database.yml (修正)
2.CIセッティング
今回のCIは2種類でセッティングしました。
- Linter (トリガー:GitHubに
push
した時) - RSpec, security (トリガー:GitHubに
push
した時 及びpull_request
時)
name: Linter
on: [push]
jobs:
linters:
name: Linters
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- name: Ruby Bundler
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: yarn install
run: yarn install
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Run linters
run: |
bundle exec rubocop --parallel
name: Rails RSpec and security
on: [push, pull_request]
env:
RAILS_ENV: test
CI_HOST: localhost
jobs:
build:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:12
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
chrome:
image: selenium/standalone-chrome
ports:
- "4444:4444"
volumes:
- /dev/shm:/dev/shm
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- name: Ruby Bundler
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: yarn install
run: yarn install
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Setup test database
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
run: |
bundle exec rake db:create db:schema:load --trace
- name: run rspec
run: bundle exec rspec
env:
SELENIUM_REMOTE_URL: http://localhost:4444/wd/hub
- name: Archive rspec result screenshots
if: failure()
uses: actions/upload-artifact@v2
with:
name: rspec result screenshots
path: tmp/screenshots/
- name: security check
run: |
bundle exec bundle-audit check --update
bundle exec brakeman -q -w2
CD (ECR自動デプロイ)
CDはECR
へのコンテナbuild&push
を行うセッティングです。
今回の設定でのトリガーはtag push
のversion(v)
で実行しております。
name: Build and Push
on:
push:
tags:
- v*
jobs:
build-and-push:
runs-on: ubuntu-18.04
timeout-minutes: 300
steps:
- uses: actions/checkout@v1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
run: |
IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
database.yml
環境変数のセッティングが必要となります。
テスト部にENV.fetch
で第一引数で指定した環境変数を確認し、
なければブロックで定義したデフォルト値が帰るようにしています。
default: &default
adapter: postgresql
encoding: utf8
min_messages: WARNING
host: db
port: 5432
username: postgres
password: postgres
pool: 5
timeout: 5000
stats_execution_limit: 10
development:
<<: *default
database: development
test:
<<: *default
database: test
host: <%= ENV.fetch('CI_HOST') { 'db' } %>
production:
<<: *default
database: myworkdb
host: <%= ENV['DB_URL'] %>
username: <%= ENV['DB_USERNAME'] %>
password: <%= ENV['DB_PASSWORD'] %>
CI/CD内容
CI
-
Linter.yml
コード内容としてはrubocop
でのLinterチェックとしました。
ローカル開発環境ではrubocop
prettier
beautify
の3種を併用しておりますが、
push
前のLinter整形忘れチェックとしてpush
時にチェックする対応で対応しました。
*ローカル環境下でのLinterセッティングについては下記記事にまとめております。
よろしければご参照下さい。
"Rails"でのフォーマット環境を整える(VScode)
-
RSpec, security
- テストはRailsの定番RSpecを走らせました。
- セキュリティは Gemの脆弱性診断
bundle-audit
と総合セキュリティbrakeman
を活用しました。
*Railsのセキュリティに関しては別記事でまとめております。
よろしければご参照下さい。
Rails6のセキュリティチェック環境を整える
CD
セッティングコードはClassmethodさんの下記の記事を参考にしました。
この記事のおかげで以後の開発が凄く捗りました。ありがとうございます。
- 参考元リンク:GitHub ActionでDockerコンテナをビルドしてAmazon ECRに保存する
(Developers.io Classmethod株式会社)
最後に
最後まで読了頂きありがとうございます。
少しでも資料がどなたかの役に立てれば幸いです。
また今回GitHub Actionsの詳細な設定内容(コード)については触れておりませんので
別記事でGitHub Actionsの設定について個人的にまとめたいと思っております。