$30 off During Our Annual Pro Sale. View Details »

令和時代のRails運用

 令和時代のRails運用

Tomohiro Hashidate

May 13, 2020
Tweet

More Decks by Tomohiro Hashidate

Other Decks in Programming

Transcript

  1. 令和時代のRails
    運⽤
    @joker1007

    View Slide

  2. self.inspect
    @joker1007
    Repro inc. CTO
    最近は専らKafka
    を触っており、実は余りRails
    を触っていない。
    という訳でインフラ寄りの話をします。

    View Slide

  3. から来ました。

    View Slide

  4. コンテナが⼀般化した現代のRails
    運⽤の話
    弊社は3
    年以上前からproduction
    でのコンテナ運⽤を採⽤している。

    View Slide

  5. 話すこと
    コンテナに⾄るまでの歴史
    Rails
    のDocker
    イメージ作成 2020
    年版
    コンテナ化した時のベストプラクティス
    弊社で作ったgem
    の紹介
    話さないこと
    コンテナとは何か
    k8s
    関連

    View Slide

  6. はじめに:
    インフラ管理の歴史を振り返る
    何故コンテナが使われているのか

    View Slide

  7. 太古:
    ⼿順書
    暖かみのある⼿作業での構築。
    ⼿順書に書かれていないことを実⾏すると怒られる。
    流⽯にRails
    の現場では⾒なかった。

    View Slide

  8. 古代:
    シェルスクリプト
    ⼿順書をスクリプトにまとめたもの。
    メンテされている内は良いが、現状と乖離すると⾯倒なことになる。
    既に構築済みのサーバを変更するには使えない。
    ⼿作業による変更を反映させて後の作業に利⽤するぐらい。

    View Slide

  9. 中世: chef, ansible
    等の構成管理ツール
    DSL
    によるサーバの⾃動構成を⾏うツールを利⽤する。
    構築後の変更もコードによって管理できる。
    適⽤後の状態を安定に保つために、コードを羃等にする必要がある。
    (
    何度適⽤しても同じ結果になる様にする)
    Infrastracture as Code
    の始まり。
    しかし、羃等なコードを保つのがかなり難しい。
    また、未知の状況から設定を作り込む負荷が⾼め。

    View Slide

  10. 近代:
    ゴールデンイメージ
    クラウド環境が⼀般化し、インスタンスイメージとインスタンスを必要に応じて作り
    直すことが可能になった。
    packer
    等のツールを使うことでイメージ構築を簡易化し常に0
    から作り直すことで、羃
    等性を意識しなくて良くなる。
    インスタンスを容易に破棄出来る様になった。
    Disposable Infrastracture
    の始まり。

    View Slide

  11. 現代:
    コンテナ
    アプリケーションコードとミドルウェア等のサーバ構成のためのコンポーネントを丸
    ごとパッケージ化する。
    VM
    より⼩さいオーバーヘッドで、いくつもアプリケーションを独⽴させて動かせる様
    になり、リソース効率が上昇。
    アプリケーションに必要なインフラだけを管理すれば良くなり、⼿元の環境で
    production
    とほぼ同等の環境が再現可能に。
    ゴールデンイメージより遥かにフィードバックのサイクルが早く、アプリケーション
    と⼀体で扱える。

    View Slide

  12. Rails
    のDocker
    イメージ作成 1
    buildkit
    を使ったモダンなRails
    アプリケーションイメージの構成⽅法を紹介する。
    # syntax = docker/dockerfile:experimental
    後述するマウントキャッシュの活⽤のため冒頭に記述しておく

    View Slide

  13. Rails
    のDocker
    イメージ作成 2
    余計なレイヤーキャッシュ削除の⼯夫をしなくて済む様にnodejs
    はmulti stage
    ビルドで
    ⼊れる
    # Node.js
    ダウンロード⽤ビルドステージ
    FROM ruby:2.6.5 AS nodejs
    WORKDIR /tmp
    # Node.js
    のダウンロード
    RUN curl -LO https://nodejs.org/dist/v12.14.1/node-v12.14.1-linux-x64.tar.xz
    RUN tar xvf node-v12.14.1-linux-x64.tar.xz
    RUN mv node-v12.14.1-linux-x64 node

    View Slide

  14. Rails
    のDocker
    イメージ作成 3
    FROM ruby:2.6.5
    # nodejs
    をインストールしたイメージからnode.js
    をコピーする
    COPY --from=nodejs /tmp/node /opt/node
    ENV PATH /opt/node/bin:$PATH
    #
    アプリケーション起動⽤のユーザーを追加
    RUN useradd -m -u 1000 rails
    RUN mkdir /app && chown rails /app
    USER rails
    # yarn
    のインストール
    RUN curl -o- -L https://yarnpkg.com/install.sh | bash
    ENV PATH /home/rails/.yarn/bin:/home/rails/.config/yarn/global/node_modules/.bin:$PATH
    # ruby-2.7.0
    でnew
    した場合を考慮
    RUN gem install bundler

    View Slide

  15. Rails
    のDocker
    イメージ作成 4
    WORKDIR /app
    # Docker
    のビルドステップキャッシュを利⽤するため
    #
    先にGemfile
    を転送し、bundle install
    する
    COPY --chown=rails Gemfile Gemfile.lock package.json yarn.lock /app/
    RUN bundle config set app_config .bundle
    RUN bundle config set path .cache/bundle
    # mount cache
    を利⽤する
    RUN --mount=type=cache,uid=1000,target=/app/.cache/bundle bundle install && \
    mkdir -p vendor && \
    cp -ar .cache/bundle vendor/bundle
    RUN bundle config set path vendor/bundle
    RUN --mount=type=cache,uid=1000,target=/app/.cache/node_modules bin/yarn install --modules-folder .cache/node_modules && \
    cp -ar .cache/node_modules node_modules
    COPY --chown=rails . /app
    RUN --mount=type=cache,uid=1000,target=/app/tmp/cache bin/rails assets:precompile
    #
    実⾏時にコマンド指定が無い場合に実⾏されるコマンド
    CMD ["bin/rails", "s", "-b", "0.0.0.0"]

    View Slide

  16. コンテナ化した時の設定値の扱いについて
    イメージ管理を簡単にするためには設定値をイメージに含めたくはない。
    環境毎の差異は外部から注⼊するとイメージが⼀つで済む。

    View Slide

  17. 基本:
    環境変数化
    # database.yml
    の例
    production: &default
    adapter: mysql2
    encoding: utf8mb4
    charset: utf8mb4
    collation: utf8mb4_bin
    pool: 5
    timeout: 5000
    username: <%= ENV["MYSQL_USERNAME"] || "app" %>
    password: <%= ENV["MYSQL_PASSWORD"] || "password" %>
    host: <%= ENV["MYSQL_HOST"] || "127.0.0.1" %>
    port: <%= ENV["MYSQL_PORT"] || "3306" %>

    View Slide

  18. 環境変数の限界
    秘匿情報をどこで管理するのかの問題は無くならない。
    参照権限の管理も必要になる。

    View Slide

  19. KeyManagementService(KMS)
    の利⽤
    AWS
    やGCP
    等のクラウド環境であればIAM
    と統合された暗号鍵管理の仕組みが利⽤で
    きる。
    アクセス権限がIAM
    で管理できるため、⾃分でマスターキー等を管理する仕組みが必
    要無い。

    View Slide

  20. S3
    にKMS
    で暗号化した設定ファイルを配置する
    aws s3 cp --sse aws:kms --sse-kms-id configs/secretdata.yml s3://myapp-configs/secretdata.yml

    View Slide

  21. 起動時に秘匿情報を取得するラッパー
    #!/bin/bash
    set -xe
    # AWS
    はファイルのメタデータとして暗号化情報を記録してあるため、何も指定せずに復号化しつつ取得できる
    #
    鍵に対するアクセス権限が無ければ、エラーになる
    aws s3 cp s3://myapp-configs/secretdata.yml configs/secretdata.yml
    # exec
    を経由してプロセスを丸ごとRails
    のものに置き換える
    #
    シェルの⼦プロセスとして起動してしまうとシグナルの管理が煩雑になる
    exec bin/rails s -b 0.0.0.0

    View Slide

  22. Parameter Store
    の活⽤
    AWS
    ならKMS
    と連携したParameter Store
    やSecure Manager
    が利⽤できます。
    ⾃分は起動時にAPI
    を叩いて環境変数に設定するラッパーツールを書いたりしました。
    https://github.com/joker1007/prmstore-exec

    View Slide

  23. ログ出⼒とエラー管理
    コンテナを活⽤する様になると基本的にサーバにログインしたりローカルストレージ
    を利⽤することは⾮推奨になります。
    コンテナが状態を持つとDisposable
    では無くなります。
    なので、ログ出⼒をどこに出すか考える必要があります。

    View Slide

  24. Logging Driver
    Docker
    のログドライバはコンテナアプリケーションの標準出⼒、標準エラー出⼒から
    ログを読み取ります。
    なので、Rails
    のログを標準出⼒に出せる様にしておく必要があります。
    # config/environments/production.rb
    #
    省略
    # Prepend all log lines with the following tags.
    # config.log_tags = [ :subdomain, :uuid ]
    config.logger = ActiveSupport::Logger.new($stdout)
    $stdout.sync = true # sync
    を有効にしないと、バッファリングされてログが⼀定量溜まらないと出⼒されない

    View Slide

  25. 最終出⼒先
    cloudwatch logs
    等のログ管理サービスを利⽤するのが現代的。
    Kibana
    を活⽤するためにElasticSearch
    に転送することもある。
    弊社ではfluentd
    のログドライバを使ってfluentd
    の集約サーバに転送し、そこからS3

    papertrail
    等に転送している。

    View Slide

  26. エラートラッキング
    エラートラッキングのためのツールは以前から活⽤されてきたが、最近は⾃前でホス
    トするより外部サービスに頼るケースが多い。
    sentry
    やrollbar
    等が流⾏っている印象がある。

    View Slide

  27. デプロイ
    コンテナとオーケストレーションサービスが⼀般化し、SSH
    でファイルを転送すると
    いう形式ではなくなった。
    イメージをリポジトリに登録しておき、デプロイはオーケストレーションのAPI
    を叩い
    たり、k8s
    の設定を変更するという形になった。
    弊社ではECS
    を利⽤しているのでcapistrano
    のプラグインを⾃作してデプロイとイメー
    ジビルドをcap
    コマンドに統合した。
    https://github.com/reproio/capistrano-dockerbuild
    https://github.com/reproio/ecs_deploy

    View Slide

  28. 運⽤コマンド実⾏
    利⽤しているオーケストレーションサービスに依って詳細は異なるが、API
    を叩いて特
    定のコンテナイメージにコマンド引数を渡し起動することは⼤抵可能である。
    弊社の例だと、ECS
    を利⽤しているのでタスク定義の更新、API
    リクエスト、ログ出⼒
    のpolling
    、結果の取得までを⾃動でやってくれるgem
    を作って運⽤している。
    https://github.com/reproio/wrapbox
    AWS
    だとFargte
    を利⽤することで、必要になった時だけリソースを確保してコマンド
    実⾏が可能になった。
    現在はバッチ処理の実⾏等で活⽤している。

    View Slide

  29. テストの並列実⾏
    コンテナ化の恩恵としてテストを並列実⾏することが容易になった。
    先に紹介したgem
    の様な任意のコマンドをオーケストレーションクラスタで実⾏する
    ツールがあれば、引数をコントロールするだけで任意の並列数でテストが実⾏可能に
    なる。
    テスト実⾏の単位ごとにRDB
    を分けるのも容易い。
    弊社ではFargate Spot
    を使って32
    並列でテストを実⾏している。

    View Slide

  30. 最後に宣伝
    今⽇話した様な内容も含んだRails
    本、パーフェクトRails
    の第⼆版が著者陣により執筆
    中です。
    まだ発売⽇は未定ですが、近⽇発売できると良いなあという状況です。
    発売されたらよろしくお願いします。

    View Slide