こんにちは Diverse developer blogです。今回はプロジェクトの構想から完了まで、1年半ほどかけて行った「PerlとDebianの更新プロジェクト」を振り返ります。
なぜやったのか?
弊社のYYCは20年以上稼働しているサービス(SNS, マッチング, ライブ配信)です。ユーザーの要望に応えるため、機能開発を優先してきたことで開発環境の改善が遅れていました。
特にバックエンドの開発言語(Perl 5.8)と、コンテナOS(CentOS)のアップデートが遅れており、今後の機能開発やセキュリティ対応に課題が生じていました。
そのため、プロジェクトの目標は「開発言語とコンテナOSをLTS(long-term support)バージョンまで更新する」ことにしました。そして、課題を一つ一つ段階的に解決して、ついに目標を達成しました。現在のYYCのバックエンドは、最新のPerl5.40とDebian Bookwormで稼働しています。
どうやったのか?
ここらはプロジェクトの進行を時系列順に紹介します。
1. 段階的リプレイスで失敗した
プロジェクト当初は、当時のYYCとは別にYYC v2を開発して画面や機能ベースで段階的にリプレイスする方式をとりました。しかし、新旧のYYCから共通のDBを安全に操作するのが難しくなり、途中でリプレイスを中止しました。
当時の判断や取り組みは、YAPC::Kyoto 2023で登壇した資料 にまとまっています。この取り組みは失敗になり、段階的なリプレイスに半年ほど費やしました。しかし、サンクコストを気にせずに方針を転換して、今では正しかったと思います。
2. リファクタリングに方針転換した
段階的なリプレイスで開発したコードやリソースは完全に削除して、既存のYYCをリファクタリングする方針に切り替えました。まずは、開発環境を理想の状態に近づけることを目指しました。そして、この作業で出た差分を本番環境へ徐々に適応しました。実施した順に具体的な作業内容を箇条書きで紹介します。
- CentOSをDebian Busterへ移行する
- 開発環境のコンテナOSをまずはDebianベースへ移行した
- mod_perl v1をStarmanとPSGI(Perl Web Server Gateway Interface)へ移行する
- PSGIでも動作するか開発環境で検証した
- Perlのバージョンを固定している原因のひとつがmod_perl v1だったため、mod_perlは置き換え可能か調査した
- Perlは5.16までアップデートする
- 5.18にアップデートするとコードの修正箇所が多いため
- 例えば
foreach my $hoge qw(a b c) {}
が使えない - 多数のモジュールがインストールに失敗する
- 例えば
- 5.16でモジュールの整理整頓と非推奨の警告修正を優先した
- 5.18にアップデートするとコードの修正箇所が多いため
- ファイルベースで管理していたライブラリをcpanfile経由へ移行する
- プロジェクトで使用中のライブラリを洗い出し、必要なライブラリのみを移行した
- すべてのパッケージを最新バージョンにアップグレードした
- 移行できないライブラリ(社内専用、CPANに存在しない)は、専用ディレクトリを用意してコードをそのままコミットして利用する方式をとった
3. 段階的にLTSバージョンまでアップデートする
PerlもDebianも段階的にアップデートしました。まずは、Debian Busterで本番環境でも正常に稼働する確認がとれてから、Perlのアップデートへ移りました。段階的な手順は以下のとおりです。
- Perl5.8 + mod_perl + busterとPerl5.16 + PSGI + Starman + busterのどちらでもバックエンドが起動して単体テストとE2Eテストが通ることを確認した
- パフォーマンステスト(taurus)で性能劣化がないことを確認した
- Perl5.16 + PSGI + Starman + busterをリリースして正常に稼働した
最後にPerl5.38.2をアップデート対象にしてコードの修正をしつつ、2024年6月30日にBusterはEOLをむかえるため、Bookwormの検証も同時に開始しました。ところが、この作業中にPerl5.40がリリースされました。Perl5.38.2で動作確認がとれていたのでPerl5.40へアップデートしてリリースしました。Perl5.40 + PSGI + Starman + bookwormでリリース後、use v5.40;
をすべてのPerlのコードに追記して、プロジェクトは完了しました。
4. アップデート対応で工夫したこと
このプロジェクトと同時並行で、現行環境での機能開発も継続して行っていました。そのため、Perl 5.16 + PSGIへの移行時は、新しい環境の変更をできるだけ現行環境にも取り込んでいく必要がありました。特に以下の2点を重視していました。
- 新しい環境の変更点を現行環境の開発中でも意識できるようにして移行をスムーズに進めたい
- コード自体は事前にリリースしておき、環境の切り替えはコンテナイメージの変更のみで行い、切り戻しをしやすい状態にしたい
これらを実現するために以下の工夫をしました。
- Perl5.8 + mod_perl と、Perl5.16 + PSGI どちらでもプロジェクトのコードが動くように、ベースクラスで環境の違いを吸収した
Apache::Constants
、Apache::Singleton
など環境に依存するパッケージを直接使っている場合は、プロジェクト内に同様の役割のクラスを作成して事前に移行した- パッケージの最新化で Perl5.8 環境から挙動やインタフェースが変わる場合には、一時的にプロジェクト内で該当のパッケージを継承したり MixIn をすることで、Perl 5.16 環境と同じように動くようにした
- CI では Perl 5.8 + mod_perl と Perl 5.16 + PSGI の2つの環境を用意し、どちらの環境でも動作確認できるようにした
2つの環境をまたがって作業すると、混乱することはありました。しかし、切替はイメージの変更だけで行えたので、不具合の特定やロールバックはしやすい状態で移行できました。正常に移行できた後、新旧の両方で動くように工夫したコードはすべて削除しました。
やってよかったことは?
1. 課題と解決策がわかりやすくなった
アップデートを安全かつ効率的に進めるために不要なコードや機能をたくさん削除しました。考慮するコンテナの数やライブラリの数も減りました。開発言語とOSのアップデートと同時に、利用中のミドルウェアやライブラリも最新化できました。この結果、問題の特定が楽になり、新たな課題の発見とその解決策がわかりやすくなりました。
2. 取れる選択肢が増えた
開発言語もOSもLTSバージョンなので、ライブラリやパッケージが利用できないケースが減りました。以前まではOSが古いため、PerlだけでなくNode.jsなどの他のライブラリのバージョンも更新できない状況でしたが、その心配はなくなりました。
まとめ
プロジェクトを完了して、古く閉ざされた開発環境から解放されました。開発するモチベーションも上がっています。このようなプロジェクトを経験できたのは、多くのユーザーがYYCを長年利用してくれた結果だと思います。今後は、もっと早く計画的に対応できるよう、Diverseでは継続的な改善を怠らない体制を維持していきます。
ブログの内容や弊社に興味のある方は、ぜひ以下の採用ページからカジュアル面談へ!様々な意見をお待ちしています。