ライブラリアップデート時はアプリケーションを実行させるな!
メモ

ライブラリアップデート時はアプリケーションを実行させるな!

2023.08.23

こんにちはjunです。最近のフレームワークやミドルウェアはバージョンあたりのサポート期限を短くして、頻繁にバージョンを更新することが多いです。マイナーはともかくメジャーバージョンでは変更点が多いので慎重に行う必要があります。

私も保守をしていたLaravelプロジェクトで8→9へのアップグレード作業がありました。マイグレーションガイドに従って他ライブラリのバージョン変更などを行い、検証してデモ環境で問題なかったため本番で実施しました。しかし本番でなぜか失敗してロールバックを2回も行う事態が発生しました。

結論からいうとLaravelのphp artisan downを実行してcomposer update諸々を実行しましたが、ユーザーのリクエストがその時にも来ていたことによってLaravelが起動。キャッシュなどの影響によってアップデートしたアプリケーションが動かなくなったことが原因と思われます。

この記事では上記事態の詳細な経緯と原因、やらかしたときのロールバック・対策、今後の対策について書こうと思います。Laravelを実例として出しますが、DjangoやRails、expressなど他のフレームワークでのバージョンアップ作業でも参考になると思います。反面教師としてご活用ください。

経緯

Laravelプロジェクトの8→9への変更にあたりアップグレードガイドを参考にして作業を行い、テストをパス、そしてデモ環境で問題なくアップデートが出来たため本番環境での実行を進めました。

流れとしては

  1. php artisan downを実行してページの表示や全てのリクエストに対して503を出すように変更。
  2. 変更したファイルをプル
  3. composer updatephp artisan migrateを行ってライブラリとDBを更新
  4. php artisan upでメンテナンスモードを解除。キャッシュの削除などを行う。

上記のように行いました。4で解除をしてサービスのURLを見てみると...

( 0Д0)

アプリケーション・サーバキャッシュの削除を行いましたがページは変わらず。しかし、php artisan tinkerやlocalhostにcurlした場合は問題なく応答しており原因が不明でした。

しばらく修正を試みて色々行いましたが結局直らず、メンテナンス終了時刻が迫ってきたためロールバックを行いました。

とりあえず元には戻りサービスが利用可能になったので一安心。しかし本番のみ発生するこの事象に頭を悩ませて他の人と相談しました。

解決と原因

先方に相談してまた次の日にメンテナンスを実行。相談に乗っかってくれたインフラエンジニアさんがスタンバイしながら、私が上記の操作を行いました。そして今回も発生して一通りログなどをみても特に有効打になりそうな内容が見つかりませんでした。

しかしなぜか100%登録されているはずのroutingがないというエラーがLaravelログに記録されており、Laravelそのものが上手く起動していないことがわかりました。またロールバックを行い、今度は別のディレクトリをコピー作成してそこでアップデート作業を行いました。とりあえず本番環境中でマイグレーションを行ってそのファイル一式をローカルなりで解析しようという戦略に変更。

念の為ドキュメントルートの向き先を変更して同じ状態であることを確認すると...なぜか正常のいつものサービスの画面が表示されました。

とりあえず問題なくアップデートは終了しことなきを得ました。しかし原因関しては予測とはなりますが、php artisan downではcomposer update 中でもLaravel自体(index.php)が実行される。本体のライブラリは色々と更新中にも関わらず、スクリプトが実行されることで変なキャッシュが生成されたことが原因だったのではないか? という結論に至りました。

対策と考察

php artisan downはあくまでLarabvelが動的に503エラーを生成するだけであり、リクエスト自体はLaravelのindex.php自体は実行されていることが今回の要因と思われます。そのため今回のようなライブラリを更新する際などはそもそもLaravel自体起動しないようにする必要がありました。

方法としてはドキュメントルートや(ネットワークの)ルーティングを変更して、変更先にはメンテナンス画面のHTMLを置いておく。そして全てのリクエストに対してそのファイルを見せるように設定することが一番な気がします。

今回はLaravelでしたが、Djangoや他のフレームワークでもメンテナンス時はwebサーバレベルでルーティングを変更して、それらが起動しないようにすることが大切だと思います。

やらかす前の対策とやらかした時のロールバック

やらかす前に..

まず本番環境では大小の変更に関わらず、必ずバックアップを行います。この場合Laravelレベルでなく、

  • DBはダンプなりしてバックアップをとっておく。
  • アップロードファイルもローカルならばバックアップしておく。
  • git などで戻れる体制を整える。

そしてアップデートの場合、composer.jsonなどの旧バージョンの管理ファイルをバックアップしておくのを忘れないでください。とにかくバックアップさえあればなんとかなることが多いです。

そしてデモ環境などであらかじめアップグレードの予行練習はしましょう。

やらかしたら..

まずは落ち着きます。とにかく落ち着きましょう。私の場合、その後の原因解明zoomでも指が震えたままで結構タイプミスしていました笑。このような場合、同席したインフラエンジニアさんはタバコを一旦吸うそうです。

そして落ち着きの間に連絡の取れるかに一報を必ず入れましょう。焦っているときは人間変な行動をしてしまうことが多く、余計に自体を悪化させることがあります。その時に他に冷静な人がいるだけでもすぐに解決策が見つかったり、次に何をすべきかを考える余裕ができます。

そしてメンテナンス時間内であれば何か手順をミスっていないか、忘れていないかを再度確認をしていきましょう。どうしても時間が間に合わなそうであればロールバックを行い、少なくともサービスが実行できるようにしましょう。

最後にログ取得や詳細な状況を記録して今後の対策に当てましょう。

いやーそれにしても何年経っても本番環境って怖いです。

Copyright © 2021 jun. All rights reserved.