LoginSignup
1

posted at

updated at

IBM Cloud CIS(Cloud Internet Services)のフォールバック・プール、いわゆるSorryサーバーをCode Engineで立ててみる

2022年10月13日追記:Code Engine内部のIstioの動きに変更があったようで、コンテナが5xxエラーを返した場合に、自動的に30回ほどリトライするようになりました。(また変わるかもしれません)
これにより、ICOSに対するリトライが無駄に大量に発生し、トータルのレスポンスも悪化するようになってしまいました。将来的にリトライ回数が制御できるようになることを祈ります。。。

はじめに

IBM CloudのCDNサービスであるCIS(Cloud Internet Services)を経由してサービスを提供する際、そのオリジンに指定したサーバーやその間のネットワークなどに問題がある際に、いわゆるSorryページを表示させるためのフォールバック・プールを設定することが出来ます。

このフォールバック・プールのオリジンに設定する、いわゆるSorryサーバーは、(多分一般的に)どのようなURLがリクエストされても、レスポンスコード503で静的なHTMLを返す、という要件があります。

これをCode Engineで実現してみます。

前提

素材の準備

IBM CloudがCode Engineのサンプルアプリとして提供している以下をカスタマイズする形で作成してみます。

ローカルに素材をクローンします。

$ git clone https://github.com/IBM/CodeEngine
Cloning into 'CodeEngine'...
remote: Enumerating objects: 1942, done.
remote: Counting objects: 100% (311/311), done.
remote: Compressing objects: 100% (91/91), done.
remote: Total 1942 (delta 235), reused 262 (delta 214), pack-reused 1631
Receiving objects: 100% (1942/1942), 2.47 MiB | 643.00 KiB/s, done.
Resolving deltas: 100% (1307/1307), done.

CodeEngine/helloにある素材を使用します。

$ cd CodeEngine/hello
$ ls -l
合計 20
-rw-r--r--. 1 root root 111  9月 13 16:52 Dockerfile
-rw-r--r--. 1 root root 417  9月 13 16:52 README.md
-rwxr-xr-x. 1 root root 593  9月 13 16:52 build
-rwxr-xr-x. 1 root root 671  9月 13 16:52 run
-rw-r--r--. 1 root root 370  9月 13 16:52 server.js

まずはサンプルをビルド

ibmcloud CLIでログインします。

$ ibmcloud login --sso -r jp-tok -g [使用するリソースグループ名]

Container Registoryにもログインします。

$ ibmcloud cr login

あらかじめ作成しておいたContainer Registoryの名前空間を環境変数に指定します。

$ export REGISTRY=jp.icr.io/[名前空間名]

ビルドします。

$ ./build

すると、jp.icr.io/[名前空間名]/hello:latestというイメージがプッシュされます。

サンプルアプリの実行

まず、事前に作成したCode Engineプロジェクトを現行コンテキストとして選択します。

$ ibmcloud ce project select -n [プロジェクト名]

アプリケーションを作成します。./runを実行、、といきたいところですが、前提となるレジストリー・アクセス・シークレットの設定が足りないようで、コンソールから実施します。プロジェクトのアプリケーション画面から、アプリケーションを作成します。

名前にhelloと入れて、「イメージの構成」をクリックします。

レジストリー・サーバーにprivate.jp.icr.ioを入力し、名前空間を自身のもの、リポジトリーはhelloを選択して、「完了」をクリックします。このとき裏で、ce-auto-icr-private-jp-tokという名前のレジストリー・アクセス・シークレットが作成されます。

さらに「作成」をクリックして、アプリケーションを作成します。

これ以降のアプリケーションの更新は、以下のコマンドで実行可能です。(runスクリプトでは、アプリケーションを一度削除してから作り直していますが、これではURLが毎回変わってしまいます)

$ ibmcloud ce app update -n hello --image private.${REGISTRY}/hello:latest --rs ce-auto-icr-private-jp-tok

アプリケーションのURLは、コンソールのEndpointsタグページか、以下のコマンドで確認出来ます。

$ ibmcloud ce app get -n hello -o url

curlで動作を確認します。(**********の部分は、ご自身の環境に合わせてください)

$ curl https://hello.**********.jp-tok.codeengine.appdomain.cloud
Hello World

Sorryページの作成

まず、Dockerfileに1行追加(3行目)して、必要なモジュールをインストールします。

Dockerfile
FROM icr.io/codeengine/node:12-alpine
RUN npm install
RUN npm install express morgan
COPY server.js .
EXPOSE 8080
CMD [ "node", "server.js" ]

次にserver.jsの中身を丸っと入れ替えます。

server.js
var express = require('express');
var morgan = require('morgan');
var app = express();

// Custom access log
app.use(morgan(':req[CF-Connecting-IP] - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'));

// For health check
app.get('/ready', function (request, response) {
   response.writeHead(200, {'Content-Type': 'text/plain; charset=UTF-8'});
   response.end('OK');
});

// Return 503 with sorry.html
app.all('/*', function (request, response) {
   msg = process.env.MSG ? process.env.MSG : 'Sorry. Out of service now.';
   response.writeHead(503, {'Content-Type': 'text/html; charset=UTF-8'});
   response.end(msg);
});

app.listen(8080);

大まかに以下の処理を実施しています。

  • アクセスログの設定。加えて、クライアントのIPアドレスを、CISが設定するヘッダCF-Connecting-IPから引用する
  • CISからのヘルスチェック(GET /ready)に対して、200 OKを返す
  • その他のリクエスト全てに対し、503でHTMLコンテンツ(環境変数MSGで設定)を返す

ビルドして、アプリケーションを更新します。

$ export export REGISTRY=jp.icr.io/[名前空間名]
$ ./build
$ ibmcloud ce app update -n hello --image private.${REGISTRY}/hello:latest --rs ce-auto-icr-private-jp-tok

Sorryページと、ヘルスチェック用ページをそれぞれcurlで確認します。

$ curl -v https://hello.**********.jp-tok.codeengine.appdomain.cloud
・・・中略・・・
< HTTP/1.1 503 Service Unavailable
< content-type: text/html; charset=UTF-8
< date: Tue, 13 Sep 2022 09:54:29 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 10
< x-powered-by: Express
< transfer-encoding: chunked
< 
* Connection #0 to host hello.**********.jp-tok.codeengine.appdomain.cloud left intact
Sorry. Out of service now.
$ curl -v https://hello.**********.jp-tok.codeengine.appdomain.cloud/ready
・・・中略・・・
< HTTP/1.1 200 OK
< content-type: text/plain; charset=UTF-8
< date: Tue, 13 Sep 2022 09:55:26 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 5
< x-powered-by: Express
< transfer-encoding: chunked
< 
* Connection #0 to host hello.**********.jp-tok.codeengine.appdomain.cloud left intact

Sorryページの設定

環境変数MSGに任意の文字列を設定することで、Sorryコンテンツをカスタマイズ出来ます。以下を実行することで、新しいリビジョンが作成され、アプリケーションが更新されます。

$ ibmcloud ce app update --name hello --env MSG="ごめんなさい"
$ curl https://hello.**********.jp-tok.codeengine.appdomain.cloud
・・・中略・・・
< HTTP/1.1 503 Service Unavailable
< content-type: text/html; charset=UTF-8
< date: Wed, 14 Sep 2022 07:14:24 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 7888
< x-powered-by: Express
< transfer-encoding: chunked
< 
* Connection #0 to host hello.**********.jp-tok.codeengine.appdomain.cloud left intact
ごめんなさい

HTMLファイルを仕込むことも可能です。

sorry.html
<html>
<header>
    <title>すまん</title>
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <meta charset="UTF-8">
</header>
<body>
<h1>ごめんなさい</h1>
<h2>いやほんと</h2>
<h3>すんません</h3>
</body>
</html>
$ ibmcloud ce app update --name hello --env MSG="$(cat sorry.html)"
$ curl -v https://hello.**********.jp-tok.codeengine.appdomain.cloud
・・・中略・・・
< HTTP/1.1 503 Service Unavailable
< content-type: text/html; charset=UTF-8
< date: Wed, 14 Sep 2022 07:11:39 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 90
< x-powered-by: Express
< transfer-encoding: chunked
< 
<html>
<header>
    <title>すまん</title>
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <meta charset="UTF-8">
</header>
<body>
<h1>ごめんなさい</h1>
<h2>いやほんと</h2>
<h3>すんません</h3>
</body>
</html>

Sorryページの中で使用したい画像ファイルは、Base64でテキストデータに変換してHTMLに仕込むのが良いと思います。

CIS設定

まず、Sorryサーバー用のヘルス・チェックを作成します。

  • 名前 : 任意
  • モニター・タイプ : HTTPS
  • パス : /ready

次に、フォールバック・プールに指定する起点プールを作成します。

  • 名前 : 任意
  • 起点
    • 起点名 : 任意
    • 起点アドレス : Sorryページのホスト名
    • ホスト・ヘッダー : 同上
  • ヘルス・チェック : 作成したヘルス・チェックを選択

最後にこの起点プールを、ロード・バランサーに加え、フォールバック・プールとして指定します。

これでいつでも謝れます(出来れば見たく無いページですが)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1