ようへいの日々精進XP

よかろうもん

2020 年 06 月 20 日 (土)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 夕方, 山王公園を 30 分スロージョッグ (3 周)
  • 背中の痛みは一番酷い時を 10 としたら 4 くらい, 朝からこの痛みだったので何が原因なんだろう, 明日はウォークに留めておく

ギョーム

  • お休み

ディナー

奥さんが頑張って巻き寿司 (細巻き) を大量に作ってくれた. 初めて細巻きで試行錯誤な感じで大変だったけど美味しゅうございました.

ブログのテーマをいじった

tl;dr

このブログのテーマは Hatena Blog のオフィシャルテーマを色々と試してきたけど, なかなかしっくりとくるテーマがなくて試行錯誤していたところ, CSS をいじることでやっとしっくりきたのでメモっておく.

テーマ

テーマは Report というテーマ.

blog.hatena.ne.jp

シンプルでとても良いんだけど, 記事本文を書く幅が狭いので, 以下の記事を参考に CSS で広げた.

www.sukinamonote.com

実際に利用した CSS は以下の通り.

/* <system section="theme" selected="report"> */
@import "/css/theme/report/report.css";
/* </system> */
#container {
width: 1080px; /* 全体の幅 */
margin: 0 auto; /* 真ん中に表示 */
}
#wrapper {
width: 820px; /* 記事部分の幅 */
float: left; /* 記事を左に表示 */
}
#box2 {
width: 200px; /* サイドバーの幅 */
float: right; /* サイドバーを右に表示 */
font-size: 14px; /* 文字の大きさ */
} 

CSS はよく解っていないので, 上記の記事からコピッペして width の値をチョコチョコとプレビューしながら調整する感じ.

いい感じ

適用前と適用後の違い.

適用前.

f:id:inokara:20200620230426p:plain

適用後.

f:id:inokara:20200620230440p:plain

だいぶん横幅が広がった.

しばらくはこれで.

2020 年 06 月 19 日 (金)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 朝, 山王公園を 2 周
  • 夕方, 奥さんと山王公園 1 周
  • 背中の痛みは一番酷い時を 10 としたら 1 くらい, むしろ肩こり, 背中のこりが辛い

ギョーム

  • GKE (Kubernetes) の Pod のオートスケーリングを設定してみた
  • RabbitMQ を Terraform で操作したり
  • 検証環境実装

ディナー

鰤の塩焼き, これは下ごしらえが素晴らしくて臭みがなくとてもジューシー. ゴーヤチャンプルーは豚バラではなくベーコンで仕上がっていてとても美味しゅうございました.

2020 年 06 月 18 日 (木)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 夕方山王公園 2 周 30 分くらいジョッグが出来た!
  • 背中の痛みは一番酷い時を 10 としたら 1 くらい, むしろ肩こり, 背中のこりが辛い

ギョーム

  • 社内検証環境をエイヤで作った, Github Actions に本格的に手を出した
  • ECS の Service を操作するコマンドラインツールを Go で書いた, やりたいことをシュッと Go で書けるようになってきて嬉しい (💩コードなんだけど...orz)
  • GKE の監視とか AutoScaling について調べた

ディナー

最近のお気に入り, トンカツ. 下味がしっかりしているので何もつけなくても十分美味しいけど, 今日は大根おろしとポン酢を少しずつ付けて食べると豚の脂を全く感じないくらい軽く食べることが出来た. 美味しゅうございました.

2020 年 06 月 17 日 (水)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 朝は山王公園 2 周, 業務後に奥さんと山王公園を 1 周
  • 背中の痛みは一番酷い時を 10 としたら 1 くらい

ギョーム

  • バタバタした一日で, やりたかったことの進捗は 2 くらいで辛い

ディナー

かぼちゃのスープが濃厚で美味しかった!ご飯も炊きたてでこれだけでおかずは要らない感じだった. いつも奥さんには食事に気を遣ってもらって本当に有り難い.

2020 年 06 月 16 日 (火)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 朝, 山王公園を二周走ることが出来た!
  • 夕方, 奥さんと山王公園を一周散歩
  • 背中の痛みは一番酷い時を 10 としたら 1 くらい, 朝, 走った後も大きな痛みがなくて良かった

ギョーム

  • 早朝作業
  • kubectl patch と格闘してた

ディナー

鶏もものソテー, もうちょっと皮がパリパリであれば 200 点だったけど, ジューシーで美味しゅうございました. お得意の生姜ご飯は炊きたてで, これまた美味しゅうございました.

2020 年 06 月 15 日 (月)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 朝, 仕事後に奥さんと山王公園を散歩
  • 背中の痛みは一番酷い時を 10 としたら 3 くらい (昨日は 2 だったけど, 朝から痛みがあった

ギョーム

  • なんだかバタバタした感じで収集力に欠けた
  • 優先度を都度コントロールしながら捌いていく
  • デスクよりも奥さんの弾かずのピアノ部屋がめっちゃ風が通って涼しかったので, そこで終日スタンディング作業

ディナー

奥さんはあまり納得出来ていなかったようだけど, サツマイモのスープがとても美味しかった. あと, タコとニラのピリ辛和えはお酒をちゃんと飲めるようになったら, 是非, おつまみとして出してもらいたいくらい癖になる.

ngx_mruby でリダイレクト実装が 256 倍捗ったのでメモ

tl;dr

とあるサービスの移行作業で 200 個くらいのリダイレクト処理を ngx_mruby で実装したのでメモしておきます.

ngx_mruby とは

github.com

matsumotory さんが実装された Nginx に組み込むことで, Nginx の各種イベントをフックして mruby コードを実行することが出来る OSS です. Apache でも同様に mruby を実行出来る mod_mruby も同じく matsumotory さんによって実装されています.

リダイレクト案件

実はシンプル

今回のリダイレクトは特に複雑なことはなく, A サイト (https://A/path/100) を B サイト (https://B/2778425522) にリダイレクトをかけるだけです. ただし, リダイレクト元とリダイレクト先でパスの名前には関係性は無い為, リダイレクト 1 件毎に, リダイレクト元とリダイレクト先を記述していくことを検討しました. また, このような場合, 以下のように Nginx の rewrite を利用することで対応出来そうです. (他にも手法があるかもしれません)

nginx.org

以下のように, リダイレクト先が三件くらいまでなら, まあ, なんとか頑張れると思いましたが...

server {
  listen 80;
  server_name A;

  rewrite ^/path/100$ https://B/2778425522$1 permanent;
  rewrite ^/path/101$ https://B/5499644550$1 permanent;
  rewrite ^/path/102$ https://B/0739584639$1 permanent;
}

ところが,今回はリダイレクト対象が csv で 200 件近く渡されました.

さて, どうしようか

先述の通り, rewrite 文を 200 個くらい並べるのは現実的ではありません. また, 今後, リダイレクト設定の追加や削除が想定される場合には, リダイレクトの管理は CSV に統一しておいたほうが良さそうです.

以下はリダイレクト元とリダイレクト先が記述された CSV ファイルのサンプルです.

/path/to/100,https://example.com/1483465573
/path/to/101,https://example.com/9009130268
/path/to/102,https://example.com/2431394607
...
/path/to/199,https://example.com/4117255063
/path/to/200,https://example.com/8894250467

ここで, ngx_mruby の登場です.

戦略として, CSV ファイルを読み込んでおいて, リクエストパスと照合して, 一致したら Location にリダイレクト先の URL を設定してステータス 301 を返すようにしたいと思います.

Nginx の設定

以下は Nginx の設定です.

user daemon;
daemon off;
master_process off;
worker_processes 1;
error_log stderr notice;
#access_log /dev/stdout;

events {
    worker_connections  1024;
}

http {
    map $http_user_agent $log_ua {
        ~ELB-HealthChecker 0;
        default 1;
    }

    access_log /dev/stdout combined if=$log_ua;
    server {
        listen 80;

        location ~ ^/path/to/.*$ {
            mruby_content_handler /usr/local/nginx/hook/redirects.rb;
        }
    }
}

/path/to/xxxx でアクセスされた場合, mruby_content_handler で指定された mruby コードを実行するようにしています. この mruby コードで CSV ファイルを読み込み, パスのチェック, リダイレクト処理を実行します.

mruby コード

以下は mruby のコードです.

# /usr/local/nginx/hook/redirects.rb
r = Nginx::Request.new

redirect_csv = '/usr/local/nginx/conf/redirects.csv'
hash = {}
begin
  File.open(redirect_csv, 'r') do |f| 
    while l = f.gets
      key, value = l.chomp.split(',')
      hash[key] = value
    end
  end
rescue
  Nginx.errlogger Nginx::LOG_CRIT, "Could not read redirect list!!!"
  Nginx.return Nginx::HTTP_INTERNAL_SERVER_ERROR
end

key = r.uri
if hash[key]
  Nginx.errlogger Nginx::LOG_INFO, "Redirect working! SRC: #{key} DST: #{hash[key]}"
  Nginx.redirect(hash[key], Nginx::HTTP_MOVED_PERMANENTLY)
else
  Nginx.errlogger Nginx::LOG_NOTICE, "No redirect target. Move to https://example.com."
  Nginx.redirect("https://example.com", Nginx::HTTP_MOVED_PERMANENTLY)
end

思ったよりもシンプルに書くことが出来て驚いています.

  • Nginx::Request クラスにはリクエスト情報が含まれてて, インスタンスメソッドで各種情報 (スキーマやメソッド, パス等) を取得出来ます
  • Nginx クラスはレスポンスを操作出来るメソッドが含まれていて, returnredirect 等のクラスメソッドを利用しています
  • HTTP ステータスは定数として用意されていますので, 今回は 301 を返したいので Nginx::HTTP_MOVED_PERMANENTLY を利用しています

詳細はドキュメントをご一読下さい.

github.com

ちょっと動かしてみた

以下のリポジトリの Dockerfile を利用させて頂きました.

github.com

mruby コードと Nginx の設定, CSV ファイルを用意するだけで動作確認することが出来ました.

$ git clone https://github.com/matsumotory/docker-ngx_mruby.git
$ cd docker-ngx_mruby
$ vim docker/conf/nginx.conf # 先述の内容を記述
$ vim docker/conf/redirects.sample.csv
/path/to/100,https://yahoo.co.jp/
/path/to/101,https://google.co.jp/
$ vim docker/hook/redirects.rb # 先述の内容を記述
$ docker build -t ngx_mruby .
$ docker run -d -p 18080:80 ngx_mruby

コンテナを起動後, リクエストを投げてみます.

$ curl -s localhost:18080/path/to/100 -LI
HTTP/1.1 301 Moved Permanently
Server: nginx/1.15.12
Date: Sun, 14 Jun 2020 14:50:12 GMT
Content-Type: text/html
Content-Length: 170
Connection: keep-alive
Location: https://yahoo.co.jp/

HTTP/1.1 301 Redirect
Date: Sun, 14 Jun 2020 14:50:12 GMT
Connection: keep-alive
Cache-Control: no-store
Location: https://www.yahoo.co.jp/
Content-Type: text/html
Content-Language: en
Content-Length: 306

HTTP/2 200
content-length: 0
content-type: text/html; charset=utf-8
date: Sun, 14 Jun 2020 14:50:12 GMT
etag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
set-cookie: B=65eq4ktfece94&b=3&s=nd; expires=Wed, 15-Jun-2022 14:50:12 GMT; path=/; domain=.yahoo.co.jp
vary: Accept-Encoding
x-vcap-request-id: 268b7a41-fdfa-4ce9-4d52-770b9291ad90
age: 0
via: http/1.1 edge1801.img.bbt.yahoo.co.jp (ApacheTrafficServer [c sSf ])
server: ATS

レスポンスから yahoo.co.jp にリダイレクトされていることが判ります. また, 以下のようなログが記録されています.

172.18.0.1 - - [14/Jun/2020:14:50:12 +0000] "HEAD /path/to/100 HTTP/1.1" 301 0 "-" "curl/7.54.0"

いい感じです.

最後に

ngx_mruby についてはほぼ初めての利用となりましたが, とても簡単に大量のリダイレクトを処理することが出来そうでエンジニアリング魂が揺さぶられました. これからも機会があれば ngx_mruby をはじめ mruby をギョームで利用出来れば良いなと考えています.

2020 年 06 月 14 日 (日)

アクティビティ (今までの走行 (歩行) 距離)

https://pixe.la/v1/users/inokappa/graphs/fitbit-activity

Fitibit Charge2 のアクティビティから走行 (歩行) 距離を Fitbit Web API で取得して Pixela で草生やしている. 色が濃くなれば濃くなる程強度が高い (歩行, 走行距離が長い) ということで. 実装の詳細はこちら.

ジョギング

  • 朝, 山王公園を三周散歩 (二周は走ってみた), 夕方は奥さんと山王公園を一周散歩
  • 背中の痛みは一番酷い時を 10 としたら 2 くらいまで落ち着いてきた

ギョーム

  • お休み

ディナー

定番の手羽中の甘辛炒め, 茄子とししとうの南蛮漬け, オクラと茗荷のネバネバネーバとご飯との相性バツグンのおかずばかりで美味しゅうございました.

ECS タスクメタデータエンドポイントを使ったバッチ処理コンテナのリソースモニタリングツール kobanzame を作りました

追記 (2020/06/15) Container Insights は GA しています!

2020/06/14 現在はベータ版として提供されていますが

この記述は誤りで Container Insights は 2019 年 11 月には既に GA されておりますので, ここで訂正させて頂きます.

aws.amazon.com

確認不足で誤った情報を記述してしまい大変申し訳ございませんでした.

tl;dr

以前に以下のような記事を書きました.

inokara.hateblo.jp

この記事では, Fargate で動いているバッチ処理タスクの CPU 使用率やメモリ使用量のリソース情報を ECS タスクメタデータエンドポイントから取得し, バッチ処理タスクが終了したらリソース情報を集計してバッチ処理タスクのログに差し込む仕組みを紹介させて頂いています.

docs.aws.amazon.com

記事を書いてからもうすぐ一年が経過しようとしているところで, この仕組みのコードを夜な夜なコツコツと整理して gem 化したので紹介させて頂きます.

kobanzame

作ったもの

github.com

rubygems.org

Kobanzame = コバンザメ.

サイドカー的にバッチ処理が実行されるコンテナにくっついてリソースの情報を取得する様が, 大きなクジラにくっついてそのおこぼれ等を餌にしているコバンザメのようだったので命名しました.

仕組み

仕組み自体は以下のようなイメージです.

f:id:inokara:20200613223419p:plain

ECS タスクにサイドカーコンテナとして Kobanzame コンテナを追加します. Kobanzame コンテナは Batch Worker コンテナが動き続けている限り, タスクメタデータエンドポイントにアクセス (デフォルトで 1 秒毎) して Batch Worker コンテナの CPU 使用率とメモリ使用量を収集します.

Batch Worker コンテナが終了 (正常, 異常問わず) すると, CPU 使用率とメモリ使用量を集計して Batch Worker のログが出力されている CloudWatch Logs の Log Stream の最終行に差し込みます. (下図の通り.)

f:id:inokara:20200613224916p:plain

集計された情報は, 以下のようにテキストまたは JSON フォーマットで送信することが可能です.

# テキストフォーマット
REPORT TaskID: xxxxxxxx Duration: 10ms, Memory Used: 133.4MiB(ave)/200.621MiB(max), CPU Usage: 62.567%(ave)/90.3%(max)

# JSON フォーマット
{
  "report": {
    "duration": {
      "duration": 10,
      "unit": "ms"
    },
    "memory_used": {
      "average": 133.4,
      "max": 200.621,
      "unit": "MiB"
    },
    "cpu_usage": {
      "average": 62.567,
      "max": 90.3,
      "unit": "%"
    }
  },
  "task_id": "xxxxxxxx",
  "docker_name": "foo"
}

また, 前回は実装していなかったのですが, CPU 使用率とメモリ使用量を CloudWatch メトリクスにカスタムメトリクスとして記録するようにしています.

f:id:inokara:20200613225453p:plain

なんちゃってプラグインアーキテクチャ

現時点では, 集計情報は Batch Worker の Log Stream に差し込み, メトリクスは CloudWatch メトリクスのみに記録するようになっていますが, なんちゃってプラグインアーキテクチャになっている為, 必要に応じて, Slack や Datadog 等に送信することも可能です.

以下は雑に Slack チャンネルに通知した様子です.

f:id:inokara:20200614072724p:plain

使い方

設定ファイル

kobanzame は JSON で設定ファイルを書きます. 以下は設定例です.

{
  "container": {
    "name": "batch-worker",
    "check_interval": 1,
    "report_format": "json"
  },
  "metrics": {
      "name": "cloudwatch",
      "namespace": "Custom/Kobanzame"
  },
  "outputs": [
    {
      "name": "cloudwatch_logs",
      "log_group_name": "kobanzame-sample-dev-batch-worker",
      "log_stream_prefix": "batch-worker",
      "log_stream_name": "batch-worker-resource-statistics"
    }
  ]
}

以下に設定内容について簡単に解説させて頂きます.

container セクションには, 対象コンテナ名を指定します (「仕組み」にて掲載している図の Batch Worker を指しています).

Key Required Value Example description
name Yes batch-worker 対象コンテナ名を指定します
check_interval Yes 1 リソース情報取得する間隔を指定します
report_format Yes json 集計情報を出力するフォーマットを指定します. JSON 以外に Text や CSV も指定可能です

metrics セクションには, リソース情報を送信する CloudWatch のネームスペースを指定します (現在は CloudWatch のみに対応しています).

Key Required Value Example description
name Yes cloudwatch 取得したメトリクスを送信します (現在は CloudWatch のみ対応)
namespace Yes Custom/Kobanzame CloudWatch メトリクスのネームスペースを指定します

outputs セクションには, リソースの集計情報の送信先を指定します.

Key Required Value Example description
name Yes cloudwatch_logs 集計した情報を CloudWatch Logs に送信します
log_group_name Yes kobanzame-sample-dev-batch-worker 送信する Log Group 名を指定します
log_stream_prefix No batch-worker 送信する Log Stream 名を指定します
log_stream_name No batch-worker-resource-statistics 送信する Log Stream 名を指定します

log_stream_prefix を指定した場合には, Batch Worker が出力する Log Stream のプレフィックスを指定すると, Lambda ファンクションの実行結果のようにログが出力されています. また log_stream_name を指定した場合には, 集計結果のみが指定した Log Stream に集積されます.

尚, 設定ファイル名自体は任意で OK です.

実行

設定ファイルを setting.json というファイル名で作成した場合, 以下のように kobanzame を実行します.

$ kobanzame --config=setting.json

その他のオプションは以下の通りです.

$ kobanzame --config=setting.json
Usage: kobanzame [options]
    -c, --config PATH                config file path (default: kobanzame.json)
    -d, --daemonize                  enable daemonize (default: false)
    -p, --pid-file PATH              pid file path (default: kobanzame.pid)
    -l, --log-file PATH              log file path (default: STDOUT)
    -D, --debug                      start with debug mode (default: false)

Example

kobanzame を実装するにあたって利用した各種ファイル (Fargate 等を構築する Terraform コードや Run Task をラップしたシェルスクリプト等) をリポジトリexample フォルダに置きました.

f:id:inokara:20200614123313p:plain

参考

今回, kobanzame を実装するにあたって, 以下の OSS ツールを参考 (利用) させて頂きました.

github.com

serverengine はその名の通り, Ruby でサーバーを実装するにあたって必要な PID ファイルの作成やログファイルの出力, 安全にプロセスを停止する為の仕組みが提供されていて, あの fluentd でも利用されているライブラリです. serverengine については, udzura さんの以下のブログ記事も参考にさせて頂きました.

udzura.hatenablog.jp

kobanzame には緩い感じのプラグイン機構が備わっていて, 集計結果の出力先やメトリクスの送信先をコア部分に影響が無いように追加することが可能です. このなんちゃってプラグイン機構のヒントと実装は sonots さんの alerty を参考にさせて頂きました.

github.com

serverengine も fluentd も alerty も以前から存じ上げていましたが, 改めて kobanzame を実装するにあったて, ソースコードを読みましたが, 理解出来ているかは置いといて大変勉強になりました. 有難うございました.

それ, Container Insights で良いんじゃないのか

おっしゃるとおり

docs.aws.amazon.com

ちゃんと使えていないのですが, コンテナのリソースを収集して CloudWatch メトリクスで確認出来る Container Insights が東京リージョンでも利用出来ます. 2020/06/14 現在はベータ版として提供されていますが, ECS のクラスタ毎, サービス毎, タスク毎にコンテナのメトリクスを確認出来ますし, 当然 kobanzame では取得出来ないメトリクスも確認出来るので, ちゃんとコンテナを監視したい場合には Container Insights を利用することをオススメしたいと思います.

じゃあ, なぜ, 俺は kobanzame を作ったのか

こちら にも書いたように, 以下のような目的がありました. 当時は Container Insights は GA されていなかったりして, Fargate で動いているコンテナのリソース状況を 手軽 に把握する術を模索していました. (Datadog や Mackrel 等のツールも検討しましたが, これらのツールどのようにコンテナのリソースを収集しているかを調べるうちに自分で実装していたという感じです.)

  • バッチ処理でどのくらいの CPU やメモリリソースが使われているのかざっくりと把握したい
  • 今後のコンテナリソースサイズを検討する際の参考にしたい

そして, バッチ処理のログ出力に Lambda ファンクションのログ出力のようなリソース使用状況を出力したかったことも理由です. 実際にログに出力して, そのログを Elasticsearch に転送して可視化したりして, バッチ処理の改善に役立てることが出来ていると思います.

以上

ECS タスクメタデータエンドポイントを使ったコンテナのリソースモニタリングツール kobanzame を紹介させて頂きました. 多くの人に使って頂きたいというわけではありませんが, 同じような悩みを持たれている方の課題解決に少しでもお役に立てれば幸いです.