Railsアプリがある程度できてCircleCIを導入しようとしたらうまくいかなかったのでメモ。
CircleCIをざっくり理解して使うようになるために、簡単な手順もメモします。
1. 前置き
1-1. 動作環境
version | |
---|---|
MacOS | Mojave |
Ruby | 2.5.7 |
Rails | 5.1.7 |
MySQL | 5.7 |
CircleCI | 2 |
1-2. この記事を読んで欲しい人
下記の人の助けになれたらと思って書いた記事です。
- CircleCIは知ってる。けど導入するのがちょっと億劫(怖い)
- いろんな記事があるけどどれが良い?
1-3. 初めてCircleCIを使うときに知っておきたかったこと(まとめ)
一番知っておきたかったことは3つです。
- CircleCI使うのが初めてだからって怖がらなくていい
- 設定ファイルを追記してpushしても全然CircleCIが実行されないがあるけど時間が経てば反映される(はず)
- 大抵は
config.yml
の設定が違うのが原因
問題なく動作するようになったら自分のテンプレート残しておくのが一番良いですよねww
ちなみにもうちょっとだけ詳しく知りたい方は私なりの感想付きの解説を読んでもらえると嬉しいです。
1-4. 書こうと思った経緯
Docker + Rails + CircleCIという構成で丁寧に解説してくださっている記事は多々あります。
下記の情報はどれも分かりやすく、理解する上でとても参考になりました。
私的には、1をベースに1~3を比較してconfig/database.yml
を作成しました。
- 【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiita
- 言語ガイド: Ruby - CircleCI
- 【サーバーサイド一式】Docker + Rails + Circle CI + Terraformでインフラをコードで環境構築 & ECSへ自動コンテナデプロイ【前半】 - Qiita
- いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiita
とりあえず問題なく動作はしたのですが、どうしても1の記事中のコードに書いてあるむりやり~~
という言葉が気になって、「じゃあきれいなのはどんなだよ。。。」ということで調べてみました。
ベストプラクティスではありませんのでご容赦ください。
2. 本題(CircleCIの関連ファイルを.config/circleci.yml
だけで動くようにする)
2-1. 手順などを参考にするリンク
下記の記事がとてもわかりやすいと思います。
私も基本的にはこの手順で進めました。
順番としては下記の手順でざっくりと理解できると思います。
最終的にはGitHubにpushするとCircleCIでbuildが実行され始めればOKです。
- いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiitaを読む。理解できると2以降の内容がスラスラ理解できます。
- 【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiitaを読む。1が少し理解できたけど、飽きてきてしまったら2を読んでみるのもありだと思います。
- 2を参考に進めてみる。1から3を繰り返してコードを修正していけばある程度作れます。
- CircleCIアカウントの登録コードを実際に書いて動かしてみる
- GitHubとの連携
- 設定ファイルを作成、コードを書く
2-2. 作成・修正するファイル
下記が今回話に出てくるファイルです。
- .circleci/config.yml
- .circleci/databse.yml.ci
- config/database.yml
- Gemfile
.circleci/databse.yml.ci
は最後には削除します。
2-3. 今回のゴール
最終的に.circleci/config.yml
だけでCircleCIの設定ができるようにする
ということのが今回のゴールです。
具体的には下記の項目が挙げられrます。
-
.circleci/database.yml.ci
を削除しても動作すること - ローカルでもテストが問題なく動作すること
-
.circleci/config.yml
内の下記のコードを削除してもCircleCI上でテストが動作すること
- run: mv config/database.yml.ci config/database.yml
2-4.先に結論(私の完成形のコード)
先に私の最終的なコードを載せます。
ちなみに下記の状態になってますので悪しからず...
- コメントアウトや今回の内容に関係ないところなどは省略、削除しています。
- コードは折りたたんでます。
-
.circleci/database.yml.ci
は必要なくなったので削除しています。
**.circleci/config.yml**
version: 2
jobs:
build:
docker:
- image: circleci/ruby:2.5.7-node-browsers
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
BUNDLE_PATH: vendor/bundle
BUNDLER_VERSION: 1.17.3
RAILS_ENV: 'test'
MYSQL_HOST: 'db'
MYSQL_PASSWORD: 'password'
MYSQL_PORT: 3306
- image: circleci/mysql:5.7
environment:
MYSQL_USER: 'test'
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_PASSWORD: 'password'
MYSQL_DATABASE: 'webapp_test'
MYSQL_HOST: 'db'
name: db
parallelism: 1
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "Gemfile.lock" }}
- v1-dependencies-
- run:
name: install dependencies
command: |
gem install bundler -v 1.17.3
bundle install --jobs=4 --retry=3 --path vendor/bundle
- save_cache:
paths:
- ./vendor/bundle
key: v1-dependencies-{{ checksum "Gemfile.lock" }}
- restore_cache:
keys:
- rails-demo-yarn-{{ checksum "yarn.lock" }}
- rails-demo-yarn-
- run:
name: install yarn
command: yarn install --cache-folder ~/.cache/yarn
- save_cache:
key: rails-demo-yarn-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run: bundle exec rake db:create
- run: bundle exec rake db:schema:load
- run:
name: run tests
command: |
mkdir /tmp/test-results
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
circleci tests split --split-by=timings)"
bundle exec rspec \
--format progress \
--format RspecJunitFormatter \
--out /tmp/test-results/rspec.xml \
--format progress \
$TEST_FILES
- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/test-results
destination: test-results
**config/database.yml**
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password
host: db
pool: 5
timeout: 5000
development:
<<: *default
database: webapp_development
test:
<<: *default
database: webapp_test
2-5. 手順詳細
2-5-1. gemを追加する
Ruby + RSpec のプロジェクトでテスト結果をCircle CIで取り扱いたい場合はrspec_junit_formatter
というgemが必要になります。
Gemfileのtest環境に追加したらbundle install
を実行します。
group :test do
gem "rspec_junit_formatter"
end
2-5-2. リンクを参考にとりあえず設定をする
【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiitaを参考にしながら作成すると下記ファイルが作成されることになります。
- .circleci/config.yml
- .circleci/database.yml.ci
.circleci/database.yml.ci
はデータベースで処理を始める前に、confing/database.yml
の中のtest用の設定を変更するためです。
version: 2
jobs:
build:
docker:
- image: circleci/ruby:2.5.7-node-browsers
environment:
- BUNDLE_JOBS: 3
- BUNDLE_RETRY: 3
- BUNDLE_PATH: vendor/bundle
- BUNDLER_VERSION: 1.17.3
- RAILS_ENV: 'test'
- image: circleci/mysql:5.7
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
- MYSQL_ROOT_HOST: '%'
parallelism: 1
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "Gemfile.lock" }}
- v1-dependencies-
- run:
name: install dependencies
command: |
gem install bundler -v 1.17.3
bundle install --jobs=4 --retry=3 --path vendor/bundle
- save_cache:
paths:
- ./vendor/bundle
key: v1-dependencies-{{ checksum "Gemfile.lock" }}
# ここがとても気になった
- run: mv config/database.yml.ci config/database.yml
- run: bundle exec rake db:create
- run: bundle exec rake db:schema:load
- run:
name: run tests
command: |
mkdir /tmp/test-results
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
circleci tests glob "spec/requests/managers/*_spec.rb" | \
circleci tests split --split-by=timings)"
bundle exec rspec \
--format progress \
--format RspecJunitFormatter \
--out /tmp/test-results/rspec.xml \
--format progress \
$TEST_FILES
- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/test-results
destination: test-results
test:
adapter: mysql2
encoding: utf8
pool: 5
username: 'root'
port: 3306
host: '127.0.0.1'
database: webapp_test
2-5-3. 【解決】.circleci/database.yml.ci
が不要になるように.circleci/config.ymlの設定を追加する
今回記事にした理由の部分です。
【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiitaの中にちょっと無理やりですが、database.ymlとdatabase.yml.ciを入れ替える記述です。
というコメントが.circleci/config.yml
のコードの中にありました(下記がそのコード部分です)。
run: mv config/database.yml.ci config/database.yml
違和感を感じたので、.circleci/config.yml
だけで設定ができるようにします。
結論としては
.circleci/config.yml
のMySQLイメージに環境変数を.circleci/config.yml
に追記します。
- image: circleci/mysql:5.7
environment:
MYSQL_USER: 'test'
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_PASSWORD: 'password'
MYSQL_DATABASE: 'webapp_test'
MYSQL_HOST: 'db'
name: db
Operation CREATE USER failed for 'root'@'%' エラーが出て MySQL コンテナが起動に失敗する - emahiro/b.log
これだけです。
3. 完成するまでに発生したエラー
今回の場合は基本的にMySQL関連のエラーでした。
-
has incorrect indentation,it should be formatted like:
orin job 'build': step was not in the right format (unable to find step's name/details)
ERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'
Access denied for user 'root'@'172.28.0.3' (using password: YES)Please provide the root password for your MySQL installation
3-1. has incorrect indentation,it should be formatted like:
インデントが間違っているというエラーです。
CircleCIのSpin up environment
というSTEPSで発生しました。
単純なエラーでちゃんと原因も教えてくれているのですが、初めてのCircleCIでエラー原因が別の場所にあると思い、気づきませんでした。
しっかりとエラー文を読みましょうねというCircleCIからの訓示ですねw
3-2. ERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'
Container circleci/mysql:5.7
のステップで発生しました。
MySQLにパスワードを設定していないことがが原因で発生したエラーです。
上記の参考にしたサイトに下記のコードが多く見られましたが、公式を見ると記述がありません(データベースの構成例 - CircleCI)。
みんなどこからこのコードを引っ張ってきてるのでしょうか?とても気になります。
config.yml
の下記のコードはkeyの文字の意味そのままですが、
このコードを付け加えることでパスワードを設定しなくてもMySQLに接続できるようにしてくれます。
# 省略
- MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
- MYSQL_ROOT_HOST: '%'
# 省略
そのため、上記のコードをコメントアウトするとERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'
というエラーが発生しました。
上記のコードを
docker mysql ERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'
でググると下記の記事が出てきます。
Operation CREATE USER failed for 'root'@'%' エラーが出て MySQL コンテナが起動に失敗する - emahiro/b.log
ググって出てきた記事のように.circleci/config.yml
のmysqlイメージのenvrionment
にパスワードを設定することで解決されます。
- image: circleci/mysql:5.7
environment:
MYSQL_USER: 'test'
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_PASSWORD: 'password'
MYSQL_DATABASE: 'webapp_test'
MYSQL_HOST: 'db'
name: db
MYSQL_USER
がroot
だとダメなのでtest
に変更しました(これも記事に書いてありました)。
一番下のname
とは他のコンテナで使用するときなどに引用するコンテナの別名みたいな感じです。
3-3. Access denied for user 'root'@'172.28.0.3' (using password: YES)Please provide the root password for your MySQL installation
docker mysql Access denied for user 'root'@'' (using password: YES)Please provide the root password for your MySQL installation
でググると下記の記事が出てきました。
railsのapp作成でmysqlを使用する時の導入とハマるところ rake db:createができるまでの流れ - Qiita
モロこれです。
パスワードが指定してなかったので、config/database.yml
のpassword
欄に下記のコードを設定することで解決しました。
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password # <- ここ
test:
<<: *default
username: test
password: password
database: webapp_test
ただ後から気づいたのですが、上記の設定をしてしまうとローカルでのテストに影響が出てしまう場合があります。
試していて私が最終的問題なく動作するようになった設定は
-
config/database.yml
にCircleCIの設定を書かない(あくまでローカル用の設定とする) - MySQLのユーザー、パスワード、データベース名前は
config.yml
に書く(上記の部分で設定済み)
というものでした。
3-4. Mysql2::Error::ConnectionError: Can't connect to MySQL server on '127.0.0.1' (115)
bundle exec rake db:schema:load
というSTEPで発生しました。
MySQLに接続できませんというエラーです(おなじみですねw)。
このエラーは上記で設定した
name: db
というコードが関係しています。
もともとMYSQL_HOST
には127.0.0.1
を設定していましたが、何度も修正していくうちにこのコードを削除していました。
MySQLのイメージに設定したname: db
を使用してrubyのイメージの環境変数(environment)のMYSQL_HOST
に'db'
という形で指定することでエラーは解消されました。
docker:
- image: circleci/ruby:2.5.7-node-browsers
environment:
- BUNDLE_JOBS: 3
- BUNDLE_RETRY: 3
- BUNDLE_PATH: vendor/bundle
- BUNDLER_VERSION: 1.17.3
- RAILS_ENV: 'test'
- MYSQL_HOST: 'db' # <- 127.0.0.1から変更
- MYSQL_PASSWORD: 'password'
- MYSQL_PORT: 3306
- image: circleci/mysql:5.7
environment:
MYSQL_USER: 'test'
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_PASSWORD: 'password'
MYSQL_DATABASE: 'webapp_test'
MYSQL_HOST: 'db'
name: db
4. 【補足】初めてCircleCIを使うときに知っておきたかったこと(その理由)
この内容はの内容をちょっとだけ細かくしている内容(私見あり)なので読み飛ばしてもらって大丈夫です。
4-1. CircleCI使うのが初めてだからって怖がらなくていい
今まで苦労して作成したアプリをCircleCIを導入して失敗すると今までの苦労が、、、
そんな恐れは必要ありません(知らなかった私はビクビクしながらやってました)。
CircleCIの設定はconfig.yml
の1ファイルにまとめて書くことができるので他の環境に影響することは(たぶん)ありません。
無料枠もあるのでpush1回で課金されることは滅多にないと思っていいです。
CircleCIに接続できて、buildが実行されれば、最低限の設定はできていると思います。
4-2. 設定ファイルを追記してpushしても全然CircleCIが実行されない
私の場合は初めてCircleCIの設定ファイルを追記してpush、20分前後かかって初めてCircleCI上でテストが実行された記憶があります。
設定とか問題なさそうなのに、、、と色々調べているうちに、いつのまにかCircleCIがテストを実行してました。笑
すぐ実行してくれる場合がほとんどかもしれませんが、私みたいなこともあるので、気を長く持ってください。
4-3. 大抵はconfig.yml
の設定が違うのが原因
だってローカルで動いてるんだもん。
エラーが表示されていたらそのエラー文を元に原因を探ることがとても大事です。
ローカルのテストもCircleCIのテストもコンテナ上で動いているのでエラー内容は基本的に同じであるはずです。
ちなみに私がCircleCIで初buildできたときに発生したエラーの原因はconfig.ymlのインデントがずれている
というものでした。
以上。
1-2. 初めてCircleCIを使うときに知っておきたかったこと(まとめ)に戻る
5. 最後に
初めての技術に触るときはやはり
- 最小の壊れてもよいアプリを使用して試す
- 新規アプリを作成して試す
のが一番だと実感しました。
ビクビクしながらやるのは辛いです(m_ _m)