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/

Hideki Igarashi

September 13, 2018
Tweet

More Decks by Hideki Igarashi

Other Decks in Programming

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. CrowdWorksのリポジトリ
    ▶ ⾔語・フレームワーク
    ▶ Ruby (Rails / Gem)
    ▶ Go
    ▶ JavaScript (Node.js / Hubot)
    ▶ Swift (iOS) / Java (Android)
    ▶ Elixir

    View full-size slide

  6. 本⽇はRails成分多め
    Rails

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. ▶ .circleci/config.ymlがあるリポジトリ数: 56
    ▶ ⽤途
    ▶ テスト / ビルド
    ▶ Dockerイメージ作成
    ▶ ドキュメント⽣成
    CircleCI

    View full-size slide

  10. すべてCircleCI 2.0に移⾏完了

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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 }}-

    View full-size slide

  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

    View full-size slide

  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" }}

    View full-size slide

  16. ▶ イメージのRegistryはQuay or Amazon ECR
    ▶ Quayの⾃動ビルドは柔軟性がない
    ▶ ⾃前でCircleCIを使ってビルド&プッシュ
    Dockerイメージのビルド

    View full-size slide

  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⼊りの
    イメージを使う。
    バージョンを揃えておく。

    View full-size slide

  18. ▶ ジョブが⾛るビルドイメージ側の話
    ▶ ⾃前イメージはlatestタグが付いているその時点のイメージの
    SHA256を使っていたが、タグが差し替わったり消えたりする
    とSHA256の参照も消えてしまってCIが回せなくなった
    ▶ @sha256:XXXXXXXXXX
    ▶ 何よりも中⾝がいつのものかわかりづらい
    ▶ 元のミドルウェアのバージョン+Dockerfileのコミットハッ
    シュにするとわかりやすい
    ▶ 例: quay.io/crowdworks/elasticsearch:5.6.10-11ead2b
    ⾃前Dockerイメージのバージョン固定⽅法

    View full-size slide

  19. ▶ 同時実⾏可能なノード数の制約がなくなるため、ビルド待ちが
    なくなる
    ▶ pushしたら常に即ビルド開始
    ▶ 以前は定期的にAPIを叩いて

    ビルド待ち時間をDatadogに

    ⾶ばし、⻑くなってきたら

    Slackに通知してコンテナを

    買い⾜したり戻したりしていた

    (温かみのある⼿作業)
    Performance Pricing plan

    View full-size slide

  20. ▶ コンテナのリソース設定ができるようになる
    ▶ https://circleci.com/docs/2.0/configuration-reference/
    #resource_class
    ▶ モノリシックなRailsアプリケーションはメモリを⾷う…
    Performance Pricing plan

    View full-size slide

  21. ▶ まだ単純に切り替えただけ
    ▶ 元々ジョブの先頭でキックしていた別のジョブを分離
    Workflow
    workflows:
    version: 2
    build:
    jobs:
    - build
    - validate_factory
    - staging_build:
    filters:
    branches:
    only:
    - /staging-.*/
    元のジョブ
    元のジョブからキックされていたジョブを
    並べて、stepsからジョブをキックしてい
    るrun定義を削除するだけ
    この状態から、分けると効率が上がりそうな

    ステップの塊を少しずつ分離していくとよさそう

    View full-size slide

  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:
    ...

    View full-size slide

  23. あれ…どこかで⾒たような

    View full-size slide

  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"

    View full-size slide

  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

    View full-size slide

  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?"

    View full-size slide

  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化できる

    View full-size slide

  28. ▶ 現在preview版
    ▶ https://github.com/CircleCI-Public/config-preview-sdk
    ▶ プロジェクトごとにAdvanced SettingsのEnable build
    processingから有効化
    CircleCI 2.1: Orb structure

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. 有効にしているルール
    ▶ Ruby
    ▶ RuboCop
    ▶ Brakeman
    ▶ Reek
    ▶ Querly
    ▶ JavaScript
    ▶ ESLint
    ▶ Other
    ▶ Misspell

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  34. Querly
    ▶ https://github.com/soutaro/querly
    ▶ ルールで指定したRubyのメソッド呼び出しを警告
    ▶ ローカルルールを定義したいときにRuboCopプラグインを
    がんばって作らなくて済む

    View full-size slide

  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` のエイリアスです。

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  39. Goodcheck
    ▶ Ruby以外でもRubyコード内でもカジュアルに正規表現で
    チェックしたいときはGoodcheck
    ▶ 要求されるGemの依存・Rubyバージョンが合わなかったため
    導⼊⾒送っていたが…
    ▶ ルールファイルさえあればSiderがチェック実⾏してくれる
    ▶ ローカルでの確認はDockerイメージにすれば…!
    ▶ ⽤意されている…!
    ▶ https://github.com/sider/goodcheck#docker-image

    View full-size slide

  40. Misspell
    ▶ https://github.com/client9/misspell
    ▶ Go製のスペルチェックツール
    ▶ かなり⾼速
    ▶ おもむろにリポジトリ丸ごとチェックに掛けてみたとこ
    ろ、明らかなスペルミスしか出てこなかったので、有効に
    しておいて損はない

    View full-size slide

  41. まとめ
    ▶ Shallow Cloneによるリポジト
    リのチェックアウト
    ▶ キャッシュ戦略
    ▶ Dockerイメージのビルド⽅法
    ▶ Performance Pricing Plan
    ▶ Workflow
    ▶ YAMLのアンカー&エイリアス
    ▶ RuboCop
    • MeowCop + Gry
    ▶ Querly
    • ローカルルール
    • Deprecatedな機能
    ▶ Goodcheck
    ▶ Misspell

    View full-size slide