くりにっき

フルスタックキュアエンジニアです

CircleCI 2.1のorbを作って最速で実アプリに投入した

tr;dr;

【前置き】先日の出来事

2.1 preview自体は結構前から出ていたのですが、先日正式リリースされました

orbとは

  • .circleci/config.yml をモジュール化する仕組み
    • 複数リポジトリで共通する処理を1箇所に集約できる
    • 自分が作ったorbを配布もできる
  • WerckerでいうところのStep Marketplace
  • GitLabCIには以前からStarter以上(有料プラン)では使えていたが、v11.4でCore(無料プラン)でも使えるようになった

【今回作ったもの】sue445/ruby-orbs

個人アプリ10個くらいCircleCIを使っているのですが、全部CircleCI 2.1にアップデートしてこのorbを導入しています

モチベーション

  • CircleCIでキャッシュをいい感じに利用しつつbundle install するにはコツがいる
    • どれくらいコツがいるのかというとCircleCIのcache key戦略だけでエントリ1つ書けるくらい
  • アプリ作る度に下記のような設定を毎回コピペするのが苦痛(10リポジトリくらいある)

.circleci/config.yml

save_bundle_cache_option: &save_bundle_cache_option
  key: v1-bundle-{{ checksum "Gemfile.lock" }}
  paths:
    - ~/app/vendor/bundle

restore_bundle_cache_option: &restore_bundle_cache_option
  keys:
    - v1-bundle-{{ checksum "Gemfile.lock" }}
    - v1-bundle

jobs:
  rspec:
    <<: *default

    steps:
      - checkout
      - restore_cache:
          <<: *restore_bundle_cache_option
      - run: ./.circleci/setup_bundle.sh
      - save_cache:
          <<: *save_bundle_cache_option

      - run: bundle exec rake test

.circleci/setup_bundle.sh

#!/bin/bash -xe

bundle install --jobs=4 --retry=3 --path vendor/bundle
bundle clean

# Resolve bundler version difference between Gemfile.lock and pre-installed in CI
gem install restore_bundled_with --no-document
restore-bundled-with

そこでこの機会に今までの知見をorbにしました

準備

organizationの設定で3rdパーティ製orbを有効にしておく必要があります。(デフォルトOFF)

f:id:sue445:20181110161451p:plain

また、リポジトリのAdvanced SettingsでEnable build processingがOffのままだと現時点だと2.1の記法が解釈できなくてvalidate errorになったので、ここもOnになってるか確認しましょう

f:id:sue445:20181110161737p:plain

使い方

.circleci/config.yml に下記のようなのを書くだけです

version: 2.1

orbs:
  # Use specific version
  # see. https://github.com/sue445/circleci-ruby-orbs/releases
  ruby-orbs: sue445/ruby-orbs@1.1.2

  # or
  # Use latest version
  # ruby-orbs: sue445/ruby-orbs@volatile

jobs:
  rspec:
    steps:
      - checkout

      - ruby-orbs/bundle-install
      # or
      - ruby-orbs/bundle-install:
          cache_key_prefix: "v1-bundle"
          bundle_jobs: 4
          bundle_retry: 3
          bundle_path: "vendor/bundle"
          bundle_clean: true
          bundle_extra_args: ""
          restore_bundled_with: true

      # Add your job (e.g. rspec, rubocop)
      - run: bundle exec rspec

補足

現時点ではGemfile.lockがコミットされてるリポジトリのみサポートしています。(具体的にはgemみたいにGemfile.lockをコミットしていないリポジトリでは使えない)

理由

  • CircleCIのキャッシュのキーにGemfile.lockのチェックサムを利用してるため
  • gemのCIでCircleCIを使ったことはあるが、色々考慮することがある&仕組が複雑になるので自分の中でベストアンサーがまだ見つかってないので作りかねてる

CircleCI 2.0から2.1に移行したPR

手持ちのアプリ10個くらい全部CircleCI 2.1対応したので、そのうちPRを1つだけ紹介します

Migrate to circleci 2.1 by sue445 · Pull Request #334 · sue445/sebastian-badge · GitHub

差分を見てもらえれば分かると思いますが、記述が大幅に減っています

ついでにHerokuにデプロイするやつもorbに寄せた

https://github.com/CircleCI-Public/circleci-orbs/tree/master/src を見てたらHerokuデプロイ用のorbもあったので導入しました

https://circleci.com/orbs/registry/orb/circleci/heroku

Before

After

補足

post-deploy

  • CircleCI 2.1だとstepを引数として受け渡しできるため、orbの処理は使いたいが特定の場所に任意の処理を差し込みたいということができる
  • 今回の場合、heroku/deploy-via-gitpre-deploypost-deploy というフックポイントを引数で用意しているので、デプロイ後に heroku run rake ar:migrate するために post-deploy を使ってる

Context

  • Herokuにdeployする時の $HEROKU_API_KEY をcontextで定義してると、同じ環境変数を各リポジトリの設定のEnvironment Variablesではなく、organizationの設定1箇所に集約できて便利
    • 2.1の新機能ではなく(たぶん)2.0時代からあった
  • Herokuのパスワード変えたり二段階認証ON/OFFするとAPI Keyも再発行されるので1箇所で集約されてると何かと便利
  • heroku/deploy-via-git もデフォルト値は環境変数$HEROKU_API_KEY から取ってきてた

f:id:sue445:20181110163549p:plain

one more thing

  • 今回作ったorbのインテグレーションテストも頑張ってるのですが、長くなるので別の機会に書こうと思います
    • どれくらい頑張ってるのかというと、orbのインテグレーションテストとその周辺技術だけで30分くらい話せるボリューム

追記:2018/11/16

書いた

sue445.hatenablog.com