Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to use CircleCI and Sider in CrowdWorks

How to use CircleCI and Sider in CrowdWorks

CircleCI/Sider合同ミートアップ@プレイド 新GINZA SIXオフィス
https://connpass.com/event/98494/

2fe6800486cb1d45bb6316d04f40a73e?s=128

Hideki Igarashi

September 13, 2018
Tweet

Transcript

  1. How to use in CrowdWorks CircleCI and Sider $JSDMF$*4JEFS߹ಉϛʔτΞοϓ!ϓϨΠυ৽(*/;"4*9ΦϑΟε 

  2. About me twitter.com/ganta0087 github.com/ganta Hideki Igarashi Engineer

  3. クラウドソーシングサービス クラウドソーシング = Crowd (群衆) + Sourcing (外注) 2012年3⽉サービス開始〜 会員数215万⼈

  4. インターネットを活⽤することで、世界中の企業と個⼈が 直接つながり、仕事の受発注を⾏うことができる

  5. CrowdWorksのリポジトリ ▶ ⾔語・フレームワーク ▶ Ruby (Rails / Gem) ▶ Go

    ▶ JavaScript (Node.js / Hubot) ▶ Swift (iOS) / Java (Android) ▶ Elixir
  6. 本⽇はRails成分多め Rails

  7. CrowdWorksにおける CircleCI Sider の活⽤⽅法

  8. CrowdWorksにおける CircleCIの活⽤⽅法

  9. ▶ .circleci/config.ymlがあるリポジトリ数: 56 ▶ ⽤途 ▶ テスト / ビルド ▶

    Dockerイメージ作成 ▶ ドキュメント⽣成 CircleCI
  10. すべてCircleCI 2.0に移⾏完了

  11. ▶ リポジトリのサイズ: 約1.3GB ▶ ⼤きすぎてキャッシュからリストアするのも遅い ▶ 過去の遺物は削除したのでShallow Cloneならばだいぶ速 くなる GitリポジトリのShallow

    Clone % git count-objects -vH count: 2802 size: 13.28 MiB in-pack: 547956 packs: 1 size-pack: 1.34 GiB prune-packable: 0 garbage: 0
  12. GitリポジトリのShallow Clone - checkout - run: name: GitリポジトリのCheckout command: |

    git clone --depth=1 --branch $CIRCLE_BRANCH --single-branch $CIRCLE_REPOSITORY_URL . # ビルド対象のリビジョンにリセットして⽬的のコミットが取得できたかを確認 git reset --hard $CIRCLE_SHA1
  13. ▶ 2.0からBuild SettingsのClear Cachesは効かなくなった ▶ 設定ミスなどで稀にキャッシュを全部⾶ばしたくなる ▶ 全部のキャッシュキーを書き換えるのは⾯倒 ▶ 初めからキャッシュキーに共通の環境変数を埋めておく

    ▶ Build SettingsのEnvironment VariablesにYYYYMMDDhhmm形式で値を 格納しておく キャッシュを⼀⻫にクリアできるようにする - restore_cache: name: Restoring Cache - Bundler keys: - gems-{{ .Environment.COMMON_CACHE_KEY }}-{{ checksum "Gemfile.lock" }} - gems-{{ .Environment.COMMON_CACHE_KEY }}-
  14. ▶ キャッシュにGemfile.lockの ハッシュ値をテキストで残し ておき、⼀致したら完全ス キップするようにした ▶ Gemがたくさんあると完全 ⼀致状態でbundle install しても少し時間が掛かる

    ▶ うっかりGemfile.lockのコ ミット忘れたものをスルーし てしまったのでGemfileも チェックするように変更 キャッシュ戦略 - run: name: bundle installの実⾏ command: | checksum_file=vendor/bundle/checksum.sha256 bundle config --local disable_shared_gems 1 bundle config --local path vendor/bundle if [ -e $checksum_file ] && shasum --check $checksum_file then echo "Skipped." else # Gemのインストール bundle install --deployment # 使われなくなったGemの削除 (キャッシュを圧迫するため) bundle clean # チェックサムを保存 shasum --algorithm 256 Gemfile > $checksum_file shasum --algorithm 256 Gemfile.lock >> $checksum_file fi
  15. ▶ また、OSにインストールされてい るライブラリのバージョン等に依 存する場合があるため、Rubyや Node.jsの場合はそれらもキーに 含めてチェックしたほうが安全 ▶ {{ arch }}でアーキテクチャも取れ

    るのでこれも⼊れておく キャッシュ戦略 - run: name: Generate OS version file command: | cat /etc/os-release > tmp/os_version - run: name: Generate Ruby version file command: | ruby --version > tmp/ruby_version - run: name: Generate Node version file command: | node --version > tmp/node_version key: gems-{{ arch }}-{{ .Environment.COMMON_CACHE_KEY }}-{{ checksum "tmp/os_version" }}- {{ checksum "tmp/ruby_version" }}-{{ checksum "Gemfile"}}-{{ checksum "Gemfile.lock" }}
  16. ▶ イメージのRegistryはQuay or Amazon ECR ▶ Quayの⾃動ビルドは柔軟性がない ▶ ⾃前でCircleCIを使ってビルド&プッシュ Dockerイメージのビルド

  17. Dockerイメージのビルド build_and_push: docker: - image: docker:18.05.0-ce-git steps: - setup_remote_docker: version:

    18.05.0-ce - checkout - run: name: Build command: | docker build -t --build-arg xxx=$XXX quay.io/crowdworks/xxxxxx . - run: name: Login to Quay command: | echo $QUAY_TOKEN | \ docker login --username $QUAY_USER --password-stdin quay.io - deploy: command: docker push quay.io/crowdworks/xxxxxx Docker Hubに公式イメージがあるので ビルドイメージに利⽤。 checkoutで必要になるため、Git⼊りの イメージを使う。 バージョンを揃えておく。
  18. ▶ ジョブが⾛るビルドイメージ側の話 ▶ ⾃前イメージはlatestタグが付いているその時点のイメージの SHA256を使っていたが、タグが差し替わったり消えたりする とSHA256の参照も消えてしまってCIが回せなくなった ▶ <image name>@sha256:XXXXXXXXXX ▶

    何よりも中⾝がいつのものかわかりづらい ▶ 元のミドルウェアのバージョン+Dockerfileのコミットハッ シュにするとわかりやすい ▶ 例: quay.io/crowdworks/elasticsearch:5.6.10-11ead2b ⾃前Dockerイメージのバージョン固定⽅法
  19. ▶ 同時実⾏可能なノード数の制約がなくなるため、ビルド待ちが なくなる ▶ pushしたら常に即ビルド開始 ▶ 以前は定期的にAPIを叩いて
 ビルド待ち時間をDatadogに
 ⾶ばし、⻑くなってきたら
 Slackに通知してコンテナを


    買い⾜したり戻したりしていた
 (温かみのある⼿作業) Performance Pricing plan
  20. ▶ コンテナのリソース設定ができるようになる ▶ https://circleci.com/docs/2.0/configuration-reference/ #resource_class ▶ モノリシックなRailsアプリケーションはメモリを⾷う… Performance Pricing plan

  21. ▶ まだ単純に切り替えただけ ▶ 元々ジョブの先頭でキックしていた別のジョブを分離 Workflow workflows: version: 2 build: jobs:

    - build - validate_factory - staging_build: filters: branches: only: - /staging-.*/ 元のジョブ 元のジョブからキックされていたジョブを 並べて、stepsからジョブをキックしてい るrun定義を削除するだけ この状態から、分けると効率が上がりそうな
 ステップの塊を少しずつ分離していくとよさそう
  22. ▶ ジョブを増やしていくと定 義内容の重複が増えてくる ▶ デフォルト値として定義し ておいて使い回す YAMLのアンカーとエイリアスの利⽤ generate_yard_documents: docker: -

    <<: *rails_docker_container working_directory: *working_directory_default steps: # Git - run: *configure_github_authentication - run: *checkout_repository - run: *configure_git # Bundler - run: *generate_os_version_file - run: *generate_ruby_version_file - restore_cache: *restore_bundler_cache - run: *bundle_install ... defaults: # Dockerコンテナ docker_containers: # Rails - &rails_docker_container image: quay.io/crowdworks/xxxxxx auth: ...
  23. あれ…どこかで⾒たような

  24. ▶ commands ▶ runステップをパラメーター差し替え可能な状態で定義できる ▶ https://github.com/CircleCI-Public/config-preview-sdk/blob/master/ docs/commands.md CircleCI 2.1: Orb

    structure commands: sayhello: description: "A very simple command for demonstration purposes" parameters: to: type: string default: "Hello World" steps: - run: echo << parameters.to >> jobs: myjob: docker: - image: "circleci/node:9.6.1" steps: - sayhello: to: "Lev"
  25. ▶ jobs ▶ jobをパラメーター差し替え可能な状態で定義できる ▶ https://github.com/CircleCI-Public/config-preview-sdk/blob/master/ docs/jobs.md CircleCI 2.1: Orb

    structure jobs: sayhello: parameters: saywhat: description: "To whom shall we say hello?" default: "World" type: string machine: true steps: - run: echo "Hello << parameters.saywhat >>" workflows: build: jobs: - sayhello: saywhat: Everyone
  26. ▶ executors ▶ Dockerイメージや環境変数などを埋め込み済みのexecutorを定義できる ▶ https://github.com/CircleCI-Public/config-preview-sdk/blob/master/ docs/executors.md CircleCI 2.1: Orb

    structure executors: lein_exec: docker: - image: clojure:lein-2.8.1 working_directory: ~/project environment: MYSPECIALVAR: "my-special-value" MYOTHERVAR: "my-other-value" jobs: build: executor: lein_exec steps: - checkout - run: echo "hello world" test: executor: lein_exec environment: TESTS: unit steps: - checkout - run: echo "how are ya?"
  27. CircleCI 2.1: Orb structure generate_yard_documents: docker: - <<: *rails_docker_container working_directory:

    *working_directory_default steps: # Git - run: *configure_github_authentication - run: *checkout_repository - run: *configure_git # Bundler - run: *generate_os_version_file - run: *generate_ruby_version_file - restore_cache: *restore_bundler_cache - run: *bundle_install ... executor化できる 意味のある単位の塊でjob化 command化できる
  28. ▶ 現在preview版 ▶ https://github.com/CircleCI-Public/config-preview-sdk ▶ プロジェクトごとにAdvanced SettingsのEnable build processingから有効化 CircleCI

    2.1: Orb structure
  29. CrowdWorksにおける Siderの活⽤⽅法

  30. Sider ▶ Siderが有効になっているリポジトリ数: 18 ▶ 基本的に各リポジトリの⾔語の主要Linterを有効にしてい る

  31. 有効にしているルール ▶ Ruby ▶ RuboCop ▶ Brakeman ▶ Reek ▶

    Querly ▶ JavaScript ▶ ESLint ▶ Other ▶ Misspell
  32. RuboCop ▶ MeowCop + Gryでいい感じにしてからカスタマイズ ▶ MeowCop ▶ https://github.com/sideci/meowcop ▶

    スタイル以外のバグやパフォーマンスに関する指摘のみのルールセット ▶ 使い⽅ ▶ Gemfileにrubocopに加えてmeowcopを追加 ▶ mewocop initで.rubocop.ymlを⽣成
 or
 既存.rubocop.ymlの先頭に
 inherit_gemの定義を追加 # To use the MeowCop gem. inherit_gem: meowcop: - config/rubocop.yml gem 'rubocop', require: false gem 'meowcop', require: false
  33. RuboCop ▶ Gry ▶ https://github.com/pocke/gry ▶ 現⾏コードからスタイルのルールを⾃動⽣成 ▶ 使い⽅ ▶

    gem install gryでインストール ▶ gryコマンドの出⼒を
 .rubocop.ymlに追記 ▶ gry >> .rubocop.yml #==== Gry Generated ==== # EnforcedStyle: empty => 7 offenses # EnforcedStyle: nil => 31 offenses # EnforcedStyle: both => 38 offenses Style/EmptyElse: EnforcedStyle: empty Enabled: true
  34. Querly ▶ https://github.com/soutaro/querly ▶ ルールで指定したRubyのメソッド呼び出しを警告 ▶ ローカルルールを定義したいときにRuboCopプラグインを がんばって作らなくて済む

  35. Querly - id: jp.crowdworks.oj pattern: - JSON.load - JSON.dump message:

    | `Oj` を使ってください。 (`JSON.load` -> `Oj.load` / `JSON.dump` -> `Oj.dump`) Specの場合は `json_spec` を使ってください。 ローカルルール(抜粋) - id: jp.crowdworks.active_record.update_attributes pattern: "update_attributes(...)" message: | `update_attributes` はバリデーションをスキップする `update_attribute` と紛らわしいた め `update` に統⼀しましょう。 `update_attributes` は `update` のエイリアスです。
  36. Querly - id: jp.crowdworks.redirect_to.and.return pattern: "redirect_to(_) [conditional]" message: | `redirect_to()`

    に続けて `and return` するのはやめましょう。 `redirect_to` が真で評価される値を返す実装に依存しているためです。 また、⾏が⻑いときに、右端の `and return` を⾒落とす可能性もあります。 ローカルルール(抜粋)
  37. Querly - id: jp.crowdworks.metaprogramming_abuse pattern: - classify - constantize -

    eval - instance_values - safe_constantize message: | フレームワーク等ではないアプリケーションコードでメタプログラミングが必要になることはありません。 本当に、本当に、メタプログラミングが必要か、3回考えてから使うのをやめましょう。 ローカルルール(抜粋)
  38. Querly - id: jp.crowdworks.controllers.before_filter pattern: "before_filter(...)" message: | `before_filter` はRails5.1で廃⽌されます。

    `before_action` を使ってください。 Deprecatedな機能 - id: jp.crowdworks.active_record.attr_accessible pattern: - "attr_accessible(...)" - "attr_protected(...)" message: | protected_attributes gemはRails5.0で廃⽌されます。 StrongParametersで対応してください。 http://morizyun.github.io/ruby/rails-controller-strong-parameters.html
  39. Goodcheck ▶ Ruby以外でもRubyコード内でもカジュアルに正規表現で チェックしたいときはGoodcheck ▶ 要求されるGemの依存・Rubyバージョンが合わなかったため 導⼊⾒送っていたが… ▶ ルールファイルさえあればSiderがチェック実⾏してくれる ▶

    ローカルでの確認はDockerイメージにすれば…! ▶ ⽤意されている…! ▶ https://github.com/sider/goodcheck#docker-image
  40. Misspell ▶ https://github.com/client9/misspell ▶ Go製のスペルチェックツール ▶ かなり⾼速 ▶ おもむろにリポジトリ丸ごとチェックに掛けてみたとこ ろ、明らかなスペルミスしか出てこなかったので、有効に

    しておいて損はない
  41. まとめ ▶ Shallow Cloneによるリポジト リのチェックアウト ▶ キャッシュ戦略 ▶ Dockerイメージのビルド⽅法 ▶

    Performance Pricing Plan ▶ Workflow ▶ YAMLのアンカー&エイリアス ▶ RuboCop • MeowCop + Gry ▶ Querly • ローカルルール • Deprecatedな機能 ▶ Goodcheck ▶ Misspell
  42. Thanks