エラーログが発生した時のアラートの設定
次に、エラーログが発生した際のアラートの設定をしていましょう。エラーログのアラート通知は以下のフローです。
- アプリケーションでログレベルがエラー以上のログが発生
- Stackdriverのロギングにエラーログが送られる
- 「Stackdriverロギングの指標」の機能でエラーログが検出される
この処理フローを実現するためには以下の手順が必要です。
- Stackdriverロギングの形式になったログフォーマット(JSON)でログレベルを出力するように、アプリケーション側の変更を行う。
- ログレベルがエラー以上のログを検出する指標を作成する。
- 先ほど作成した指標のCondition(状態)を条件にしたアラートを作成する。
Stackdriverロギング
手順の説明に入る前に、Stackdriverロギングについて簡単に説明します。Stackdriverロギングは主にログの収集と分析を行うことができるサービスです。GKEはStackdriverロギングと連携する機能があり、機能を有効にしているとGKEのコンテナで出力されたログは自動的にStackdriverに収集、保存されます。
Stackdriverロギングにはブラウザから見られるログのビューア機能もあり、ログレベルや特定の文字列をフィルタにしてログを表示することができます。他にもログベースの指標の機能を使って、特定の条件に合致したログエントリの数を記録する指標を作ることができます。
1.Stackdriverロギングの形式になったログフォーマット(JSON)でログレベルを出力するように、アプリケーション側の変更を行う。
GKEのコンテナで出力したログは、基本的には標準出力であればログレベルがINFO、標準エラー出力であればERRORになります。しかしログをJSON形式した上で、severityというキーにINFOやERRORといった値を指定して出力することで、その値に応じたログレベルを持ったログに変更できます。今回は検証用にseverityでログレベルを指定し、ログを出力するアプリケーションを作成します。
検証に使うアプリケーションは、どんなものでも構いません。今回はGo言語を使ったものを紹介します。エディタを開き、リスト2の内容をコピーして「server.go」のファイル名で保存してください。
package main import ( "os" "fmt" "net/http" ) func stdoutHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "stdout") fmt.Print("stdout") } func stderrHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "stderr") os.Stderr.WriteString("stderr") } func infoHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(`{"severity": "INFO", "message":"info"}`) fmt.Fprintf(w, "info") } func warningHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(`{"severity": "WARNING", "message":"warning"}`) fmt.Fprintf(w, "warning") } func errorHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(`{"severity": "ERROR", "message":"error"}`) fmt.Fprintf(w, "error") } func criticalHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(`{"severity": "CRITICAL", "message":"critical"}`) fmt.Fprintf(w, "critical") } func main() { http.HandleFunc("/stdout/", stdoutHandler) http.HandleFunc("/stderr/", stderrHandler) http.HandleFunc("/info/", infoHandler) http.HandleFunc("/warning/", warningHandler) http.HandleFunc("/error/", errorHandler) http.HandleFunc("/critical/", criticalHandler) http.ListenAndServe(":80", nil) }
このアプリケーションは、エンドポイントのパスに応じたログレベルのログを出力するように作ってあります。例えば「/info/」であればログレベルがINFO、「/error/」であればログレベルがERRORといった具合です。今回は検証ということで、INFO、WARNING、ERROR、CRITICALのログレベルのログを出力します。その他のStackdriverで使えるログレベルを確認したい方は、公式サイトのLogSevertiyのEnumsの項目をご覧ください。
また、検証において標準出力と標準エラー出力の場合、ログレベルがどうなるかを確認するため、それらのログを出力する「/stdout/」と「/stderr/」のパスを持ったエンドポイントも作ってあります。
次は、このアプリケーションのDockerコンテナイメージを作成するDockerfileを作っていきましょう。エディタを開き、リスト3の内容をコピーして「Dockerfile」のファイル名で保存してください。
FROM golang:1.9.2-alpine3.6 ADD ./server.go ./ RUN go build -o server CMD ["/go/server"]
このDockerfileはgo buildで先ほどのGoのファイルをビルドし、コンテナ起動時にビルドしたアプリケーションを起動するように設定したものです。
それでは、このDockerfileをbuildしてContainer Registryにpushしましょう。
$ docker build -t gcr.io/{プロジェクト名}/my-api:logtest . $ gcloud docker -- push gcr.io/{プロジェクト名}/my-api:logtest
次に、このアプリケーションをGKEにデプロイしましょう。エディタを開き、リスト4の内容をコピーして「my-api-logtest.yaml」のファイル名で保存してください。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-api-logtest spec: replicas: 1 template: metadata: labels: app: my-api version: logtest spec: containers: - name: my-api-logtest image: gcr.io/{プロジェクト名}/my-api:logtest #先ほどpushしたイメージを指定(1) ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-api-logtest spec: type: ClusterIP ports: - protocol: TCP port: 80 targetPort: 80 name: http selector: app: my-api version: logtest
コンテナのイメージを指定している(1)の箇所は先ほどpushしたイメージに合わせて変更してください。
それではデプロイしていきましょう。
$kubectl apply -f my-api-logtest.yaml
デプロイが完了したら、curlコマンドでアプリケーションをたたいてみましょう。
$curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/info/
これで、INFOのログレベルを持ったログが出力されました。
では実際にStackdriverのLoggingのページに行って、INFOのログレベルのログが出力されたかを確認しましょう。手順は以下の通りです。
最初にGCPのコンソールからStackdriver Loggingのページにアクセスします。次にログのページに移動して、ログビューアのプルダウンメニューから[GKEコンテナ>{クラスタ名}>{default(ネームスペース)}]を選択してください。
次にすべてのログのプルダウンメニューから「my-api-logtest」を選択して[OK]を押してください。
これで、先ほどデプロイしたアプリケーションのログが確認できるはずです。
この画像を見ると、ログのメッセージが「info」でseverityが「INFO」になっていることが確認できると思います。他にも以下のcurlコマンドでアプリケーションのエンドポイントをたたくと、それに応じたログが出力されログビューアで確認ができるので試してみてください。ちなみにログがStackdriverに反映されるまでに多少ラグがあるので注意してください。
$curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/warning/ $curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/error/ $curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/critical/ $curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/stdout/ $curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/stderr/
warning、error、criticalはエンドポイントのパスと同じログレベルのログを出力されるはずです。stdout(標準出力)とstderr(標準エラー出力)はseverity(ログレベル)の指定はしてませんが、stdoutの方はINFOで、stderrはERRORのログレベルになります。
2.ログレベルがエラー以上のログを検出する指標を作成する。
次に指標を作成していましょう。指標は先ほどのログビューアのページから作成することができます。プルダウンメニューからログのレベルを「エラー」に変更し、左上の[指標を作成]をクリックしてください。
指標エディタが開くので、適当な名前を入れ[指標を作成]を押せば完了です。
指標を作成すると「ログベースの指標」のページに遷移します。このまま続けて、この指標を元にしたアラートを作成していきましょう。
先ほど作成した指標が[ユーザー定義の指標]の下に表示されているので、その右端の丸が3つ縦に並んでいるアイコンをクリックすると[指標に基づいて通知を作成する]という項目が出てきます。それをクリックをすると「Add Metric Threshold Condition」のページに遷移するので、「Configuration」の下の構成を変更していきましょう。まず「CONDITION」を「above」に「THRESHOLD」を「0.001」に「FOR」を「1 minute」にします。これは「1分間以上、0.001以上のエラーログが発生した場合」という条件になります。
次に「RESOURCE」を「gke_container」に変更してください。正しい設定ができてエラーログがあれば、下の画像のように発生したエラーログによって山ができたグラフが確認できるはずです。
Note
もし、エラーログがグラフに反映されていなければ、グラフの[TIME]を変更するかcurlコマンドでエラーのエンドポイントをたたいてエラーログを出力してみてください。StackDriverのロギングはログが発生してから実際に反映されるまで多少ラグがあります。そのため、エラーログが検出されない場合は少し間を開けてください。
確認ができたら[Save Condition]を押して保存しましょう。保存すると「Create new alerting policy」というアラートポリシーの画面に遷移するので、このまま[Save Policy]を押してアラートを保存しましょう。
右に表示されている「OPEN」が現在発生しているアラート、「ACKNOWLEDGED」が確認済みのアラート、「RESOLVED」が解決済みのアラートです。
最後に、実際にアラートが発生した時の挙動を確認しましょう。アラートポリシーの条件に引っかかるように、curlコマンドを間隔を開けて2回たたきます。
$curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/error/ && sleep 55 s && curl --resolve dev.app.io:80:{ingress-ip} http://dev.app.io/versions/logtest/error/
しばらくしてからアラートポリシーの一覧画面にアクセスすると、OPENが1以上になっていることが確認できると思います。
ちなみにAlertingから「Incident」のメニューを選択することで、OPENになっているアラートを一覧で確認できるようになっています。
OPENになったアラートはアラートポリシーの条件を満たさなくなると、自動的にRESOLVEDになります。
最後に
今回はアラートの設定とアプリケーションのログの設定ついて解説をしました。アラートの設定はアプリケーションを運用していく上で欠かせないものです。ぜひ試してください。