503メンテナンスページ

やりたかったこと~全Webサーバをロードバランサーから外してメンテナンスしたい~

構成はCloudFront-NLB-EC2(2台)、外部公開サイトは2つ。
2台サーバともにロードバランサーから外してメンテナンスしたい。
なのでSorryサーバーを立ててロードバランサーの下に差し込み、他2台をロードバランサーから外しせば外部公開サイトへのアクセスはすべてSorryサーバーで503を返せる!と考えました。
※後述しますが実際にやってみると問題点が多く見つかりました。
※ちょっとググったら、CloudFront+S3でメンテページを表示させる方法があるらしく、次回以降はそちらをやる予定です。

作業記録~Sorryサーバ構築、メンテナンスページ表示、戻し作業~

マスターサーバおよびスレーブサーバはAPACHE,MYSQLのみでなく、DNSサーバ、メールサーバとしても機能しているので作業はもう少し複雑でしたがはしょっています。
今回はマスターサーバに大きな変更点を加えたのでスレーブサーバはマスターのコピーから作成しました。
なのでMySQLレプリも組み直し。
レプリ面倒・・・お金があればRDSを使いたい・・・。

・Sorryサーバの構築
インスタンス作成 (amazonlinux2)
※セキュリティグループで80,443を開けることを忘れない

・Apacheインストール
yum -y install httpd mod_ssl
cp -ai /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.0

・全アクセスに503メンテページへリダイレクト設定
vi /etc/httpd/conf/httpd.conf
-----
※下記を<Directory "/var/www/html"> の中に記述

ErrorDocument 503 /maintenance.html

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !=/maintenance.html
    RewriteRule ^.*$ – [R=503,L]
</IfModule>
-----

・httpsアクセスも同様に503メンテページへリダイレクト設定
cp -ai /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.0
vi /etc/httpd/conf.d/ssl.conf
-----
#DocumentRoot "/var/www/html"
↓
DocumentRoot "/var/www/html"

※下記を<Directory "/var/www/html"> の中に記述

ErrorDocument 503 /maintenance.html

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !=/maintenance.html
    RewriteRule ^.*$ – [R=503,L]
</IfModule>
-----

・(超簡素な)メンテページ作成
cat > /var/www/html/maintenance.html << '_EOF_'
ただいまメンテナンス中です。
_EOF_

・Apache起動
httpd -t
Syntax OK
systemctl start httpd

・503ステータスが返ってくるか確認
http://グローバルIPアドレス/
https://グローバルIPアドレス/
※Googleデベロッパーツールなどで確認しましょう。

・メンテページ表示
Sorryサーバをロードバランサーに組み込む
※healthyになるまで待つ

しばらくするとメンテページ表示されたりされなかったりする。
※キャッシュが効いてしまうのでいろいろなページにアクセスしてみる

ロードバランサーからマスター、スレーブサーバを外す
※外れたら念のためCloudFrontのキャッシュを消しておく
↓
どのページもメンテナンスページが表示されるようになった。

・メンテナンス作業
マスターで色々作業。
作業し終わったあと、マスターのAMI作成、そのAMIからスレーブを作成。
ホスト名やら微調整を加えてスレーブを仕上げる。

・MySQLレプリケーション
手順省略

・マスターとスレーブをロードバランサーに組み込む
メンテページ、普通のページが混在していることを確認
※ここで普通のページの挙動がおかしい場合はロードバランサーから外す

・Slaveの動作確認
Masterのapache、mysql、postfix、dovecot、named-chrootを停止
メール → おk 逆引きおっけ
dns → おk
外部公開サイト1 → 閲覧おk ログイン画面入れない 検索おっけ
外部公開サイト2 → 閲覧おk ログイン画面入れない 検索おっけ
cron監視 → おk

・Masterの動作確認
masterのapache、mysql、postfix、dovecot、named-chrootを開始
Slaveのapache、mysql、postfix、dovecot、named-chrootを停止
メール → おk 逆引きおっけ
dns → おk
外部公開サイト1 → 閲覧おk、記事更新おっけ、検索おっけ
外部公開サイト2 → 閲覧おk、記事更新おっけ、検索おっけ
cron監視 → おk
redmine → 更新おっけ、新規チケットおっけ、メールも飛ぶ。

失敗、問題点

Sorryサーバの構築失敗により502エラー

原因は①mod_sslのインストール忘れ(443で受けられるようにし忘れた)、②セキュリティグループを開け忘れた(80,443ポート)、だった。
仕事でこんなんやらかしていたらやばすぎた。
もし仕事でやるなら(CloudFront、NLB、EC2の本番環境のコピーから)ステージング環境を構築して事前検証するべきだろう。

特定IPアドレスからのみサイト確認するようにしたいができない(できるがめんどくさい)

作業後、一般ユーザにはメンテページへリダイレクト、わたしは通常通りにサイト確認できるようにしたいと考えた。
そこで試しにマスターサーバにSorryサーバーと同じようにメンテページを仕込み、
RewriteCond %{REMOTE_ADDR} !=<わたしのIPアドレス>
を追加してみたが問題発生・・・!
わたしが普通に見たサイトはキャッシュが残ってしまっているので、他のipアドレスからも普通に見れてしまうし、また、ほかのipからアクセスしてメンテページが表示されたページはわたしもメンテページが表示されてしまうのだ!!!

CloudFrontのビヘイビアをいじってキャッシュしないように設定すればいけそうだが、それでなくともメールやDNS、Cronなどの動作確認、MySQLのレプリなどもあってできる限り面倒なことは避けたい。

解決案~CloudFront+S3によるメンテナンスページ表示~

先述したがCloudFront+S3でメンテページを表示させる方法があるらしく、次回はそちらを試してみる。
まぁ今回のようにEC2を2台同時にApache落とすときは、マスターを複製してスレーブを作りレプリを組みなおす時なのであまり機会ないのだが・・。