はんドンクラブ 運営ブログ

Mastodonインスタンス「handon.club」の運営ブログです。コラムなど,Mastodonに関する一般的な記事も投稿予定です。

【追記あり】【障害発生・復旧報】一部画像が正常に表示されない不具合が発生していました

はんドンクラブにおいて,以下の障害が発生していましたが,現在は復旧しています。ご迷惑をおかけしたことをお詫びいたします。

  • 日時: 2019年11月19日 15:05:13 〜 2019年11月19日 19:02:19 (JST)
  • 影響範囲: はんドンクラブの全ユーザ
  • 障害内容: 特定の画像が表示されない
  • 原因:Webサーバ設定が不適切であり,利用している外部サービスのIPアドレス変更に追従できなかったため
  • 解決方法: 暫定的にはWebサーバの再起動で回復済。本格対処は11月21日までに実施予定 11月20日23:50頃に本格対処完了

障害の発生メカニズム

はんドンクラブでは,メディア(トゥートに添付された画像や動画,またはアイコン画像など)は,Conohaのオブジェクトストレージに保存されています。このオブジェクトストレージ内のメディアへのアクセス用URLをWebページのドメイン(handon.club)と同一ドメイン(media.handon.club)にするため,はんドンクラブサーバ内のnginxでリバースプロキシを使っています。

media.handon.club における nginx.conf は,以下のようになっていました(一部抜粋)。

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name media.handon.club;
  ~~~中略~~~
  add_header Cache-Control "public, max-age=31536000, immutable";
  location / {
    proxy_pass https://object-storage.tyo2.conoha.io/v1/xxxxxxx/xxxxxxx/;
    ~~~中略~~~
  }
}

よく知られた問題として,proxy_passドメインを書いた場合,nginxの起動時にのみ名前解決が行われます。そのため,nginx起動後にDNSレコードの変更があった場合でも,OS側のTTL設定に依らず,レコード変更に追従することができません。つまり,手動でnginxを再起動するまで,永遠に古いDNSレコードが使われつづけてしまいます。

ktrysmt.github.io

今回の障害の原因については,前述のnginxの仕様により,オブジェクトストレージのグローバルIPアドレス変更に追従できなかったためです。conoha側で何らかの理由で object-storage.tyo2.conoha.ioIPアドレスが変更されましたが,はんドンクラブのnginxは古いIPアドレスへアクセスし続けてしまうため,結果としてユーザが画像を表示できない状態になっていました。

なお,古い画像には通常通りアクセスできていました。これは, media.handon.club が CDN によりキャッシュされているためです。前述の nginx.conf のとおり,一度アクセスした画像は,最大で31,536,000秒間CDNサービスのCloudflareにキャッシュされます(あれ,そういえば,Cloudflareってこのヘッダをちゃんと尊重してくれるんでしたっけ??)。そのため,キャッシュされているアイコン画像や古いトゥートに添付された画像はアクセスが出来るが,1度もアクセスがなかった画像にはアクセスができなかった・・・・ということになります。

なお管理人は,この proxy_pass の挙動について認識こそしていたものの,正しくない設定をしてしまいました。原因は,media.handon.club サーバについてはあまり深く考えずに各種設定を行っており,チェック漏れが発生したためです。要するに管理人の凡ミスです。

障害に気づくのが遅れた理由

今回の障害はユーザ申告により発覚しました。そのため,管理人が問題を把握したのは問題発生から3時間以上経過した18:30頃でした。こちらの原因について説明します。

はんドンクラブでは,media.handon.club については,1分に1回HTTPSリクエストを送ることで死活監視を行っています。そして,連続してアクセスエラーが発生すると,管理人と副管理人のLINEに通知される仕組みとなっています。そのため,サーバ障害に対しては速やかにその発生を認知出来るはずでした。

しかし,この死活監視は,常に同じエンドポイントに対して実施していました。そのため,当然CDNにキャッシュされているページに対して死活監視していたことになります。そのため,今回のように,新たにアップロードされている画像に限定して再現する障害では,アラートが上がらない状態となっていました。

今後の改善

  • nginx.conf については修正を行います。
    • 変数を介することでDNSレコードのTTLが設定出来るという(不思議な)手法があるため,これを適用します
    • 検証環境での動作確認を行う必要があるため,11/21(木)までの本番設定変更を目標に準備を進めます 適用済です
  • 死活監視方法の変更による早期障害検知は現実的ではないため,リスクを許容することとします。
    • 新しくアップロードされた画像に対するポーリング監視は,適切なエンドポイントが分からないため現実的ではありません
    • ただし,長期的には,ユーザの申告をより簡単かつ速やかに受け付けられる仕組みを検討し,リスクを軽減します

(11/20追記)以下のように設定変更しました。

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name media.handon.club;
  ~~~中略~~~
  add_header Cache-Control "public, max-age=31536000, immutable";

  location ~ /(.*) {
    resolver 8.8.4.4 1.0.0.1 valid=360s;
    set $container "object-storage.tyo2.conoha.io/v1/xxxxxxx/xxxxxxx";
    proxy_pass https://$container/$1$is_args$args;
    ~~~中略~~~
  }
}