13 期の@yumuと@donokunです。10 月のサイクル OJT はホスティング事業部にお世話になりました。今回は SRE チームに入り、ロリポップとヘテムルの Rails アプリケーションのコンテナ化を行いました。
背景
ロリポップとヘテムルは複数のロールで構成されるサービスです。その一部は VM で動作していましたが、徐々にコンテナ化を進めてきました。
コンテナ化する理由は色々ありますが、特に今回はメンテナンス面のメリットに着目しました。コンテナはアプリケーションとその依存関係を一つのイメージにカプセル化するため、VM よりも管理が簡単です。これにより、アップデートやパッチの適用が容易になり、メンテナンスにかかる時間とコストを大幅に削減できます。
VM の場合システムの全容がわかりづらくメンテナンスをできる人が限られていましたが、コンテナ化により多くのメンバーがメンテナンスを行えるようになり、アップデートが迅速にできるようになりました。
やったこと
今回はVMで動作しているロリポップとヘテムルのロールのうち、申し込みやユーザ契約といった操作をするコントロール画面のバックエンドである Rails アプリケーションをコンテナ化し、Kubernetes に移行しました。
最初は現状のアプリケーションの役割や構成を把握するところから始めました。続いて、コンテナの作成、Kubernetes マニフェストの作成、動作確認、そしてモニタリング周りの整備といった手順で進めていきました。以降のセクションでは実際に行った作業やその中で解決した課題をいくつかピックアップして紹介します。
既存アプリケーションの構成把握
コンテナ化に際して、まずは現状の VM やアプリケーションの役割、構成を把握しました。何をコンテナ化して、既存のシステムをどのように置き換えるのかを明らかにすることが目的です。
VM の構成把握では、同一の VM でどのようなアプリケーションが動いているかを調べました。事前の情報から、移行対象のアプリケーションに加えて他のアプリケーションと NGINX が VM で動作していることと、NGINX はホスト名で HTTP リクエストを二つのアプリケーションに振り分けていることがわかっていました。もし仮にこれらが同一の VM で動いていることに依存した実装であった場合、一方のアプリケーション だけをコンテナ化すると何かが正常に動作しなくなるでしょう。例えばプロセス間の通信やローカルファイルの共有などが考えられます。そのような不具合を起こす要因として何があるかを洗い出しました。
具体的には NGINX の設定ファイルや移行対象のソースコードを全体的にみて怪しいところにあたりをつけます。NGINX の設定ファイルとログは VM にログインして実際に動作しているプロセスが使用しているものを確認します。結果としてはローカルファイルの共有などはなく、アプリケーションの変更はほとんど必要ないと判断できました。ただ NGINX はパスベースのルーティングを一部で行っており、もう少し詳細な調査を行いました。
個人的な話ですが、本番環境にログインする経験はこれが初めてで新鮮でした。
ルーティングの移行後の構成と妥当性の判断
先ほどのセクションの終わりに詳細な調査を行ったと言及しました。まずは最終的に決めた移行後の構成を説明します。
移行後の構成では対象のアプリケーションだけをコンテナ化し、Kubernetes 環境に移します。そのほかの NGINX やもう一つのアプリケーションはそのまま残して引き続き動作します。クライアントからのリクエストは DNS を設定することでそれぞれのアプリケーションに振り分けます。
次に、移行時の懸念点を述べます。移行前の構成では前節で言及したように VM は、VM 外のアプリケーションから複数のホスト名で参照されます。VM 内の NGINX では基本的にはそのホスト名をもとに HTTP リクエストを二つのアプリケーションに振り分けていました。しかし、remain.com
をホスト名と指定するリクエストの一部はパスベースで移行対象のアプリケーションに振り分けていました。おそらく機能の一部をアプリケーション間で移植し、その移行期間の設定としてパス名での振り分けをしていて今日まで残っていたのでしょう。
単純に一方のアプリケーションを VM から Kubernetes 環境に移行すると、VM の NGINX から Kubernetes にルーティングする形になり不恰好です。またパフォーマンスやメンテナンスの観点でも不利になります。そのため以下の構成図のように、リクエストをするクライアントのコードを変更して、適切なホスト名でリクエストを受け付けるようにする必要があります。
クライアントは全て社内で開発・運用しており、それらのソースコードを閲覧・編集できました。そのため以下の流れで該当するリクエストを発行しているクライアントを特定し、リクエストするホスト名を変更すれば解決します。
- NGINX のログをフィルタリング、IP アドレスの割り出し
- ソースコードの割り出し
- 変更可否の判断
幸いなことに変更箇所は一行だけで済むことがわかったため、先ほど挙げた通りの構成に移行することを決めました。
ArgoCD の活用
ホスティング事業部では、ArgoCDを採用しています。
ArgoCD は Kubernetes クラスタに対する継続的デリバリーを実現するツールです。ArgoCD は Git リポジトリ内の Kubernetes マニフェストファイルの変更を監視し、Kubernetes クラスタに自動的に適用します。
また、ArgoCD の拡張機能である ArgoCD Image Updater を使用して、Kubernetes クラスタ内のアプリケーションで使用されているコンテナイメージのCD(継続的デリバリー)を行っています。
revert 時の問題解決
アプリケーションに問題があって Pull Request を Revert した場合に、ArgoCD Image Updater がRevert後の最新コンテナイメージを反映してくれない問題が発生しました。結論としては、ビルド後のイメージハッシュとArgoCD Image Updaterの設定方法に原因がありました。
1. リリース前のイメージ(ハッシュ A)
2. リリース後のイメージ(ハッシュ B)
3. 2 を revert したイメージ(ハッシュ A)
revert したら 3 を適用したいのに 2 が適用されたままになってしまう
revert して再ビルドしたイメージ(3)は、リポジトリによっては過去と全く同じハッシュになることがあります。これまで、ArgoCD Image Updater の設定をイメージが作成された順でソートして最も新しいものを適用する方式にしていたのですが、イメージがビルドされた日時が最新であっても過去と同じハッシュだと無視されるため、revert 前のイメージ(2)が適用されてしまっていました。この事象が発生した場合は、手動でコンテナレジストリから revert 前のイメージ(2)を削除する必要がありました。
そこで今回、イメージを作成順ではなく名前順でソートする方式に変更しました。イメージのタグに20231127-170000
のようにビルド日時を入れることで、revert して過去と同じハッシュのイメージが作成されたとしても確実に revert 後のイメージを適用できるようになりました。
Pull Request 毎の preview 環境の構築
ホスティング事業部では、ArgoCD を用いて preview 環境の作成も行っています。preview 環境とは、一般に言う staging 環境のようなもので、本番に近い状態で実装した内容の動作確認ができます。
Pull Request にpreview
ラベルをつけるとArgoCD ApplicationSetが検知してそのPR専用のpreview環境をデプロイします。そのPRに/preview
とコメントすることをトリガーとして、GitHub Actions のワークフローが実行されます。ワークフローによってコンテナレジストリにイメージがプッシュされると、ArgoCD Image Updaterがこれを検知し、preview 環境のイメージを更新します。この仕組みによって、誰か 1 人が staging 環境を独占することなく、PR ごとに動作確認ができるようになっています。
今回のコンテナ化に伴い、ロリポップとヘテムルの Rails アプリケーションにもこのシステムが導入され、より開発しやすい環境が整いました。
まとめ
今回はホスティング事業部で Rails アプリケーションを VM から Kubernetes に移行した話をご紹介しました。2 人ともインフラ初心者ながら、1 カ月という短い期間で多くのことを学ぶことができました。
ペパボのサイクル OJT では毎月いろいろな面白いタスクに取り組んでいるので、ぜひ他の記事もご覧ください!