shibatch's journey

日々考えていることをつらつら書くだけです

【AWS】ALBのヘルスチェックでRESTfulなAPIの更新処理が動作するかを監視したい

f:id:shibatch:20210107232553p:plain

AWSでALB→EC2(複数)という構成のお話をします。

AWSのL7ロードバランサー、ALBでEC2やらにヘルスチェックする際、HTTPまたはHTTPSプロトコルのGETのリクエストメソッドを使いますね。例えば対象のEC2のポート80に対して30秒に1回ヘルスチェックして200 OKが返ってきたらOK〜という感じで。

Webサーバのヘルスチェックならそれで十分なのですが、RESTfulなインタフェースを持っているシステムなら、RESTful APIを叩いてヘルスチェックしたいって思うケースがあると思うのです。私はそんな場面に出くわしました。で、これをALBでやってみようとするとなかなか難しい。 何が難しいって、

  • リクエストヘッダを記載できないのでAPI Keyといった認証情報を乗せることができない
  • HTTPメソッドがGETのみで、PUTやPATCHができるかは確認できない
    • 当然更新用のdataといった情報は載せることができない

わけです。

私の場合はPowerDNSで更新のAPIをヘルスチェックで確認させたいな、と思っていて、何か良い方法ないかなぁと社内で相談したところ「EC2で動作するかんたんなWEBサーバを書いてヘルスチェックが来たらAPIでPOSTやPATCHするようにしたらどうか?」とアドバイスをいただき、なるほどそりゃ名案だ、ということでPythonで実装してみました。

↓こんな感じです。(healthcheck.py)

#!/usr/bin/env python3

from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import urllib.request
import urllib.parse
import configparser

config_ini = configparser.ConfigParser()
config_ini.read('/etc/default/PdnsAPIHealth.ini', encoding='utf-8')

class APIHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    base_url = 'http://127.0.0.1:8081'
    path = 'api/v1/servers/localhost/zones/example.com'
    headers = { "X-API-Key": "" }
    headers["X-API-Key"] = config_ini['DEFAULT']['api_key']
    data = {
      'rrsets': [{
         'name': 'example.com.',
         'type': 'MX',
         'ttl': 3600,
         'changetype': 'REPLACE',
         'records': [{
            'content': '10 mail.example.com.',
         }],
      }],
    }
    url = urllib.parse.urljoin(base_url, path)
    req = urllib.request.Request(url, json.dumps(data).encode(), headers, method='PATCH')
    try:
        with urllib.request.urlopen(req) as res:
           if res.code == 204:
              statuscode = 200
           else:
              statuscode = res.code
    except urllib.error.HTTPError as err:
       statuscode = err.code
    except urllib.error.URLError as err:
       statuscode = 500

    self.send_response(statuscode)
    self.send_header('Content-type', 'text/plain; charset=utf-8')
    self.end_headers()
    self.wfile.write(str(statuscode).encode())

if __name__ == '__main__':
  server_address = ('0.0.0.0', int(config_ini['DEFAULT']['listen_port']))
  with HTTPServer(server_address, APIHandler) as server:
    server.serve_forever()

これは何をやっているのかと言うと、ポート8080にHTTPのアクセスがきたらRESTfulなAPIを自分自身のポート8081に投入してレスポンスコードが正常なら200 OKを、そうでないなら500やらエラーのレスポンスコードを返します。

あとは以下のようなサービス起動設定を/usr/lib/systemd/system/ に配置して(CentOSです)、

[Unit]
Description=PowerDNS API HealthCheck Daemon

[Service]
ExecStart=/bin/healthcheck.py
Restart=always
Type=simple
PIDFile=/var/run/healthcheck.pid

[Install]
WantedBy=multi-user.target

サービスを起動させる。

$ sudo systemctl daemon-reload
$ sudo systemctl start healthcheck

あと、ALBではターゲットグループに対して「ポート8081をターゲットにするけどヘルスチェックはポート8080を使うよ」という設定をしてあげます。

f:id:shibatch:20210108100624p:plain
ALB設定
これでALBのヘルスチェックで「RESTfulなAPIで更新処理が動作するか」を監視できるようになりました! こういうことやりたい人、けっこういるんじゃないかなぁ、と思ったけれどもあまり参考になる情報がないなぁ、と思ったので書いたのでした。