【学習記録】CircleCIに入門してみた
運動量よりも食べる量が異常に増えてきて、
体が重いです。
勉強も含めて個人でアプリを作りたいなと思って、
空き時間で取り掛かっています。
環境構築周りでCircleCIについて勉強したのでその際のメモです。
記事に書く内容
CircleCIの概要
CircleCIを使ってみる
CircleCIの設定ファイル(config.yml)について
CircleCIの概要
CircleCIって何?
CircleCIの公式&gclid=Cj0KCQiAyp7yBRCwARIsABfQsnTANY0-freoXkHqV5p4DuPaQ1JTlM7LM3DvcJaiyQ2mJieOsDp5bCIaAhcYEALw_wcB)
流行り(というかデファクトになりつつある)のSaaS型のCI/CD
サービスです。
GitHubだとかBitbucketと連携して、テストだとかビルドができるようになります。
基本的なLinuxのコマンドは実行できるので、aws cliを利用してリソースの変更だとかもできるみたいです。
ところでCI/CDって何?
CI/CD
を日本語に訳すと、*継続的インテグレーションと継続的デリバリー`という意味になります。
継続的インテグレーション - ビルドやテストを短期間で繰り返して開発効率をあげること - 定期的に実行(デイリービルド) - 短期間で繰り返しテスト 継続的デリバリー - CIの仕組みをインフラ構築まで拡張したような考え方 - テストした成果物をそのまま本番環境に自動デプロイ - テスト環境と同じ構成で本番環境を動作させることができる
CircleCIでできることって何?
ビルド
テスト
- lintツールによるコードスタイルチェック
- ○○specでのテスト実行
デプロイ
- ビルドしてテストが通ったものを本番/stg環境にデプロイすることができるようになります
パターンによりけりですが、CircleCIと連携させて下図のような開発体制を構築することができます。
開発者がCommitしたら自動でテストを走らせて、Slackに通知させるだとか
masterとかdevelopであれば、本番/stg環境に自動デプロイするといったことができるようになります。
なんでCircleCI?
CircleCIはSaaS型のサービスです。
Jenkinsのように自前でサーバを組んだりする必要がなく、環境構築/運用コストが非常に低いことが魅力的です。
ビルド~デプロイの設定はymlファイル
で設定するので、職人が作って中身がブラックボックスになりにくいことも魅力的です。
ただ、デメリットもあり、インフラ ~ ミドルまでのあたりはCircleCIの持ち物なので、
何か障害が起きた時だとかは自分たち原因究明するのはまず不可能です。
CircleCIを使ってみる
CircleCIはGithub
もしくはBitbucket
と連携させることが前提としてあります。
そのため、利用するにあたってはどちらかのアカウント登録が必要になります。
料金体系
無料枠
と有料枠
があります。
無料枠
個人開発なので無料枠を利用します。
- 同時実行ジョブ(同時に実行できるCI/CD活動)
- 1
- ビルド時間の制限
- 1000min/month
アカウント登録 ~ GitHub連携まで
CircleCIの公式&gclid=Cj0KCQiAyp7yBRCwARIsABfQsnTANY0-freoXkHqV5p4DuPaQ1JTlM7LM3DvcJaiyQ2mJieOsDp5bCIaAhcYEALw_wcB)
でアカウント登録 ~ GitHub連携までやっていくと、リポジトリにcircleci-project-setup
というリモートブランチが作成されます。
このブランチの中にはCircleCIの設定ファイル.circleci/config.yml
が含まれています。
git branch -r [circleci-project-setup] origin/circleci-project-setup origin/master git checkout -b circleci-project-setup git pull origin circleci-project-setup [circleci-project-setup] remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (3/3), done. remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (4/4), done. From github.com:*****/trainning-rails-vue * branch circleci-project-setup -> FETCH_HEAD * [new branch] circleci-project-setup -> origin/circleci-project-setup Updating 2b6de12..6dfc64b Fast-forward .circleci/config.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .circleci/config.yml
CircleCIの設定ファイル(config.yml)について
先ほどデフォルトで作成されたconfig.yml
の中身は下のようになっていました。
version: 2.1 orbs: ruby: circleci/ruby@0.1.2 jobs: build: docker: - image: circleci/ruby:2.6.3-stretch-node executor: default steps: - checkout - run: name: Which bundler? command: bundle -v - ruby/bundle-install
orbs
Version2.1から追加された機能です。
CircleCIのcommandsやジョブ(設定)をパッケージとして公開し、再利用するための仕組みです。
今回設定されているruby@0.1.2
はRubyのインストールだとかテストのコマンドがすでに定義されているパッケージになります。
jobs
jobsのフィールドは一般的に下記のような構造になう量です。
jobs -job名(1つの場合はbuildという名前にする) - docker - executer - steps
job名
1つ以上のjobを設定します。
jobが1つの場合はbuilt
という名前にしなければいけません
docker
ほとんどのwebアプリの場合は、コンテナイメージを利用すると思いますが、
CircleCI上で動かすdocker imageの設定です。
- image
- ベースとなるdocker imageを指定する。複数指定もOK
- environmentやcommandを使ってコンテナが動く際の動作を変えていく
- auth(optional)
- Docker hubを利用する場合の認証情報
- username
- password
- aws_auth (optional)
- steps
- CI環境上で動作させるコマンドや実行結果の保存、キャッシュ操作などを設定
実際に設定したconfig設定
今回アプリケーションはデプロイまではせずに、テストを実行したいと思います。
(実際のリポジトリにはnuxtのプロジェクトも含まれていますが一旦はbackendのみを)
- rubocopによるコードのLintチェック
- Rspecによるテスト
上の基本構文に含まれていない、ブロックがありますが下のような設定です。
version: 2.1 orbs: ruby: circleci/ruby@0.1.2 commands: bundleinstall: description: "bundle install --path vendor/bundle" steps: - run: cd back && bundle install --jobs=4 --retry=3 --path vendor/bundle executors: backend-executor: docker: - image: circleci/ruby:2.6.3-stretch-node environment: RAILS_ENV: test RDS_HOST: 127.0.0.1 TZ: Asia/Tokyo LANG: C.UTF-8 - image: circleci/mysql command: mysqld --default-authentication-plugin=mysql_native_password environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: trainning_test MYSQL_ROOT_HOST: '%' TZ: Asia/Tokyo jobs: rubocop: working_directory: ~/app executor: backend-executor steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - v1-dependencies- - save_cache: paths: - ./back/vendor/bundle key: v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - bundleinstall - run: name: Rubocop command: cd back && bundle exec rubocop rspec: working_directory: ~/app executor: backend-executor steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - v1-dependencies- - save_cache: paths: - ./back/vendor/bundle key: v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - bundleinstall - run: cd back && bundle exec rails db:schema:load - run: name: Rspec command: cd back && bundle exec rspec workflows: version: 2 backend_build_work_flow: jobs: - rubocop - rspec: requires: - rubocop
commandsブロック
複数のジョブで利用するコマンドを定義することができます。
今回は、front(nuxt)とbact(rails)を1つのリポジトリで管理する想定でしたので、
cd back &&
で事前にRailsプロジェクトが入っているディレクトリに移動しています。
commands: bundleinstall: description: "bundle install --path vendor/bundle" steps: - run: cd back && bundle install --jobs=4 --retry=3 --path vendor/bundle # parameterブロックを追加して引数を受け取ることもできる commands: bundleinstall: description: "bundle install --path vendor/bundle" parameters: path: type: string default: "vendor/bundle" steps: - run: bundle install --jobs=4 --retry=3 --path << parameters.path >>
executorsブロック
複数のジョブで利用する実行環境を定義することができます。 今回はrubyのイメージとmysqlのイメージを利用しています。
localhost
を複数のコンテナで共有するようです。
注意点としてはDBコンテナのホストを指定する際にはlocalhost
ではなく、127.0.0.1
を指定しないとうまく動いてくれません。
CircleCIではDockerのNetwork Namespaceという機能を使ってlocalhostを複数のコンテナで共有しています。これを使うと複数のコンテナで使うネットワークを分けることができます。もともとはLinux Kernelが提供している機能でnetnsと呼ばれ、Dockerはそれをラップしている形となります。
executors: backend-executor: docker: - image: circleci/ruby:2.6.3-stretch-node environment: RAILS_ENV: test RDS_HOST: 127.0.0.1 TZ: Asia/Tokyo LANG: C.UTF-8 - image: circleci/mysql command: mysqld --default-authentication-plugin=mysql_native_password environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: trainning_test MYSQL_ROOT_HOST: '%' TZ: Asia/Tokyo
jobsブロック
rubocop
working_directory
でappというディレクトリを作業ディレクトリにしていきます。restore_cache
で以前に保存しておいたbundleインストールしたライブラリを復元します。- 動作時間の短縮につながります。
bundleinstall
は上で定義した再利用可能なコマンドですsave_cache
でvendor/bundleに入っているライブラリ群を保存します。
rubocop: working_directory: ~/app executor: backend-executor steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - v1-dependencies- - save_cache: paths: - ./back/vendor/bundle key: v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - bundleinstall - run: name: Rubocop command: cd back && bundle exec rubocop
rspec
rspecも同じような形です。
bundle exec rails db:schema:load
とすることで、schema.rb
と同じ内容のDBを作ります。
マイグレーション忘れなどでエラーが発生しないための工夫です。
rspec: working_directory: ~/app executor: backend-executor steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - v1-dependencies- - save_cache: paths: - ./back/vendor/bundle key: v1-dependencies-{{ checksum "./back/Gemfile.lock" }} - bundleinstall - run: cd back && bundle exec rails db:schema:load - run: name: Rspec command: cd back && bundle exec rspec
workflow
workflowはバージョン2から追加された機能なのですが、
名前の通りjobのワークフローを作ります。
jobをいつ、どの順番で実行するかを定義することができます。
今回はrubocopの後にrspecを実行して欲しかったのでrequires
を使って順番関係を定義しています。
workflows: version: 2 backend_build_work_flow: jobs: - rubocop - rspec: requires: - rubocop
ローカルでcofigファイルの検証
この時点でgithubにpushすればCircleCIが自動的に変更を検知して、
configに書かれた内容が実行されるためローカルじゃなくてもconfigファイルの検証はできます。
が、なんとなくダサいので、ローカルで検証してからpushしたいと思います。
CircleCI CLI
ローカル環境からCircleCIに対してビルドしたり、
config.ymlの文法が正しいか検証ができるコマンドです。
リファレンスに沿ってダウンロードしてください。
#クイックインストール curl -fLSs https://circle.ci/cli | bash
configファイルの検証
circleci config validate
コマンドで検証ができます。
デフォルトで.circleci/config.yml
を検証対象とします。
circleci config validate [circleci-project-setup] Config file at .circleci/config.yml is valid.
ローカルでjobを実行
circleci local execute
でローカル環境で作成したjobを実行ができるのですが、
2.1
についてはまだ対応していないようで下のようなエラーが発生します。
circleci local execute [circleci-project-setup] Error: You attempted to run a local build with version '2.1' of configuration. Local builds do not support that version at this time. You can use 'circleci config process' to pre-process your config into a version that local builds can run (see 'circleci help config process' for more information)
CLI側で2.1から2.0形式に変換してくれるコマンドが用意されています。
2.1から追加されたexecutors
やorbs
を展開して出力してくれます。
circleci config process .circleci/config.yml > process.yml circleci local execute -c process.yml --job [実行したいjob名]
githubへのpush
ここまで来て、githubへプッシュすると、
CircleCIが自動的に動作していると思います。
画像では、rubocopに成功したがrspecのjobが失敗していることがわかります。
(まだ、アプリ自体がまっさらな状態なので、rails db:schema:load
でこけたようでした)
まとめ
CircleCIについて、少し学習をしてみました。
CircleCIは、SaaS型のCI/CDサービス
- CI(継続的インテグレーション)は、ビルドやテストを短期間で繰り返して品質を向上させていく取り組み
- CD(継続的デリバリー)は、インフラ環境への自動デプロイを含めてCIを実行していく取り組み
CircleCIの
config.yml
にコンテナイメージや実行するジョブを定義していく
二番煎じどころではない今更勉強したので、かなり情報が溢れています。
ただ2.1
については、DRYに書くための新機能(executors)があったりするので、
公式のリファレンスを確認した方がいいですね。
色々と進んできたら、masterブランチだけデプロイをするjobを含めて、
もう一回記事を書きたいと思います。