Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
How to use CircleCI and Sider in CrowdWorks
Search
Hideki Igarashi
September 13, 2018
Programming
1
890
How to use CircleCI and Sider in CrowdWorks
CircleCI/Sider合同ミートアップ@プレイド 新GINZA SIXオフィス
https://connpass.com/event/98494/
Hideki Igarashi
September 13, 2018
Tweet
Share
More Decks by Hideki Igarashi
See All by Hideki Igarashi
AWSマルチアカウント管理 / ODC2021 Online
hideki
0
4k
な…何を言っているのかわからねーと思うが、コードを書いていたと思ったらレビューが終わっていた / Code Review Meetup 3
hideki
1
290
CrowdWorks Engineering Culture
hideki
0
410
CrowdWorksのChatOpsの歴史 / ChatOps History of CrowdWorks
hideki
1
1k
Bring out the ability of CircleCI 2.0
hideki
1
660
Grails with Spock
hideki
0
1.3k
JavaOne Report for G* 2012 San Francisco
hideki
2
1.2k
Other Decks in Programming
See All in Programming
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
3
510
Haze - Real time background blurring
chrisbanes
1
520
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
190
これでLambdaが不要に?!Step FunctionsのJSONata対応について
iwatatomoya
2
3.7k
なまけものオバケたち -PHP 8.4 に入った新機能の紹介-
tanakahisateru
1
120
PHPUnitしか使ってこなかった 一般PHPerがPestに乗り換えた実録
mashirou1234
0
230
コンテナをたくさん詰め込んだシステムとランタイムの変化
makihiro
1
140
useSyncExternalStoreを使いまくる
ssssota
6
1.2k
ドメインイベント増えすぎ問題
h0r15h0
2
360
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
4
290
From Translations to Multi Dimension Entities
alexanderschranz
2
140
【re:Growth 2024】 Aurora DSQL をちゃんと話します!
maroon1st
0
780
Featured
See All Featured
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
The Cult of Friendly URLs
andyhume
78
6.1k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
44
9.3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Speed Design
sergeychernyshev
25
670
Designing for humans not robots
tammielis
250
25k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
Thoughts on Productivity
jonyablonski
67
4.4k
We Have a Design System, Now What?
morganepeng
51
7.3k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
Building Your Own Lightsaber
phodgson
103
6.1k
Producing Creativity
orderedlist
PRO
341
39k
Transcript
How to use in CrowdWorks CircleCI and Sider $JSDMF$*4JEFS߹ಉϛʔτΞοϓ!ϓϨΠυ৽(*/;"4*9ΦϑΟε
About me twitter.com/ganta0087 github.com/ganta Hideki Igarashi Engineer
クラウドソーシングサービス クラウドソーシング = Crowd (群衆) + Sourcing (外注) 2012年3⽉サービス開始〜 会員数215万⼈
インターネットを活⽤することで、世界中の企業と個⼈が 直接つながり、仕事の受発注を⾏うことができる
CrowdWorksのリポジトリ ▶ ⾔語・フレームワーク ▶ Ruby (Rails / Gem) ▶ Go
▶ JavaScript (Node.js / Hubot) ▶ Swift (iOS) / Java (Android) ▶ Elixir
本⽇はRails成分多め Rails
CrowdWorksにおける CircleCI Sider の活⽤⽅法
CrowdWorksにおける CircleCIの活⽤⽅法
▶ .circleci/config.ymlがあるリポジトリ数: 56 ▶ ⽤途 ▶ テスト / ビルド ▶
Dockerイメージ作成 ▶ ドキュメント⽣成 CircleCI
すべてCircleCI 2.0に移⾏完了
▶ リポジトリのサイズ: 約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
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
▶ 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 }}-
▶ キャッシュに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
▶ また、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" }}
▶ イメージのRegistryはQuay or Amazon ECR ▶ Quayの⾃動ビルドは柔軟性がない ▶ ⾃前でCircleCIを使ってビルド&プッシュ Dockerイメージのビルド
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⼊りの イメージを使う。 バージョンを揃えておく。
▶ ジョブが⾛るビルドイメージ側の話 ▶ ⾃前イメージはlatestタグが付いているその時点のイメージの SHA256を使っていたが、タグが差し替わったり消えたりする とSHA256の参照も消えてしまってCIが回せなくなった ▶ <image name>@sha256:XXXXXXXXXX ▶
何よりも中⾝がいつのものかわかりづらい ▶ 元のミドルウェアのバージョン+Dockerfileのコミットハッ シュにするとわかりやすい ▶ 例: quay.io/crowdworks/elasticsearch:5.6.10-11ead2b ⾃前Dockerイメージのバージョン固定⽅法
▶ 同時実⾏可能なノード数の制約がなくなるため、ビルド待ちが なくなる ▶ pushしたら常に即ビルド開始 ▶ 以前は定期的にAPIを叩いて ビルド待ち時間をDatadogに ⾶ばし、⻑くなってきたら Slackに通知してコンテナを
買い⾜したり戻したりしていた (温かみのある⼿作業) Performance Pricing plan
▶ コンテナのリソース設定ができるようになる ▶ https://circleci.com/docs/2.0/configuration-reference/ #resource_class ▶ モノリシックなRailsアプリケーションはメモリを⾷う… Performance Pricing plan
▶ まだ単純に切り替えただけ ▶ 元々ジョブの先頭でキックしていた別のジョブを分離 Workflow workflows: version: 2 build: jobs:
- build - validate_factory - staging_build: filters: branches: only: - /staging-.*/ 元のジョブ 元のジョブからキックされていたジョブを 並べて、stepsからジョブをキックしてい るrun定義を削除するだけ この状態から、分けると効率が上がりそうな ステップの塊を少しずつ分離していくとよさそう
▶ ジョブを増やしていくと定 義内容の重複が増えてくる ▶ デフォルト値として定義し ておいて使い回す 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: ...
あれ…どこかで⾒たような
▶ 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"
▶ 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
▶ 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?"
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化できる
▶ 現在preview版 ▶ https://github.com/CircleCI-Public/config-preview-sdk ▶ プロジェクトごとにAdvanced SettingsのEnable build processingから有効化 CircleCI
2.1: Orb structure
CrowdWorksにおける Siderの活⽤⽅法
Sider ▶ Siderが有効になっているリポジトリ数: 18 ▶ 基本的に各リポジトリの⾔語の主要Linterを有効にしてい る
有効にしているルール ▶ Ruby ▶ RuboCop ▶ Brakeman ▶ Reek ▶
Querly ▶ JavaScript ▶ ESLint ▶ Other ▶ Misspell
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
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
Querly ▶ https://github.com/soutaro/querly ▶ ルールで指定したRubyのメソッド呼び出しを警告 ▶ ローカルルールを定義したいときにRuboCopプラグインを がんばって作らなくて済む
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` のエイリアスです。
Querly - id: jp.crowdworks.redirect_to.and.return pattern: "redirect_to(_) [conditional]" message: | `redirect_to()`
に続けて `and return` するのはやめましょう。 `redirect_to` が真で評価される値を返す実装に依存しているためです。 また、⾏が⻑いときに、右端の `and return` を⾒落とす可能性もあります。 ローカルルール(抜粋)
Querly - id: jp.crowdworks.metaprogramming_abuse pattern: - classify - constantize -
eval - instance_values - safe_constantize message: | フレームワーク等ではないアプリケーションコードでメタプログラミングが必要になることはありません。 本当に、本当に、メタプログラミングが必要か、3回考えてから使うのをやめましょう。 ローカルルール(抜粋)
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
Goodcheck ▶ Ruby以外でもRubyコード内でもカジュアルに正規表現で チェックしたいときはGoodcheck ▶ 要求されるGemの依存・Rubyバージョンが合わなかったため 導⼊⾒送っていたが… ▶ ルールファイルさえあればSiderがチェック実⾏してくれる ▶
ローカルでの確認はDockerイメージにすれば…! ▶ ⽤意されている…! ▶ https://github.com/sider/goodcheck#docker-image
Misspell ▶ https://github.com/client9/misspell ▶ Go製のスペルチェックツール ▶ かなり⾼速 ▶ おもむろにリポジトリ丸ごとチェックに掛けてみたとこ ろ、明らかなスペルミスしか出てこなかったので、有効に
しておいて損はない
まとめ ▶ Shallow Cloneによるリポジト リのチェックアウト ▶ キャッシュ戦略 ▶ Dockerイメージのビルド⽅法 ▶
Performance Pricing Plan ▶ Workflow ▶ YAMLのアンカー&エイリアス ▶ RuboCop • MeowCop + Gry ▶ Querly • ローカルルール • Deprecatedな機能 ▶ Goodcheck ▶ Misspell
Thanks