8
4

More than 3 years have passed since last update.

はじめてのCircleCI(Docker+Rails+MySQL)でハマったお話

Last updated at Posted at 2021-03-27

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を作成しました。

  1. 【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiita
  2. 言語ガイド: Ruby - CircleCI
  3. 【サーバーサイド一式】Docker + Rails + Circle CI + Terraformでインフラをコードで環境構築 & ECSへ自動コンテナデプロイ【前半】 - Qiita
  4. いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiita

とりあえず問題なく動作はしたのですが、どうしても1の記事中のコードに書いてあるむりやり~~という言葉が気になって、「じゃあきれいなのはどんなだよ。。。」ということで調べてみました。
ベストプラクティスではありませんのでご容赦ください。

2. 本題(CircleCIの関連ファイルを.config/circleci.ymlだけで動くようにする)

2-1. 手順などを参考にするリンク

下記の記事がとてもわかりやすいと思います。
私も基本的にはこの手順で進めました。
順番としては下記の手順でざっくりと理解できると思います。
最終的にはGitHubにpushするとCircleCIでbuildが実行され始めればOKです。

  1. いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiitaを読む。理解できると2以降の内容がスラスラ理解できます。
  2. 【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる - Qiitaを読む。1が少し理解できたけど、飽きてきてしまったら2を読んでみるのもありだと思います。
  3. 2を参考に進めてみる。1から3を繰り返してコードを修正していけばある程度作れます。
    1. CircleCIアカウントの登録コードを実際に書いて動かしてみる
    2. GitHubとの連携
    3. 設定ファイルを作成、コードを書く

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
.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
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を実行します。

Circle CI のテストで RSpec のテストレポートを生成する - Tbpgr Blog

Gemfile
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用の設定を変更するためです。

.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'
      - 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
.circleci/database.yml.ci
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に追記します。

.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: or in 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に接続できるようにしてくれます。

.circleci/config.yml
# 省略
- 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にパスワードを設定することで解決されます。

.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

MYSQL_USERrootだとダメなので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.ymlpassword欄に下記のコードを設定することで解決しました。

config/database.yml
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'という形で指定することでエラーは解消されました。

config.yml
    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)

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4