最近、CIの勉強をするにあたって「CircleCI実践入門──CI/CDがもたらす開発速度と品質の両立」という本を読んでCIの勉強をし直しました。
その整理でRailsでテストやデプロイをするCIを作りました。
その中で学んだ知識とか書いていきます。
環境
- Ruby On Rails6系
- Ruby 2.6.5
- PostgreSQL 11.5
- Bundler 1.17.3
- CircleCI 2.1
準備
- https://circleci.com/ から CircleCIに登録
- .circleciディレクトリ配下にconfig.ymlを置く
$ mkdir .circleci
$ touch .circleci/config.yml
3.config/database.ymlに環境変数を使う設定を書く
test:
<<: *default
database: <%= ENV['DATABASE_NAME'] || 'test_app_db' %>
host: <%= ENV['DATABASE_HOST'] || 'localhost' %>
port: <%= ENV['DATABASE_PORT'] || 5432 %>
username: <%= ENV['DATABASE_USER'] || '' %>
password: <%= ENV['DATABASE_PASSWORD'] || '' %>
用語の説明
ここからCIの説明を書いていきます。
ステップ
- ジョブの設定の最小単位
- CircleCIで実行されるコマンドのリストをステップと呼ぶ
- 大別するとRunステップとビルトインステップの2種類に分別できる
- runステップ:CircleCI上で実行したいシェルコマンドはユーザー自身がrunステップとして定義する
- ビルトインステップ:リポジトリからのソースコードのチェックアウトやキャッシュなど、CircleCIが用意した特殊なステップをビルトインステップと呼ぶ
▼たとえば▼
steps:
# ビルトインステップ
- checkout # checkoutする。working_directoryにGitリポジトリをコピーする
# runステップ
- run:
# runしているコマンドの名前をつけられる
name: pg gem の依存関係のインストール
# 実際に動かすコマンド
command: sudo apt-get update; sudo apt-get install libpq-dev
run
- コマンドライン プログラムの呼び出しのために使用する
-
command
は必須
▼たとえば▼
# ステップの1つ。ステップのうちのRunステップに該当する
- run:
# runの名前。なんでもいい。
name: pg gem の依存関係のインストール
# 実行するコマンド
command: sudo apt-get update; sudo apt-get install libpq-dev
ジョブ
- ステップの1つ以上のまとまり
- 他のCI/CD ツールではビルドとも呼ばれる
- 実行を開始するたびに実行環境をゼロから構築する(終了すると破棄する)
▼たとえば▼
jobs:
# jobの名前
build_and_test:
# 動かすマシンを定義
docker:
- image: cimg/ruby:2.6.5-node
# ↓動かすStep
steps:
- checkout
- run:
name: pg gem の依存関係のインストール
command: sudo apt-get update; sudo apt-get install libpq-dev
Executor
- Executorではどのようなマシン環境でジョブ中のステップを実行するのかを定義する
▼docker executor▼
jobs:
build_and_test:
docker:
- image: cimg/ruby:2.6.5-node
ワークフロー
- ワークフローはいくつかのジョブの塊とそれらのジョブの実行順序を定めたルール
▼たとえば▼
# ワークフロー
# ジョブの実行順序を定める
workflows:
version: 2
# ワークフローの名前
main:
# ↓Jobの実行順序を書いていく
jobs:
# Jobの名前。上で書いた名前を実行したい順番に書く
- build_and_test
# Jobの名前
- deploy-production:
# ↓Jobを実行する条件も書ける
requires: # build_and_testって「Jobが成功したら」実行する
- build_and_test
filters: # masterブランチでのみ実行する
branches:
only: master
working_directory
ステップを実行するディレクトリを明示
▼たとえば▼
# ステップを実行するディレクトリ
working_directory: ~/repo
save_cache
- save_cacheはキャッシュを生成する
- pathとkeyが必要
▼たとえば▼
# キャッシュを生成する
- save_cache:
# キャッシュに追加するディレクトリのリスト
paths:
- ./vendor/bundle
# キャッシュのキー。識別子
# checksumによって、Gemfile.lockのファイルの中身が変わると新しいキーになる
key: rails-bundle-v1-{{ checksum "Gemfile.lock" }}
restore_cache
- キーを元にキャッシュを復元する
- keysで書かれたキャッシュキーのうち最初にヒットしたキャシュを復元する
▼たとえば▼
# 以前に保存したキャッシュを key に基づいて復元する
# 保存は save_cache によって行われる
- restore_cache:
# 復元するキャッシュを検索するためのキャッシュ キーのリスト
# 最初に一致したキーのみが復元される
keys:
# checksumは、指定したファイルの中身の SHA256 ハッシュを Base64 エンコードした値が入る
- rails-bundle-v1-{{ checksum "Gemfile.lock" }}
- rails-bundle-v1-
他にも色々出来ることはありますが、最低限CIでテストしてデプロイするまでがここで出来ました。
最後にまとめて書いたCIのコードを記載します。
書いたCI
# CircleCIの実行バージョン
version: 2.1
# ジョブはステップの集まり
jobs:
# jobの名前
build_and_test:
# Docker Executor(動かすマシンの設定)
docker:
# cimg/はCircleICがあらかじめ用意しているDockerイメージの新板
- image: cimg/ruby:2.6.5-node
# circleci/はCircleICがあらかじめ用意しているDockerイメージの旧板
- image: circleci/postgres:11.5-alpine
# 環境変数の設定
environment:
RAILS_ENV: test
BUNDLE_PATH: ./vendor/bundle
DATABASE_NAME: connpass_tube_api_test
DATABASE_USER: postgres
DATABASE_PASSWORD: ""
DATABASE_HOST: 127.0.0.1
DATABASE_PORT: 5432
TZ: Asia/Tokyo
# ステップを実行するディレクトリ
working_directory: ~/repo
# ジョブの設定の最小単位
# CircleCIで実行されるコマンドのリスト
steps:
# checkoutする。working_directoryにGitリポジトリをコピーする
- checkout
# 以前に保存したキャッシュを key に基づいて復元する
# 保存は save_cache によって行われる
- restore_cache:
# 復元するキャッシュを検索するためのキャッシュ キーのリスト
# 最初に一致したキーのみが復元される
keys:
# checksumは、指定したファイルの中身の SHA256 ハッシュを Base64 エンコードした値が入る
- rails-bundle-v1-{{ checksum "Gemfile.lock" }}
- rails-bundle-v1-
# ステップの1つ。ステップのうちのRunステップに該当する
- run:
# ステップの名前。なんでもいい。
name: pg gem の依存関係のインストール
# ステップで実行するコマンド
command: sudo apt-get update; sudo apt-get install libpq-dev
- run:
name: Bundler のインストール
# gemfile.lockの一番下くらいに書かれているbundlerのバージョンを書く
command: gem install bundler -v 1.17.3
- run:
name: gem の依存関係のインストール
command: bundle check || bundle install
# キャッシュを生成する
- save_cache:
# キャッシュに追加するディレクトリのリスト
paths:
- ./vendor/bundle
# キャッシュのキー。識別子。
key: rails-bundle-v1-{{ checksum "Gemfile.lock" }}
# キャッシュを復元
- restore_cache:
keys:
- rails-yarn-v1-{{ checksum "yarn.lock" }}
- rails-yarn-v1-
- run:
name: node_modules の依存関係のインストール
command: yarn install
- save_cache:
paths:
- ~/.cache/yarn
key: rails-yarn-v1-{{ checksum "yarn.lock" }}
- run:
name: データベースの起動を待機
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: データベースのセットアップ
command: bundle exec rails db:create db:schema:load --trace
# RSpecでテスト
- run:
name: run tests
command: |
bundle exec rspec --format documentation --backtrace
# 2つめのJob
deploy-production:
# Docker Executor(動かすマシンの設定)
docker:
- image: cimg/ruby:2.6.5-node
environment:
RAILS_ENV: production
working_directory: ~/repo
steps:
- checkout
- run:
name: Deploy to Heroku Production
# HEROKU_API_KEYとHEROKU_APP_NAMEはCiecleCI上で設定している環境変数
# HerokuでAPI_KEYやアプリケーションの名前を調べてCiecleCIに設定してあげてください
command: |
git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME.git master
# ワークフロー
# ジョブの実行順序を定める
workflows:
# ここのバージョンは2である必要がある
version: 2
# ワークフローの名前
main:
# Jobの実行順序を書いていく
jobs:
# Jobの名前。上で書いた名前を実行したい順番に書く(が、requiresなどの設定をしないと同時にJobは実行される)
- build_and_test
- deploy-production:
# build_and_testのJobが成功したらdeploy-productのJobを実行する制御
requires:
- build_and_test
# Jobを実行したいブランチやコミットタグを書く
filters:
# BranchがMasterのときだけ動かしたい
branches:
only: master
「CircleCI を設定する」このCircleCIのドキュメントもとってもわかりやすいです。