Railsアプリケーションで利用しているコンテナベースイメージのOSをアップデートした際に発生した問題とその対処 – Repro Tech Blog


こんにちは。Repro Teamでエンジニアをしている矢作です。 Reproには入社して約2ヶ月程になります。
Repro というシステムのうち、マーケターの方々が利用する管理画面は Ruby on Rails で構築されており、現在は ECS (Amazon Elastic Container Service) 上で稼働しています。

先日、この Rails アプリケーションを動かしているコンテナのベースイメージのOS(Debian)を Busterから Trixie へアップデートした際に、アップデート自体は問題なく完了したものの、タイムゾーン関連でニッチな不具合に遭遇しました。

まずは、実際にどんなエラーが発生していたのかを見てみましょう。

ActionView::Template::Error: Invalid Timezone: Rangoon

どうやら Asia/Rangoon というタイムゾーンの解決ができなくなっており、該当のタイムゾーンを活用する場面において、システムが正常に動作しなくなってしまいました。

手元でTrixie/BusterそれぞれのベースイメージのRailsアプリケーションで以下のようなスクリプトを実行したところ、Trixie上で動いているRailsアプリケーションでのみエラーが発生するため、OSアップデート起因の不具合であると判断しました。

以下はそれぞれ、Trixie/Buster上で動いているRailsアプリケーションで再現コードを実行した際のログになります。

irb(main):003> Time.use_zone('Rangoon') { pp 'hello' } 
(irb):3:in `
': Invalid Timezone: Rangoon (ArgumentError)
irb(main):004> Time.use_zone('Rangoon') { pp 'hello' } 
"hello"

OSアップデート起因の不具合であることの裏付けとして、Rails内では2025/10現在、Rangoonというキー 1 に対応するタイムゾーンマッピングは残ったままとなっております。

"Rangoon"                      => "Asia/Rangoon",

https://github.com/rails/rails/blob/6ec4c85507d10650cb80796deda7d79a17677c29/activesupport/lib/active_support/values/time_zone.rb#L143

ここでは、 Busterから TrixieへのOSアップデートによって、

  • 何故 Asia/Rangoon というタイムゾーンが正しく解決されなくなったのか
  • どう対処したか

を紹介していきます。

RailsActiveSupport::TimeZone は、内部的にTZInfo::Timezone インスタンスを取得して使っています。
実際、ソースコード上では

def find_tzinfo(name)
  TZInfo::Timezone.get(MAPPING[name] || name)
end

https://github.com/rails/rails/blob/6ec4c85507d10650cb80796deda7d79a17677c29/activesupport/lib/active_support/values/time_zone.rb#L208-L210

のように TZInfo を呼び出しており、Rails 自体にタイムゾーンデータが含まれているわけではありません。
OS内のtzdata 側の定義が変わると、この処理にも影響が出る構造になっています。

ここまでで、RailsActiveSupport::TimeZone は内部的に TZInfo を利用し、
TZInfo は OS にインストールされている tzdata の情報を参照してタイムゾーンを解決していることを確認しました。

リリースノートより、旧称や別名(エイリアス)として扱われていたタイムゾーン定義が tzdata-legacy パッケージに分離されました。

If necessary, you can install the tzdata-legacy package.

必要に応じて tzdata-legacy パッケージをインストールしてください と書かれています。

また、記述内のリンクから影響を受けるタイムゾーンの一覧を参照することができ、今回の発端となった Asia/Rangoon タイムゾーンもこの一覧に含まれています。

つまり、Asia/Rangoon タイムゾーンはこの変更によって影響を受けるタイムゾーンのうちの一つ2であることが判明しました。

tzdata-legacy パッケージとは

そもそも tzdata-legacy とは? 何故legacyなのかも気になると思いますのでここで軽く紹介しておきます。

先ほど紹介したリリースノート内に以下の一文が書かれています。

Timezone names not following the current tzdata naming rule of geographical region (continent or ocean) and city name were split out into the tzdata-legacy package.

機械翻訳したものが以下です。

地理的地域 (大陸または海洋) と都市名の現在の tzdata 命名ルールに従わないタイムゾーン名は、tzdata-legacy パッケージに分割されました。

じゃあ 地理的地域 (大陸または海洋) と都市名の現在の tzdata 命名ルールに従うタイムゾーン とは? という疑問が新たに生まれますが、これは IANA という組織が管理しているようです。

つまり、何らかの理由によって現在の命名規則にそぐわなくなったタイムゾーン定義が tzdata-legacy パッケージに含まれています。

Asia/Rangoon タイムゾーンはそのうちの一つでした。

対処方法には以下の2パターンが上がりました。

  • コンテナ内部にtzdata-legacyパッケージをインストールする
  • tzinfo-data gem をインストールする

今回採用した方法は tzinfo-data gem をインストールする になります。

Rails組み込みのtzinfo gem は、tzinfo-data gem が入っていたらこれを、なかったらzoneinfoディレクトリに配置されているタイムゾーン情報を参照することでタイムゾーンの解決を図ります。

By default, TZInfo will attempt to use TZInfo::Data. If TZInfo::Data is not available (i.e. if require ‘tzinfo/data’ fails), then TZInfo will search for a zoneinfo directory instead (by checking the directories specified by TZInfo::DataSources::ZoneinfoDataSource.search_path in turn).

https://github.com/tzinfo/tzinfo?tab=readme-ov-file#data-sources

アプリケーションレイヤーで解決可能であること、-legacyと名の付いたパッケージをずっと入れ続けることに違和感を感じること、アプリケーションレイヤーで解決しておけると今後OSのtzdataの変更による影響から切り離せることからこちらの方法を採用しました。

リポジトリREADMEを読むと

Timezone data is based on the public domain IANA Time Zone Database.

と書かれていますが、将来的に現在の命名規則にそぐわなくなったタイムゾーン定義が消される予定なのか、はたまたそういった定義も残し続ける方針なのかどうかまではissue等を読む限り分かりませんでした。

そもそも何で Asia/Tokyo 以外のタイムゾーンを扱っているのか?

弊社は MA(マーケティングオートメーション)ツールとして、アプリや Web サイトを運営する事業者様にご利用いただいています。
日本国内だけでなく、海外をターゲットにした事業者様の利用も想定しており、管理画面上から利用するタイムゾーンの指定が可能となっております。

例えばですが、ターゲットはインドネシアのユーザーなのにも関わらず、日本時間を基準にメルマガを送信してしまうと、現地では管理画面上で設定したよりも2時間早い時間にメルマガが配信されてしまいます。

つまり、弊社ではターゲットの現地時間に対する正確な配信スケジュールを管理する必要性が生じているため、 Asia/Tokyo 以外のタイムゾーンも扱っております。

ここまで書くともうお分かりの通りかと思いますが、ある事業者様がタイムゾーンとして Asia/Rangoon を選択されていたため、Debian Trixie へのアップデート後、このタイムゾーンが解決できなくなり、今回の事象が発生していました。

  • tzdata パッケージの構成変更により、Asia/Rangoon を含む旧称タイムゾーンtzdata-legacy パッケージ側へ移動された
  • デフォルトでは tzdata-legacy パッケージがインストールされていないため、Asia/Rangoon に関するタイムゾーンの定義がコンテナ内部から存在しなくなった
  • その結果、tzdataが持つタイムゾーン定義に依存するTZInfo経由でタイムゾーンを解決している ActiveSupport::TimeZoneAsia/Rangoon に対するタイムゾーンの解決が行えず、実行時にエラーを起こしてしまった。
  • Reproでは tzinfo-data gem を追加でインストールすることで、アプリケーションレイヤーでの解決を実施した

となります。

以上、Railsアプリケーションを動かしているコンテナベースイメージのOSをアップデートした際に発生した際に遭遇したタイムゾーン関連の不具合とそれに対する対処についてご紹介しました。
この対応にあたるまで私は、tzdata はおろか、IANAという組織名すらも知りませんでした。

タイムゾーンの扱いは難しいとよく本などに書かれていたりはしますが、身を持って実感する機会には恵まれてこなかったため、対象のユーザーさんには不具合によって一時的に不便な思いをさせてしまったことと思いますが、自分としては良い経験となりました。

Reproでは、普段の開発からなんかわからんがとりあえず作れた/直ったからヨシ! ではなく、何故その不具合に繋がったのかをディープダイブして解き明かしていける文化があるなと感じています。

これだけにとどまらず、Reproというシステムはシステム特性上、大量データの扱いから逃れられないスリリングな開発経験を積むことが出来る環境です。

SaaSの開発は、DBからデータを読み出してJSONを返すだけ とか言いながら開発に慣れている感を出してきた自分ですが、Reproのシステムを前に日々実力と知識不足を痛感しております。

このような環境で、ソフトウェアエンジニアとしてさらに一皮向けたいと思っている方がいましたら、ぜひお話ししましょう!
フロントエンドからバックエンドまで関われる | 大量のトラフィックを高速に捌くアプリケーション開発をしたいエンジニア募集!




Source link

関連記事

コメント

この記事へのコメントはありません。