Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: 開発環境をVS CodeのRemote Containersで立ち上げるMEMO

既存もDockerで開発環境を作っていたのですが、VS CodeのRemote Containersを使うとディレクトリを開いた時にサジェストしてくれたり、拡張とかもデフォルトでインストールしてくれたりと何かと便利だったのでメモ🗒

VS CodeのRemote Containersとは?

The Visual Studio Code Remote - Containers extension lets you use a Docker container as a full-featured development environment. Create a development container using Visual Studio Code Remote Development

Dockerコンテナを直接開発環境にできる拡張機能です。環境を用意しておくと以下のような感じで開いた時にサジェストしてくれます。

f:id:madogiwa0124:20220130171421p:plain

詳しい使い方とかは以下の公式のチュートリアル等を参照してください。

code.visualstudio.com

既存のRuby on RailsのDocker環境を使ってRemote Containers用の環境を用意する

既存のDocker環境

以下のようなRails用のDocker環境を使ってRemote Containers用の環境を用意します。

FROM ruby:3.1.0

WORKDIR /app

# Using Node.js v16.x(LTS)
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -

# Add packages
RUN apt-get update && apt-get install -y \
    git \
    nodejs \
    vim \
    chromium \
    chromium-driver

# Add yarnpkg for assets:precompile
RUN npm install -g yarn
version: "3"
services:
  db:
    image: postgres:13.5
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - db:/var/lib/postgresql/data
  redis:
    image: redis:6.2-alpine
  rails: &rails
    build:
      context: .
    tty: true
    ports:
      - "3000:3000"
    links:
      - db
      - redis
    tmpfs:
      - /tmp
    volumes:
      - ../:/app:cached
      - node_modules:/app/node_modules
      - bundle:/app/vendor/bundle
      - log:/app/log
      - packs:/app/public/packs
      - packs-test:/app/public/packs-test
      - rails-cache:/app/tmp/cache
    working_dir: /app
    user: root
    environment:
      HOST_NAME: rails
      DATABASE_URL: postgres://postgres:password@db:5432
      REDIS_URL: redis://redis:6379/0
      BUNDLE_PATH: /app/vendor/bundle
      RAILS_ENV: development
      NODE_ENV: development
      TZ: "Asia/Tokyo"
  sidekiq:
    <<: *rails
    command: ["bundle", "exec", "sidekiq"]
    ports: []
volumes:
  db:
  node_modules:
  bundle:
  log:
  packs:
  packs-test:
  rails-cache:

Remote Containers用の環境を用意する

と言っても特に大変な作業は必要なく、ルートディレクト.devcontainerディレクトリを作成し、以下の2つのファイルを作成します。

  • devcontainer.json : 参照するdocker-compose.ymlやインストールする拡張を設定
  • boot.sh : 起動時に実行するshell (起動後に自分でbin/setupを実行するなら無くてもいい)
{
  "name": "workspace",
  "dockerComposeFile": "../docker/docker-compose.yml",
  "service": "rails",
  "workspaceFolder": "/app",

  "extensions": [
    "editorconfig.editorconfig",
    "rebornix.ruby",
    "misogi.ruby-rubocop",
    "octref.vetur",
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
  ],

  "postCreateCommand": ".devcontainer/boot.sh",

  "remoteUser": "root"
}
# .devcontainer/boot.sh
#!/bin/sh

set -eux

bin/setup

devcontainer.jsonのリファレンスは以下を参照してください。

code.visualstudio.com

Tips

Remote Container上から認証が必要なGitHubリポジトリにpush/pull等する

ssh-add $HOME/.ssh/github_rsaで追加しとけば自動的にフォワーディングしてくれる。

Using SSH keys# There are some cases when you may be cloning your repository using SSH keys instead of a credential helper. To enable this scenario, the extension will automatically forward your local SSH agent if one is running. You can add your local SSH keys to the agent if it is running by using the ssh-add command. For example, run this from a terminal or PowerShell:

ssh-add $HOME/.ssh/github_rsa

code.visualstudio.com

終わりに

VS Code Remote Containers extension、気になってはいたもののあまり触れてなかったのですが用意しとくと開発環境構築とか自動化できて便利ですね。

また.devcontainerを整備しておくとGitHub CodeSpaceでも使えたりするかも(?)なので、そこも夢が広がりますね。

docs.github.com

参考

qiita.com

GitHub ActionをRubyとRailsのバージョンのマトリクスで実行するメモ

Gemとかを作るときにRailsのバージョンとサポートしているRubyのバージョンのメトリクスでGitHub ActionでCIを回すときのメモ📝

まず現時点(2022/01/22)のStableのRailsバージョンである7系をインストールするGemfileを用意します。

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

# Specify your gem's dependencies in aikotoba.gemspec.
gem "rails", "~> 7.0"

Railsは1つ前のメジャーバージョンまでセキュリティパッチのサポートするので6.1系をインストールするGemfileを用意する。このときdependencies.delete_ifを使ってRailsのみを削除して差し替えるようにします。

eval_gemfile File.expand_path("../Gemfile", __dir__)

dependencies.delete_if { |d| d.name == "rails" }
gem "rails", "~> 6.1"

3 セキュリティ問題
現在対象となっているシリーズ: 7.0.Z、6.1.Z。

Ruby on Rails のメンテナンスポリシー - Railsガイド

そして以下のようなGitHub Action用のyamlを用意します。

name: CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        ruby: ["2.7", "3.0", "3.1"]
        gemfile: ["Gemfile", "gemfiles/rails_6_1.gemfile"]
    env:
      BUNDLE_GEMFILE: ${{ matrix.gemfile }}
    steps:
      - uses: actions/checkout@v2
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
      - name: install dependencies
        run: bundle install --jobs 3 --retry 3
      - name: migration
        run: |
          bin/rails db:create RAILS_ENV=test
          bin/rails db:migrate RAILS_ENV=test
      - name: test
        run: bin/rails test

ポイントは以下のmatrixでrubyとgemfileを指定して、BUNDLE_GEMFILEmatrix.gemfileを指定することで動的に読み込むgemfileを変更しているところです。

    strategy:
      matrix:
        ruby: ["2.7", "3.0", "3.1"]
        gemfile: ["Gemfile", "gemfiles/rails_6_1.gemfile"]
    env:
      BUNDLE_GEMFILE: ${{ matrix.gemfile }}

gemfile (BUNDLE_GEMFILE): The name of the file that bundler should use as the Gemfile. This location of this file also sets the root of the project, which is used to resolve relative paths in the Gemfile, among other things. By default, bundler will search up from the current working directory until it finds a Gemfile. https://bundler.io/man/bundle-config.1.html#LIST-OF-AVAILABLE-KEYS

これで以下のような感じでRubyRailsのバージョンのマトリクスで実行することができます。

f:id:madogiwa0124:20220122224944p:plain

参考

sinsoku.hatenablog.com

sue445.hatenablog.com

Ruby: よりセキュアなArgon2でパスワードをハッシュ化するメモ

パスワードのハッシュ化といえば、RailsのActiveModel::SecurePasswordでもBcryptが使われているので今まで自分で作るときもBcryptを使っていたのですが、Bcryptには以下のような仕様があり、多少気になりArgon2を使ってみたので使い方とかをメモ📝

bcryptは、PHPのpassword_hash関数のデフォルトアルゴリズムである他、他の言語でも安全なハッシュ保存機能として広く利用されていますが、パスワードが最大72文字で切り詰められるという実装上の特性があり、その点が気になる人もいるようです(この制限はDoS脆弱性回避が目的です)。 bcryptの72文字制限をSHA-512ハッシュで回避する方式の注意点 | 徳丸浩の日記

Argon2とは?

Argon2 は 2015年の Password Hashing Competition で1位を獲得した比較的新しいハッシュ関数です。

  • GPU や専用のハードウェア(FPGA/ASIC) 攻撃に強い Argon2d
  • サイドチャンネル攻撃に強い Argon2i
  • Argon2d と Argon2i のハイブリッド型の Argon2id

OWASPに学ぶパスワードの安全なハッシュ化 | DevelopersIO

OWASAPでも基本的にはArgon2の使用が推奨されているようですね。

This cheat sheet provides guidance on the various areas that need to be considered related to storing passwords. In short

  • Use Argon2id with a minimum configuration of 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism.
  • If Argon2id is not available, use bcrypt with a work factor of 10 or more and with a password limit of 72 bytes.

Password Storage - OWASP Cheat Sheet Series

Argon2をRubyで使う

Argon2をRubyで使用できる以下のRuby Argon2 Gemがあるのでそれを利用してみます💎

github.com

hasher = Argon2::Password.new
Argon2::Password.create("password")
    => "$argon2i$v=19$m=65536,t=2,p=1$61qkSyYNbUgf3kZH3GtHRw$4CQff9AZ0lWd7uF24RKMzqEiGpzhte1Hp8SO7X8bAew"

Version 2.0 - Argon 2id Version 2.x upwards will now default to the Argon2id hash format. This is consistent with current recommendations regarding Argon2 usage. It remains capable of verifying existing hashes.

Version 2.0以降であれば Argon2id hash formatでハッシュ化できるようです。

Ruby Argon2 Gemではハッシュ化に関するコストまわりの設定を行えますが、デフォルトだと以下のような設定になるようです。

  • m_cost (使用メモリ) : 16 ※2のm_cost乗のKiB値が使用されるため65536KiB(64MiB)がデフォルトの使用メモリ量になるようです。
  • t_cost (反復回数) : 2
  • p_cost(並列処理数) : 1

ref: ruby-argon2/test.c at b89f08dfffaf160dffcda1f9163e2e3e31076c9a · technion/ruby-argon2 · GitHub

OWASAPの推奨設定がデフォルトは以下のようなので、デフォルトは対象コストを上げているようですね👀

Use Argon2id with a minimum configuration of 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism.

https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#introduction

OWASAPの値に設定するなら以下のような感じになりそうです。

  • m_cost (使用メモリ) : 14※16384KiB(16Mib)
  • t_cost (反復回数) : 2
  • p_cost(並列処理数) : 1

Argon2でパスワードのハッシュ化・検証を行う

Argon2でパスワードのハッシュ化・検証を行う以下のようなclassを作ってみました。 そこまでBcryptと使い勝手は変わらず良い感じですね✨

require "argon2"

class Password
  def initialize(
    value:,
    pepper: "default-papper"
  )
    @value = value
    @pepper = pepper
  end

  attr_reader :value

  def match?(digest:)
    verify_password?(password_with_pepper(value), digest)
  end

  def digest
    generate_hash(password_with_pepper(value))
  end

  private

  def verify_password?(password, digest)
    Argon2::Password.verify_password(password, digest)
  end

  def password_with_pepper(password)
    "#{password}-#{@pepper}"
  end

  def generate_hash(password)
    # NOTE: Adjusted to be OWASAP's recommended value by default.
    # > Use Argon2id with a minimum configuration of 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism.
    # > https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#introduction
    argon = Argon2::Password.new(t_cost: 2, m_cost: 14, p_cost: 1)
    argon.create(password)
  end
end

password = Password.new(value: "password")
# => #<Password:0x00000001097b2208 @pepper="default-papper", @value="password">
password.digest
# => "$argon2id$v=19$m=16384,t=2,p=1$HyAICViZtYIldgmsu3mICw$7wfMkSRMnpyLzal1rdQ1YdnwsncfYceGXp4Cn7gDSSA"
password.match?(digest: password.digest)
# => true
other_password = Password.new(value: "other_password")
# => #<Password:0x0000000109f1f9a0 @pepper="default-papper", @value="other_password">
password.match?(digest: other_password.digest)
# => false  

M1 MacBook Pro を買ってある程度Dockerまわりとかセットアップしたのでメモ

M1 MacBook Pro 14インチ買ったのでセットアップしたこととかメモ

www.apple.com

開発用のツールまわり

ターミナル

デフォルトのzshでテーマはpreztoを使って、powerlevel10kにした。

github.com

github.com

prezto使ったことなかったけど、結構すっと設定できて良かった。

qiita.com

Editor

Visual Studio Code

azure.microsoft.com

brew caskでinstall

brew install --cask visual-studio-code

テーマはOne Dark Proにした

marketplace.visualstudio.com

Git

mac標準ではなくbrewで入れ直す

brew install git

以下を実行して設定

git config --global user.name my_name
git config --global user.email my_email
git config --global core.editor "code --wait"

以下を参考に自動補完の設定も入れた

zsh で git コマンドの補完を有効にする · GitHub

Ruby

rbenvを入れて複数バージョンで運用できるようにする

github.com

brew install rbenv
rbenv init
rbenv install 3.1.0
rbenv global 3.1.0

eval "$(rbenv init - zsh)".zshrcにも追記

以下のgemはglobalに入れといた

gem install solargraph
gem install dip

Node.js

nodebrewを入れて複数バージョンで運用できるようにする

github.com

brew install nodebrew
mkdir -p ~/.nodebrew/src
nodebrew install stable
nodebrew use stable

yarnもglobalに入れておく

sudo npm install --global yarn 

Docker

brew caskでインストール

brew install --cask docker

アーキテクチャを考慮してinstallしてくれるっぽいのでcaskでinstallしても大丈夫そうだった。

github.com

個人のRails製のWebサービスで試してみたけど、対応が必要だったのは以下ぐらいで思ったよりは全然動く。

ActiveSupport::EventedFileUpdateCheckerを使わないようにした

github.com

Chromeが動かないのでFirefoxでSystem Specを実行するようにした

RUN sudo apt -y install firefox firefox-locale-ja firefox-geckodriver
Capybara.register_driver :haedless_firefox do |app|
  browser_options = ::Selenium::WebDriver::Firefox::Options.new
  browser_options.add_argument('--headless')
  Capybara::Selenium::Driver.new(
    app,
    browser: :firefox,
    options: browser_options
  )
end

RSpec.configure do |config|
  config.before(:each, type: :system) do |example|
    example.metadata[:js] ? driven_by(:headless_chrome) : driven_by(:rack_test)
    js_driver = ENV['CI'] ? :headless_chrome : :haedless_firefox
    example.metadata[:js] ? driven_by(js_driver) : driven_by(:rack_test)
  end
end

github.com

blog.savanna.io

でも思ったよりパフォーマンスは良くない。。。この辺は開発環境でarm対応してないImageを使っているからかも。

tech.repro.io

今まで開発環境でもcimg/rubyを使ってたけど、これがarmアーキテクチャに対応してなかったため、エミュレーションが発生してたっぽい。

hub.docker.com

なのでarmに対応しているrubyイメージを使うようにした。

しかし上述の通りarmイメージではchromeが動かないため妥協してchromiumを使うようにした。

割と快適になった。

おわりに

M1 Mac、Dockerまわりとかだいぶハマるのかなと思ってましたが、意外とそこまではまらずに今のところは動いてる。

2021年振り返り

今年も一年が終わるということで今年も振り返ってみる。

今年の振り返り

アウトプット

BLOG

BLOGは、今年1年で51記事書いていて、1週間に1記事ぐらい書いてるので、そこそこ書いてた✍ (月間PV数は4300弱くらい)

なぜか以下の記事が、ホットエントリーに取り上げられたりもした。

madogiwa0124.hatenablog.com

公開したツールとか

今思い返すとgemとかテンプレートとか今年も結構作って公開してた💎

Markdown形式のテキストをRSpecのコードに変換するGem

github.com

OK Computerのヘルスチェックをウェブで見るときに見やすくするGem

github.com

Rails newするときのテンプレート(Rails 7にはまだ対応出来てない)

github.com

HerokuでRailsを動かすときのTerraformのテンプレート

github.com

JavaScript / TypeScriptで色々ゲームとか作った

github.com

OSS活動

OSS活動としては、

rspec-railsのテンプレートのちょっとした修正したり、

github.com

Railsガイドの翻訳をちょっと直したり、

github.com

あとはPasswordlessというmagicklinkのGemのセキュリティFIXとか、

github.com

CIとかテストとか開発環境周りを整えたりしてました。

インプット

今年は、33冊読んでました📚

印象に残ってる本を載せておきます。

去年の目標と結果

目標 結果 メモ
CS系の本を6冊読む 4冊しか読んでなかった。
身近な課題を解決するなにかを作る 割とツールとか公開できてたので。
仕事以外の時間をちゃんと確保する 新規の案件とか色々あって割と業務時間は頑張って調整出来たけど微妙な感じだったので△
Ruby, JavaScript以外の言語を学ぶ TypeScriptを学んでたけど、言語かと言われると微妙な気もしたので△

今年の目標

目標 メモ
心身ともに健やか/穏やかに過ごす 精神的にも肉体的にも穏やかに健やかに過ごしたい。
技術的に一定自信を持てるような何かを見つける RubyとかRailsとか、何でもいいけど一定これだったらある程度でリードできるみたいなものを見つける
CS系の教材を5つぐらいこなす 一定時代に左右されない基盤となる知識を得たい。

おわりに

今年も引き続きコロナでリモートワークだったので業務外の時間を取りやすかったのはいいことだったが、業務的には割と新規の案件が多くて割と大変だったのかもしれない。

来年は、心身ともに健やか/穏やかに過ごしたい。

Ruby on Rails: 個人のサービスをRails7にアップグレードしたのでやったこととかメモ📝

2021/12/15 Rails 7がリリースされました🎉

rubyonrails.org

さっそく個人のサービスをRails 6.1.4.4 -> Rails 7にアップグレードしたのでやったこととかメモ📝

Rails 7の主要な対応

While most Rails applications won’t need a dependency on Node given these defaults, we’ve still managed to also dramatically improve the integration story for those who do in Rails 7.

import_mapによりnode依存を解消!

madogiwa0124.hatenablog.com

また以下の大きな新機能 ※ActiveRecordで属性の暗号化、SQLコメントで実行元をトレース、非同期のeagar_loading

  • At-Work Encryption With Active Record
  • Trace Query Origins With Marginalia-Style Tagging
  • Asynchronous Query Loading
  • Zeitwerk Exclusively

新しいブランドサイトもカッコいいですね👍

rubyonrails.org

引用元:https://rubyonrails.org/2021/12/15/Rails-7-fulfilling-a-vision

Rails 7へのアップグレード手順

Rails以外のgemのバージョンアップ

まだRails 7に対応してない可能性があるので、まずはRails以外のgemを最新に上げときます。

Railsのバージョンアップ

上記でrails以外のgemが最新になっているはずなのでbundle update railsでバージョンをあげます。

bundle update時にRails 7に対応してないgemが見つかった場合は、masterに向ける OR 対応のPRが出ていれば、そのbranchに向けたりすることも検討します。

Upgrade Guideを読む

edgeguides.rubyonrails.org

上記を読んで自身のサービスに影響がありそうなところを把握します。

自分のサービスだと以下の変更はキャッシュ及び暗号化された値の読み込みに影響がありそうでしたが、 今回のサービスではキャッシュは無くなってもいいのと暗号化された値も暗号化されたクッキーが読めず、 ログインセッションが切れる等が発生しても問題ないので一旦そのまま入れることにしました。

  • 3.10 Key generator digest class changing to use SHA256
  • 3.12 New ActiveSupport::Cache serialization format

リリースノートにも目を通しておきます。

edgeguides.rubyonrails.org

RailsDiffで設定ファイルまわりの更新を取り込む

RailsDiff is about what you'd have to change about your app's configuration when upgrading Rails versions, not about what Rails has changed internally. https://railsdiff.org/

バージョンごとの設定ファイルの差分を閲覧出来るRailsDiffというサービスを使って差分を確認しつつ、反映が必要そうな箇所を修正していきます。

https://railsdiff.org/6.1.4.4/7.0.0

bin/rails app:updateを使っても良いですが、オーバーライドの良し悪しとかの判断がCLIの対話形式だとやりにくいと感じたので上記方法を選択しています。

正常に動作することを確認する

最後に既存のテストコードが通ることや、実際に動かしてみて動作することを確認できればOKです🎉

アップグレード時に発生したエラーとか

missing require leading to uninitialized constant ActiveSupport::XmlMini::IsolatedExecutionState

テスト実行時にmissing require leading to uninitialized constant ActiveSupport::XmlMini::IsolatedExecutionStateが発生したため、 ActiveSupportをrequireするようにしました。

# config/application.rb

require 'active_support'

module MyApp
  class Application < Rails::Application

github.com

その他気づいたこと

redirect_toでopen redirectの検証がされるようになった

redirect_toでopen redirectの検証がデフォルトで入るようになったようです。

By default, Rails protects against redirecting to external hosts for your app's safety, so called open redirects. Note: this was a new default in Rails 7.0, after upgrading opt-in by uncommenting the line with raise_on_open_redirects in config/initializers/new_framework_defaults_7_0.rb https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to

従来どおりの挙動にする場合は引数allow_other_hostにtrueを渡す。

redirect_to "https://rubyonrails.org", allow_other_host: true

ActiveRecord::Core#strict_loading!が追加されてた

今までGlobalで設定されていたsrict_loadingを無効化したいケースのためにmasterから実装を持ってきてパッチを当ててたのですが、publicなメソッドとして追加されてました。

Sets the record to strict_loading mode. This will raise an error if the record tries to lazily load an association. Parameters:

  • value - Boolean specifying whether to enable or disable strict loading.
  • mode - Symbol specifying strict loading mode. Defaults to :all. Using

https://api.rubyonrails.org/classes/ActiveRecord/Core.html#method-i-strict_loading-21

modeも指定出来るようになっていて、念願のn_plus_one_onlyも指定出来るのですが、globalでn_plus_one_onlyに指定する方法が分からなかった。。。(strict_loading_modeはdefaultでallで、read_attributesになっていた。。。)

madogiwa0124.hatenablog.com

参考

inside.pixiv.blog

Ruby on Rails: 開発環境込みでcircleci/rubyからcimg/rubyに乗り換えるメモ

今までCircleCI及び開発環境でcircleci/rubynode-browserのイメージを利用していた*1のですが、下記ということでcimg/rubyに乗り換えることにしました。

プレフィックスが「 circleci / 」のレガシーイメージは、 2021 年 12 月 31 日に廃止されます。 ビルドを高速化するには、次世代の CircleCI イメージを使ってプロジェクトをアップグレードしてください。 https://circleci.com/docs/ja/2.0/circleci-images/

開発環境を含めた乗り換え方法とかをメモ📝

開発環境をcircleci/rubyからcimg/rubyに乗り換える

circleci/rubynode-browserのイメージからcimg/rubyに乗り換える際にはcimg/rubybrowserのイメージに乗り換えます。

ブラウザー ブラウザー バリアントのベースは元の Ruby イメージと同一ですが、こちらでは apt により Node.js、JavaSeleniumブラウザーの依存関係が事前インストールされます。 https://circleci.com/developer/ja/images/image/cimg/ruby#variants

単純に利用するimageを変更するだけだったら話が早いのですが、cimg/rubybrowserのイメージではデフォルトでブラウザ及びドライバーがインストールされません。

このバリアントは、CircleCI Browser-Tools Orb と組み合わせて使用する想定で設計されています。 この Orb を使用すると、任意のバージョンの Google ChromeFirefox のいずれかまたは両方をビルドでインストールできます。 https://circleci.com/developer/ja/images/image/cimg/ruby#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC

CI環境ではorbsが提供されているので、それを利用すればいいのですが、開発環境では自分でインストールする必要があります。

今回は以下のようなDockerfileを用意してcimg/rubybrowserのイメージに追加でChrome及びChrome Driverをインストールするようにしました。

# == base
FROM cimg/ruby:3.0.3-browsers

# instal stable chrome / chrome driver
RUN wget https://dl.google.com/linux/linux_signing_key.pub &&\
    sudo apt-key add linux_signing_key.pub &&\
    echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list &&\
    sudo apt -y update && sudo apt-get -y install google-chrome-stable
RUN CHROME_LATEST_VERSION=$(curl -sS "omahaproxy.appspot.com/linux?channel=stable") &&\
    CHROME_LATEST_MAJOR_VERSION=$(echo $CHROME_LATEST_VERSION | cut -d . -f 1) &&\
    CHROME_DRIVER_VERSION=$(curl -sS "chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_LATEST_MAJOR_VERSION}") &&\
    wget https://chromedriver.storage.googleapis.com/${CHROME_DRIVER_VERSION}/chromedriver_linux64.zip &&\
    unzip chromedriver_linux64.zip &&\
    sudo mv chromedriver /usr/bin/chromedriver &&\
    sudo chown root:root /usr/bin/chromedriver &&\
    sudo chmod +x /usr/bin/chromedriver

上記のDockerfileでcircleci/rubynode-browserのイメージと同様にheadless chromeを利用したE2Eテストが行えるようになりました✨

CI環境をcircleci/rubyからcimg/rubyに乗り換える

以下の通りcimg/rubybrowserイメージは、CircleCI Browser-Tools Orbを利用するとcircleci上で簡単に任意のブラウザ環境を立ち上げることができます。

このバリアントは、CircleCI Browser-Tools Orb と組み合わせて使用する想定で設計されています。 この Orb を使用すると、任意のバージョンの Google ChromeFirefox のいずれかまたは両方をビルドでインストールできます。 https://circleci.com/developer/ja/images/image/cimg/ruby#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC

※以下は一部を抜粋したものです。orbscircleci/browser-toolsを追加して、E2Eテストの実行前にbrowser-tools/install-chromebrowser-tools/install-chromedriverを実行すれば良い。

version: 2.1

orbs:
  ruby: circleci/ruby@1.2.0
  node: circleci/node@4.0.0
  browser-tools: circleci/browser-tools@1.2.3

web: &web
  - image: cimg/ruby:3.0.3-browsers
    environment:
      <<: *web-default-enviroments

db: &db
  - image: circleci/postgres:10.13
    environment:
      POSTGRES_USER: circleci
      POSTGRES_PASSWORD: password

executors:
  web:
    docker:
      - <<: *web
  web-db:
    docker:
      - <<: *web
      - <<: *db
jobs:
  ruby_test:
    executor:
      name: web-db
    steps:
      - attach_current
      - install_ruby_deps
      - install_node_deps
      - browser-tools/install-chrome
      - browser-tools/install-chromedriver
      - rails_migration
      - build_webpack
      - run:
          name: run tests
          command: bundle exec rspec spec/

circleci/browser-toolsの詳細は以下

circleci.com

参考

tecadmin.net

dev.classmethod.jp

blog.toshimaru.net

*1:こちらを参考に良い感じに依存ライブラリ等がデフォルトでインストールされていて便利だったので。