令和時代のRails運用

 令和時代のRails運用

A5e5ee2fb9e4ce3c728ed9e3ef6e916f?s=128

Tomohiro Hashidate

May 13, 2020
Tweet

Transcript

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

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

  3. から来ました。

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

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

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

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

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

  9. 中世: chef, ansible 等の構成管理ツール DSL によるサーバの⾃動構成を⾏うツールを利⽤する。 構築後の変更もコードによって管理できる。 適⽤後の状態を安定に保つために、コードを羃等にする必要がある。 ( 何度適⽤しても同じ結果になる様にする)

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

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

    ゴールデンイメージより遥かにフィードバックのサイクルが早く、アプリケーション と⼀体で扱える。
  12. Rails のDocker イメージ作成 1 buildkit を使ったモダンなRails アプリケーションイメージの構成⽅法を紹介する。 # syntax =

    docker/dockerfile:experimental 後述するマウントキャッシュの活⽤のため冒頭に記述しておく
  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
  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
  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"]
  16. コンテナ化した時の設定値の扱いについて イメージ管理を簡単にするためには設定値をイメージに含めたくはない。 環境毎の差異は外部から注⼊するとイメージが⼀つで済む。

  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" %>
  18. 環境変数の限界 秘匿情報をどこで管理するのかの問題は無くならない。 参照権限の管理も必要になる。

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

  20. S3 にKMS で暗号化した設定ファイルを配置する aws s3 cp --sse aws:kms --sse-kms-id <key-arn>

    configs/secretdata.yml s3://myapp-configs/secretdata.yml
  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
  22. Parameter Store の活⽤ AWS ならKMS と連携したParameter Store やSecure Manager が利⽤できます。

    ⾃分は起動時にAPI を叩いて環境変数に設定するラッパーツールを書いたりしました。 https://github.com/joker1007/prmstore-exec
  23. ログ出⼒とエラー管理 コンテナを活⽤する様になると基本的にサーバにログインしたりローカルストレージ を利⽤することは⾮推奨になります。 コンテナが状態を持つとDisposable では無くなります。 なので、ログ出⼒をどこに出すか考える必要があります。

  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 を有効にしないと、バッファリングされてログが⼀定量溜まらないと出⼒されない
  25. 最終出⼒先 cloudwatch logs 等のログ管理サービスを利⽤するのが現代的。 Kibana を活⽤するためにElasticSearch に転送することもある。 弊社ではfluentd のログドライバを使ってfluentd の集約サーバに転送し、そこからS3

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

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

    のプラグインを⾃作してデプロイとイメー ジビルドをcap コマンドに統合した。 https://github.com/reproio/capistrano-dockerbuild https://github.com/reproio/ecs_deploy
  28. 運⽤コマンド実⾏ 利⽤しているオーケストレーションサービスに依って詳細は異なるが、API を叩いて特 定のコンテナイメージにコマンド引数を渡し起動することは⼤抵可能である。 弊社の例だと、ECS を利⽤しているのでタスク定義の更新、API リクエスト、ログ出⼒ のpolling 、結果の取得までを⾃動でやってくれるgem を作って運⽤している。

    https://github.com/reproio/wrapbox AWS だとFargte を利⽤することで、必要になった時だけリソースを確保してコマンド 実⾏が可能になった。 現在はバッチ処理の実⾏等で活⽤している。
  29. テストの並列実⾏ コンテナ化の恩恵としてテストを並列実⾏することが容易になった。 先に紹介したgem の様な任意のコマンドをオーケストレーションクラスタで実⾏する ツールがあれば、引数をコントロールするだけで任意の並列数でテストが実⾏可能に なる。 テスト実⾏の単位ごとにRDB を分けるのも容易い。 弊社ではFargate Spot

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