giftee Tech Blog

ギフティの開発を支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信しています。

Railsバージョンアップ対応のハマりから得たDockerベースイメージ更新の知見

thumnail

はじめに

こんにちは、エンジニアのoruiと申します。

普段は大手飲食チェーンに向けて開発を行っており、最近は業務でRailsバージョンアップ対応に携わっています。Railsのバージョンアップに伴いRuby自体のバージョンも上げる必要があり、Rubyのバージョンは Dockerのベースイメージで管理しているため、ベースイメージの更新を行いました。

そのベースイメージ更新時に、チームでハマった出来事がありました。 本記事では、そのハマりの詳細を振り返りながら、ベースイメージ更新時に注意すべき点を共有します。

事象

Dockerのベースイメージを ruby:3.1.2-alpine から ruby:3.4.7-alpine に変更した際に、ローカル環境でDBの接続に失敗する問題が発生しました。

その時に発生したエラーは以下になります。

Failure/Error: ActiveRecord::Migration.maintain_test_schema!

ActiveRecord::ConnectionNotEstablished:
  TLS/SSL error: Certificate verification failure: The certificate is NOT trusted.

原因

調査の結果、MySQL接続用の MariaDB Connector/C というライブラリのバージョンが上がり、証明書検証を強制するようになったことが原因と分かりました (参考)。既存の接続設定では証明書検証を前提としていなかったため失敗していたというわけです。

対応方針

今回は、DB接続時に証明書検証を行うように修正対応を行う方針となりました。

検討したものの、採用しなかった解決策

参考までに、採用しなかった案も残しておきます。

  1. 環境変数 MARIADB_TLS_DISABLE_PEER_VERIFICATION=1 で証明書検証を無効化する

    今回の問題への対応策の一つとして挙がっていました (参考)。 ただ、この環境変数がいつ使えなくなるか分からず、将来また同じ問題を踏む懸念があったため見送りました。

  2. ベースイメージを slim に変更する

    slim (Debianベース) に変更したところ、この問題は発生しませんでした。ただ、当時は「Alpineの方が軽量でイメージに含まれるパッケージが少ないため、脆弱性が検知されにくい」と考え、採用を見送りました。

原因の深掘り

記事の執筆にあたり、MariaDB Connector/C のバージョンが上がった原因を改めて調べてみました。

そもそも MariaDB Connector/C はどこで入っているのか

まず、Dockerfile上のどの記述によって MariaDB Connector/C ライブラリが導入されているのかを調べました。 原因は、インストールしているパッケージ mysql-dev でした。

FROM ruby:3.4.7-alpine
RUN apk update && apk add --no-cache \
    ... \
    mysql-dev \
    ... \

mysql-dev は実体として mariadb-dev のことを指します。mariadb-devPackage details を確認すると、パッケージの別名を表すProvidesmysql-dev が含まれています。

また、Package detailsの依存関係に mariadb-connector-c-dev が含まれています。この mariadb-connector-c-dev こそが MariaDB Connector/C の本体です。

なぜ MariaDB Connector/C のバージョンが上がったのか

バージョンを固定せず apk add でパッケージをインストールした場合、バージョンはAlpineのバージョンに依存します。 Dockerのベースイメージを ruby:3.1.2-alpine から ruby:3.4.7-alpine に変更したことで、土台のAlpineバージョンも 3.16.3 から 3.23.0 に変わりました。

$ docker run --rm ruby:3.1.2-alpine cat /etc/alpine-release
3.16.3
$ docker run --rm ruby:3.4.7-alpine cat /etc/alpine-release
3.23.0

そして、Alpine 3.23 では mariadb-connector-c3.4.x 系列になります。3.4.x 系列は、3.3.x 系列とTLS検証の動作が異なり、証明書検証を強制するようになりました (参考)。

整理すると、今回のハマりは次の経緯で起きていました。

  1. DockerベースイメージのRubyのタグを変更( 3.1.23.4.7
  2. それに伴い土台のAlpineバージョンが更新される( 3.16.33.23.0
  3. Alpineバージョンの変更に伴い、mysql-dev 経由で入る MariaDB Connector/C が 3.3.x から 3.4.x に上がる
  4. 3.4.x ではTLS/証明書検証が強制され、既存のDB接続が失敗する

まとめ

今回のハマりで以下を学びました。

ベースイメージをバージョンアップすると、利用するパッケージのバージョンも変わり、挙動の差異が発生することがあります。これは、ベースイメージのタグ変更により、土台となるOSのバージョンが代わり、それに伴いパッケージのバージョンも変わるためです。

この仕組みを頭の片隅に入れておけば、今後同様の現象に遭遇しても、落ち着いて原因を切り分けられそうです。