ようへいの日々精進XP

よかろうもん

初老丸を支えた技術 2018 〜 アイレットにさよならするのは辛いけど 〜

これは

qiita.com

初老丸アドベントカレンダー 2018 の最終日, 25 日目の記事でございます. 初老丸アドベントカレンダー, だいぶん歯抜け状態になっていてコンプリート出来ていないんですが, とりあえず, 時間を見つけて年内には全ての記事を書ければなーと考えております.

さて

ここ数年, アドベントカレンダーを書くようになり, 最終日の 25 日の記事は「初老丸を支えた技術」と題して, その一年の振り返り等を書いてきましたが, 今年は年末でアイレットを退職にすることになりましたので, アイレットの思い出とこれからの初老丸について少しだけ書いてみたいと思います.

アイレットに「さよならするのは辛いけど」ということで.

www.youtube.com

愛・愛・アイレット

リモートワークがしたい

こんなつぶやきを SNS でしたら, @yoshidashingo に拾って頂いたのが, 愛・愛・アイレットに入社するきっかけでした. @yoshidashingo さんには, 入社後も色々とお気遣い頂いて本当に感謝していますし, 奥さんの次くらいに愛しています.

そして, 初出社の日に会社に誰も会社に居なくて, 一番乗りだったというのが印象に残っています. また, クロスという犬社員が先輩に居て, 事あるごとに吠えられ, 仕事でミスると噛まれたりしたことはとても良い思い出です. そのクロスパイセンですが, すでに他界されていますが, パイセンのキリッとした顔と甲高い雄叫びは今も忘れません. 本当に有難うございました.

挫折

2014 年の 9 月から福岡でリモートワーク始めましたが, 自分のスキルの低さと降り掛かってくるタスクのバランスを保つことが出来ずに心と体のバランスまで崩してしまい, 三ヶ月間休職を頂いておりました. 休職に伴い, 当時のチームメンバーには多大な迷惑を掛けてしまったことを今でも反省しています. ただ, 三ヶ月も休職を頂いていながら, 復職の際には何事もなかったように迎えてもらえたことに本当に感謝しています.

年末の国民的なイベントとの関わり

アイレットでは AWS を使ったインフラ構築や運用, 保守の仕事に携わっていました. その中でも特に印象に残っているのが, 年末の某国民的なイベントに関わらせて頂いたことです. ただ, このイベントにおいては, アクセスログを集計するシステムの実装から構築, 運用までをワンストップで行っていました. 年末の国民的なイベントの裏側で, ある程度設計されていたシステムだったとは言え, アプリケーションを設計して実装し, そのアプリケーションを動かすインフラを構築し, 運用するという仕事を任せてもらえるのは本当にエキサイティングでした.

この仕事を任せてもらった後, 少しずつですが, 仕事に対する自信も持てるようになってくると共に, 目の前の課題をある程度の設計とともにコードを以て解決することの喜びを感じるようになりました.

チームメンバーと家族に支えられたリモートワーク

約 4 年間, リモートワークを行って感じたのは, 二点. 一点目は, ベースとなるオフィス (アイレットだと東京虎ノ門オフィス) のチームメンバーの支え無くしてリモートワークは成し得なかったということ, もう一点は家族の理解が必要ということです.

これだけインターネット環境が整い, リモートワーク (テレワーク) という言葉が当たり前のように飛び交うようなご時世でも, 実際にリモートワークしてみると, ベースとのタイムラグや意思疎通が取りづらい状況はあると考えています (実際にそういうことは多々有りました). そんな時にリモートワーカーの助けになるのは, ベースとなるオフィスに常駐しているメンバーの理解とサポートだと考えています. 例えば, 特に用事がなくても Slack で声をかけてもらったり, 仕事の情報は早めに共有してもらったり等, きっとメンバーの皆さんのストレスは大きかったのではと考えています.

また, 自宅で仕事をしていると, 家族と過ごす時間と仕事の時間をうまく区切ることが出来ない状況が多くありました. サーバーの障害が復旧しても, その裏で家庭内の障害が発生してしまい, そちらの障害復旧の方が大変だったことが良くありました. 今では笑い話になっていますが.

産業革命

ここ最近では, インフラの仕事よりも, アプリケーションを作るような仕事をさせて頂いて, PythonPHP, Vue.js をなんとか切り貼りしながらアウトプットしてきました. その中でどの言語, どのアプリケーションにおいても, テストコードを書いて, アウトプットの品質を担保する必要があるということを学べたことが貴重でした. また, 他のメンバーとともにアプリケーションを実装する際の作法等も学ぶことが出来ました. 体育大学を出て, なんか良くわからないまま IT ベンチャーにジョインして, なんちゃってインフラエンジニアとしてプログラミングとはほぼ無縁だった自分にとってこれらを学べたことは俺的産業革命に匹敵する出来事でした.

また, awspec との出会いも, 俺的産業革命でした. 当然, awspec のコンセプトや実装についても目がさめるような衝撃を与えてくれましたが, awspec の開発自体に携われたことが, 大きな自信になり, Ruby をちゃんと勉強しなければと強く感じさせてくれた出来事でした. awspec の作者である, @k1low さんには, 手取り足取り awspec の実装について教えて頂いて本当に感謝しています.

ユーザーをもうちょっとだけ身近に感じたい

俺的産業革命のうねりの中で, アイレットに対して, 実家のようなすごく居心地の良い雰囲気を感じていました. 自分の場合, リモートという環境でベースのメンバーよりもある程度自由度の高い仕事のやり方が出来ていたからかもしれません. そのような居心地の良い環境の中で, これからの自分がエンジニアとしてどの程度成長出来るのか考えていました. また, お客様の環境をお預かりして構築, 運用している中で, その環境の先にいるエンドユーザーに近い環境で仕事をしたいという思いがありました. そんな時に, 福岡の地場で登山者向けのアプリを提供している YAMAP さんからお声がけ頂きお話をさせて頂きました. YAMAP は登山者向けアプリのパイオニアであること, エンドユーザーとの交流イベント等を定期的に開催していること, システムが Ruby で動いている!!等, ここらでイッチョという思いに至り, アイレットを卒業して YAMAP に入学することを決めました.

Hello YAMAP

自社サービスを支える技術

YAMAP は電波が届かない山中でも, スマフォの GPS で現在地と登山ルートを提供する登山アプリで, 登山の記録や写真が活動記録として日々投稿されるので, 山の情報収集や全国の登山好きと交流することも出来る, 日本最大の登山・アウトドアプラットフォームです. そのプラットフォームを運用するインフラの構築や運用保守がメインのミッションとなりますが, インフラの構築運用に留まらず, インフラの上で稼働する様々のアプリケーション (サービス) に対して良い意味でお節介を焼けるようなエンジニアを目指していきたいと思います. また, サービスがより多くのユーザーに使われる為に何をすべきかについて, 技術的な観点から包括的に考えて実装出来るように, 既存のメンバーの協力を頂きながら推し進めたいと考えています.

以上

上記の通りの通り, YAMAP さんでこれまで通り頑張ろうと思います. 駅伝で言うところの, 次の走者にタスキが渡されて, 眼の前に続く未知 (道) に向かって走り出すタイミングなだけで, 自分という人間は何も変わらず, ただひたすらに走るだけだと考えていますので, 今後共, 生暖かい目で見守っていただけると幸いです.

まずは, この 4 年半, お世話になりましたアイレットの皆さん, お客様, 大変お世話になりました. 色々と至らない部分が多々ありましたが, 皆さんのおかげでここまでやってこれたと考えています. これからも走りつづけることで少しずつでも恩返ししたいと思います.

そして, JAWS-UG 福岡の皆さんや, 各種コミュニティメンバーの皆さん, 引きこもりな自分をいつもやさしく受け入れてくれて本当に有難うございました. 今後共, 宜しくお願い致します.

最後に奥さん, なんか小学生がそのまま大きくなったような自分をいつも支えてくれて本当に有難う. これからも小学生のままかもしれないけど, 宜しく頼む. ありがとう.

次の回まで, ごきげんよう.

2018 年 12 月 24 日 (月)

ジョギング

  • 岩国市内を 35 分くらい
  • ホテルから岩国錦帯橋空港までぐるっと周った
  • 左足の踝周りは相変わらずの痛み, ただ, 昨晩, 林田くんに施術してもらった影響か, 筋肉の使い方少し変わったような気がする

日課

  • お休み

錦帯橋

岩国名所として名高い, 錦帯橋, 岩国城を林田家と共に巡る.

錦帯橋。アーチの部分の実装が精巧で震えた。

岩国城。

岩国城の後は名物瓦そばを食べる. 熱々の瓦の上で少し焦げたパリパリの部分を甘辛いタレにつけて食べる. とても美味しかった.

往復 500 キロ以上

だいぶん走ったよなあ. MINI さん, お疲れ様でした.

2018 年 12 月 23 日 (日)

ジョギング

  • 移動の為, お休み

日課

  • お休み

岩国旅行

幕末の #ひょっこりはん

  • 奥さんの友人夫婦, 浪速の林田夫婦とともに岩国旅行をする為, ミニさんを走らせて山口県岩国市までの小旅行
  • 夏場はすごく賑わったであろう, 誰もいない滝壺や川等をドライブした後, 山賊料理を食べに行く
  • 岩国市内のホテルにチェックインして, 岩国市内の夜を満喫からの部屋飲み
  • とても楽しい一日だった

2018 年 12 月 22 日 (土)

ジョギング

  • 山王公園往復
  • 懸垂 5 回
  • やっぱり, 左足踝, 左足の甲の外側...長引くな...

日課

  • お休み

睡魔

  • 遅い朝ごはんを食べた後, 急激な眠気でお昼寝を 2 時間ほど...
  • 睡魔せん

豚ステーキ

  • 自宅近くの看板が出ていないお店で豚ステーキを食べた
  • メニューも豚ステーキとビールの 2 品のみという, こだわりを感じるお店
  • ジューシーでとても美味しかった, 1000 円也

AWS CodeBuild のビ・ビ・ビルドを実行したり, ビルドのステータスを確認出来るコマンドラインツールを作ってみたので, 何卒, ご容赦下さい

tl;dr

手元の端末で Docker ビルドするのって, Docker の環境を手元の端末に用意したりする必要があります. その環境を用意するにあたって, MacWindows 等の環境依存が発生することがあり, 結局, Docker という基盤の上に乗っけてしまえば環境に依存しないという Docker のメリットを殺してしまうよなーと思う機会がありました.

いっそのこと手元の端末での Docker ビルドは止めて, AWS の CodeBuild や CircleCI 等の CI/CD 環境にお任せすればいいんやないかな...その場合, 出来るだけ簡単に (コマンド一発か二発で) ビルド出来るようにしたいよなーと思ったので, AWS CodeBuild に特化しちゃうけどコマンドラインツールを作ってみました.

bibuild

これ

github.com

bibuild という名前です. 名前は星野源さんのシングル「ドラえもん」の初回特典 DVD に収録されていたらしい「ViVi Video」からインスピレーションを得ました.

www.hoshinogen.com

尚, bibuild はソースコードは S3 に放り込むことを前提としていて, GithubAWS CodeCommit には対応していません. すいません.

bibuild で出来ること

  • 指定したディレクトリに入っているソースコードを zip で固めます
  • zip で固めたソースコードを S3 にアップロードします
  • 指定した CodeBuild プロジェクトのビルドを実行します
  • 指定したビルドの状態を確認します

使い方

インストール

インストールはリリースページがダウンロードして頂いて, パスの通ったディレクトリにバイナリを放置して下さい. 強いて言えば, 念の為, 実行権限を付与して下さい.

chmod +x ~/bin/bibuild

尚, CodeBuild にアクセスするにあたって, 適切な権限が付与されたクレデンシャルを用意する必要がありますので, 合わせて用意しましょう. この記事では, direnv を利用して, AWS の Profile 名を環境変数にセットしています.

export AWS_PROFILE=washino-profile
export AWS_REGION=ap-northeast-1

例えば

以下のようなディレクトリ構成を用意します.

$ tree -L 1 .
.
├── config.yml
├── docker
└── terraform

2 directories, 1 file

terraform ディレクトリは気にしないで下さい. config.yml は bibuild で利用します. config.yml の内容は以下の通りです.

default:
  source_bucket: "codebuild-docker-build-project-sources"
  project_name: "codebuild-docker-build-project"
  source_key: "source.zip"
  directory: "docker"

尚, 今回は Docker イメージをビルドして ECR に push するようなプロジェクトをすでに CodeBuild に作成しているという体 (てい) でいきます. docker ディレクトリ以下に Dockerfile と buildspec.yml を用意しています.

$ tree -L 1 ./docker
./docker
├── Dockerfile
└── buildspec.yml

0 directories, 2 files

ちなみに, Dockerfile は以下のような内容です.

$ cat docker/Dockerfile
FROM ruby:latest
RN echo "Hello World"

あえて, エラーを発生させたいので, 構文エラーをしちゃっています.

docker ディレクトリ以下のファイルを source.zip というファイル名で圧縮して S3 バケットにアップロードし, CodeBuild プロジェクトにてビルドを実行するところまでを bibuild がやってくれることになります.

実際にやってみる

実際に bibuild を使って Docker イメージをビルドしてみたいと思います.

$ bibuild -version
0.0.2

以下のように -zip-put-build フラグを付与することで source.zip を生成, S3 バケットにアップロード, CodeBuild プロジェクトにてビルドをキックという処理を行います. フラグを個別に指定することで, 指定した処理のみを行わせることが出来ます.

$ bibuild -zip -put -build

以下のように出力されます.

✅  ソースファイルの zip 圧縮に成功しました.
✅  ソースファイルの S3 へのアップロードに成功しました.
✅  ビルドを開始しました. Project Name: codebuild-docker-build-project, Build ID: codebuild-docker-build-project:bc9be7f1-e9a7-4397-a5c5-3c9405cb1ccb

次に, ビルドの状態を確認してみます. bibuild に -stat=ビルド ID を指定すると, 以下のようにビルドの状態を確認することが出来ます.

$ bibuild -stat=codebuild-docker-build-project:bc9be7f1-e9a7-4397-a5c5-3c9405cb1ccb
Build ID: codebuild-docker-build-project:bc9be7f1-e9a7-4397-a5c5-3c9405cb1ccb
Build Status: FAILED
+------------------+---------------+---------------------+---------------------+
|       名前       |  ステータス   |      開始時刻       |      終了時刻       |
+------------------+---------------+---------------------+---------------------+
| SUBMITTED        | ✅  SUCCEEDED | 2018-12-22 09:56:02 | 2018-12-22 09:56:03 |
| QUEUED           | ✅  SUCCEEDED | 2018-12-22 09:56:03 | 2018-12-22 09:56:04 |
| PROVISIONING     | ✅  SUCCEEDED | 2018-12-22 09:56:04 | 2018-12-22 09:56:25 |
| DOWNLOAD_SOURCE  | ✅  SUCCEEDED | 2018-12-22 09:56:25 | 2018-12-22 09:56:26 |
| INSTALL          | ✅  SUCCEEDED | 2018-12-22 09:56:26 | 2018-12-22 09:56:26 |
| PRE_BUILD        | ✅  SUCCEEDED | 2018-12-22 09:56:26 | 2018-12-22 09:56:31 |
| BUILD            | ‼️   FAILED    | 2018-12-22 09:56:31 | 2018-12-22 09:56:32 |
| POST_BUILD       | ‼️   FAILED    | 2018-12-22 09:56:32 | 2018-12-22 09:56:32 |
| UPLOAD_ARTIFACTS | ✅  SUCCEEDED | 2018-12-22 09:56:32 | 2018-12-22 09:56:32 |
| FINALIZING       | ✅  SUCCEEDED | 2018-12-22 09:56:32 | 2018-12-22 09:56:34 |
| COMPLETED        | N/A           | 2018-12-22 09:56:34 | N/A                 |
+------------------+---------------+---------------------+---------------------+

あらー, 見事に BUILD フェーズで FAILED になっていることが判ります. 正常にビルドが終了するように Dockerfile を修正して, 再度, ビルドしてみたいと思います.

$ bibuild -zip -put -build
✅  ソースファイルの zip 圧縮に成功しました.
✅  ソースファイルの S3 へのアップロードに成功しました.
✅  ビルドを開始しました. Project Name: codebuild-docker-build-project, Build ID: codebuild-docker-build-project:aa626cb1-7395-4e9a-8910-aa85091853af

ステータスを確認してみます.

$ bibuild -stat=codebuild-docker-build-project:aa626cb1-7395-4e9a-8910-aa85091853af
Build ID: codebuild-docker-build-project:aa626cb1-7395-4e9a-8910-aa85091853af
Build Status: IN_PROGRESS
+--------------+---------------+---------------------+---------------------+
|     名前     |  ステータス   |      開始時刻       |      終了時刻       |
+--------------+---------------+---------------------+---------------------+
| SUBMITTED    | ✅  SUCCEEDED | 2018-12-22 10:00:13 | 2018-12-22 10:00:13 |
| QUEUED       | ✅  SUCCEEDED | 2018-12-22 10:00:13 | 2018-12-22 10:00:15 |
| PROVISIONING | N/A           | 2018-12-22 10:00:15 | N/A                 |
+--------------+---------------+---------------------+---------------------+

まだ, ビルド中のようですね.

$ bibuild -stat=codebuild-docker-build-project:aa626cb1-7395-4e9a-8910-aa85091853af
Build ID: codebuild-docker-build-project:aa626cb1-7395-4e9a-8910-aa85091853af
Build Status: SUCCEEDED
+------------------+---------------+---------------------+---------------------+
|       名前       |  ステータス   |      開始時刻       |      終了時刻       |
+------------------+---------------+---------------------+---------------------+
| SUBMITTED        | ✅  SUCCEEDED | 2018-12-22 10:00:13 | 2018-12-22 10:00:13 |
| QUEUED           | ✅  SUCCEEDED | 2018-12-22 10:00:13 | 2018-12-22 10:00:15 |
| PROVISIONING     | ✅  SUCCEEDED | 2018-12-22 10:00:15 | 2018-12-22 10:00:35 |
| DOWNLOAD_SOURCE  | ✅  SUCCEEDED | 2018-12-22 10:00:35 | 2018-12-22 10:00:36 |
| INSTALL          | ✅  SUCCEEDED | 2018-12-22 10:00:36 | 2018-12-22 10:00:36 |
| PRE_BUILD        | ✅  SUCCEEDED | 2018-12-22 10:00:36 | 2018-12-22 10:00:41 |
| BUILD            | ✅  SUCCEEDED | 2018-12-22 10:00:41 | 2018-12-22 10:01:15 |
| POST_BUILD       | ✅  SUCCEEDED | 2018-12-22 10:01:15 | 2018-12-22 10:01:16 |
| UPLOAD_ARTIFACTS | ✅  SUCCEEDED | 2018-12-22 10:01:16 | 2018-12-22 10:01:17 |
| FINALIZING       | ✅  SUCCEEDED | 2018-12-22 10:01:17 | 2018-12-22 10:01:19 |
| COMPLETED        | N/A           | 2018-12-22 10:01:19 | N/A                 |
+------------------+---------------+---------------------+---------------------+

おおー, 正常にビルドが完了したようです.

以上

俺のクソコードシリーズ, 第 N 弾である, bibuild をご紹介しました. 完全に俺得でしかないツールですが, コマンド一発で zip で圧縮して S3 にアップロードしてビルドまで実行してくれるので, docker build を叩くのとそれほど変わらない気軽さはあるかなあと思っています.

もし, よろしければ, お手元にダウンロード頂きましてお試し頂ければ幸いです.

2018 年 12 月 21 日 (金)

ジョギング

  • 山王公園往復
  • 懸垂 5 回
  • やっぱり, 左足踝周りが...

日課

  • お休み

今年も...

あと, 残すところ 10 日を切ったぞ...おい.

来週は

  • 火曜日, 水曜日とお休みを頂いて, 溜まっている手続きとかを済ませたい

2018 年 12 月 20 日 (木)

ジョギング

  • 左足のくるぶしの周りもだけど, 右足の甲にも強い痛みがあるのでお休み

日課

  • お休み

今年最後の JAWS-UG 福岡もくもく会

jaws-ug-kyushu.doorkeeper.jp

クラスメソッドさんの会議室をお借りしての開催. コアメンバーだけの参加だったけど, ワイワイ色々と話しが出来て楽しかった. 来年も宜しくお願いいたします.

夕飯

遅い夕飯は美人居酒屋にて.

おでんについて研究している。

Healthchecks.io チュートリアル

tl;dr

最近, Healthchecks.io という Web サービスを教えていただきました. SaaSだけではなく, 仕組み自体は OSS で提供されていて Docker でサクッと試すことが出来ます.

healthchecks.io

github.com

Healthchecks.io とは

シンプル

Django で書かれた Cron ジョブをモニタリングするツールです. どのようにモニタリングするかと言うと, サイトにも掲載されているように Cron ジョブが終了したら, Healthchecks.io から払い出される HTTP エンドポイントに対してリクエストを投げることで Cron ジョブが正常に終了することをモニタリングします.

以下は, サイトのトップページに掲載されている Cron 定義です.

# m h dom mon dow command
  8 6 *   *   *   /home/user/backup.sh && curl -fsS --retry 3 https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > /dev/null

backup.sh が正常に終了しなかった場合, curl -fsS --retry 3 https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > /dev/null が実行されないことになります.

ドキュメントの中でこの URL は Ping URL と呼ばれています.

Healthchecks.io は Ping URL にリクエストを送信する度に, そのリクエストを記録し, 監視対象 (この例で言うと backup.sh) の Ping の値を更新します. 最後に受信した Ping から設定した時間 (期間) が経過すると, その監視対象は遅延しているとみなされ, Healthchecks.io は「猶予期間」を待ってから Ping がない場合にはアラートを送信します. 以下, 期間と猶予期間を設定する Web ユーザーインターフェースです.

f:id:inokara:20181219001224p:plain

上記の設定例だと, Ping は 30 分毎に送信され, 猶予期間は 30 分となり, 30 分 + 30 分 = 60 分間 Ping の送信が無い場合にはアラート送信されます. この設定は監視対象毎に設定が可能となりますので, 1 つの Cron ジョブ毎に設定が可能ということになります.

尚, 以下のように Ping URL に /fail を追加することで, 監視対象の障害発生を通知することが出来ます. 以下はドキュメントより引用した Python コードです.

import requests
URL = "https://hc-ping.com/your-uuid-here"

def do_work():
    # Do your number crunching, backup dumping, newsletter sending work here.
    # Return a truthy value on success.
    # Return a falsy value or throw an exception on failure.
    return True

success = False
try:
    success = do_work()
finally:
    # On success, requests https://hc-ping.com/your-uuid-here
    # On failure, requests https://hc-ping.com/your-uuid-here/fail
    requests.get(URL if success else URL + "/fail")

Healthchecks.io の主な機能はこれだけ (良い意味で!) となり, 実にシンプルで理解しやすいツールになっていると思います.

インテグレーション

以下のような外部サービスと連携が可能なようです.

  • Slack
  • Email
  • Webhook
  • PagerTree
  • HipChat
  • VictorOps
  • OpsGenie

おなじみの Slack をはじめ, いにしへのプロトコルになりつつある電子メールや Webhook 等, 通知系のサービスとの連携がデフォルトで行えるようになっています.

料金プラン

Healthchecks.io は無償枠以外に以下のような料金プランが用意されています.

healthchecks.io

無料枠でも 20 Checks で各 Check 毎に 100 ログエントリとあるので, 通常の利用範囲 (ちょっとした Web サービス) であれば無料枠でも十分なのでは思います.

その他

REST API も提供されていますので, 監視対象の追加や削除, 監視の一時停止等を API で操作することが出来ますし, 幾つかの言語で API をラップしたクライアントライブラリが有志の方々によってリリースされています.

healthchecks.io

尚, API を利用する為には, [Account Settings] → [Account] → [API Access] にて API キーを払い出す必要があります.

チュートリアル

Docker にて

以下の docker-compose.yml を利用して, ローカル環境に Healthchecks.io を起動します.

github.com

起動すると, Healthchecks.io 以外に MariaDBMailHog というテスト用のシンプルな SMTP サーバーが起動します. 尚, 今回の検証環境は以下の通りとなっています.

$ docker version
Client: Docker Engine - Community
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:47:43 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:55:00 2018
  OS/Arch:          linux/amd64
  Experimental:     true

$ docker-compose --version
docker-compose version 1.23.2, build 1110ad01

起動

docker-compose up -d を実行すると, 以下のようなコンテナが起動します.

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                              NAMES
822062af97fc        docker-healthchecks_hc   "/entrypoint.sh /sta…"   27 hours ago        Up 27 hours         0.0.0.0:9090->9090/tcp             docker-healthchecks_hc_1
d5684cbb2484        mariadb                  "docker-entrypoint.s…"   27 hours ago        Up 27 hours         3306/tcp                           docker-healthchecks_db_1
0a2910fbde7d        mailhog/mailhog          "MailHog"                27 hours ago        Up 27 hours         1025/tcp, 0.0.0.0:8025->8025/tcp   docker-healthchecks_mailhog_1

コンテナが起動したら, 以下を実行して管理者権限を持つユーザーを作成します.

$ docker-compose exec hc ./manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

作成したユーザー (実際には Email address) を使って, Docker で起動している Healthchecks.io にブラウザで http://localhost:9090 にアクセスしてログインします.

f:id:inokara:20181219013119p:plain

チェック (監視対象) の追加

以下のように実行して API を利用して監視対象の追加を行います.

$ export API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ curl http://localhost:9090/api/v1/checks/ \
    --header "X-Api-Key: ${API_KEY}" \
    --data '{"name": "my-first-check", "tags": "my-test", "timeout": 3600, "grace": 60}'

各パラメータは以下のような内容になっています.

  • name : 監視対象の名前
  • tags : 監視対象をグループ化する際に便利なタグを付与することが出来ます
  • timeout : Period (期間)
  • grace : 猶予期間

以下のように出力されます.

{
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "timeout": 3600,
  "tags": "my-test",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": null,
  "channels": "",
  "next_ping": null,
  "name": "my-first-check",
  "grace": 60,
  "n_pings": 0,
  "status": "new"
}

ping_url が払い出されていることが判ります.

監視

以下のように ping_url に対して curl でアクセスしてみます.

curl http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b -w "\n"

以下のように出力されます.

$ curl http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b -w "\n"
OK

監視対象の状態を確認してみます.

curl -s http://localhost:9090/api/v1/checks/?tag=my-test  --header "X-Api-Key: ${API_KEY}" | jq .

以下のように出力されます.

$ curl -s http://localhost:9090/api/v1/checks/?tag=my-test  --header "X-Api-Key: ${API_KEY}" | jq .
{
  "checks": [
    {
      "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "timeout": 3600,
      "tags": "my-test",
      "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
      "last_ping": "2018-12-19T23:10:46+00:00",
      "channels": "",
      "next_ping": "2018-12-20T00:10:46+00:00",
      "name": "my-first-check",
      "grace": 60,
      "n_pings": 2,
      "status": "up"
    }
  ]
}

ブラウザでは以下のように出力されます. Log の部分に Ping URL へのアクセスが記録されていることが判ります.

f:id:inokara:20181220090524p:plain

監視の一時停止

メンテナンス等で, Cron バッチ等を一時的に停止する必要がある場合, 以下のように Ping URL のパスに pause を付与してリクエストを送信することで, 監視を一時停止することが出来ます.

curl -XPOST http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause --header "X-Api-Key: ${API_KEY}"

以下のように出力されます.

{
  "timeout": 3600,
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": "2018-12-19T23:48:49+00:00",
  "name": "my-first-check",
  "grace": 60,
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "n_pings": 2,
  "status": "paused",
  "tags": "my-test",
  "channels": "",
  "next_ping": "2018-12-20T00:48:49+00:00",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
}

監視の再開は, Ping URL にアクセスすることで再開されます.

期間や猶予期間の変更

監視対象を登録した際に設定した期間や猶予期間は以下のように変更します. 期間を 3600 秒から 60 秒に変更してみます.

curl http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b \
    --header "X-Api-Key: ${API_KEY}" \
    --data '{"name": "my-first-check", "tags": "my-test", "timeout": 60, "grace": 60}'

以下のように出力されます.

{
  "timeout": 60,
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": "2018-12-19T23:50:16+00:00",
  "name": "my-first-check",
  "grace": 60,
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "n_pings": 3,
  "status": "down",
  "tags": "my-test",
  "channels": "",
  "next_ping": "2018-12-19T23:51:16+00:00",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
}

監視対象との疎通が取れなくなった場合

Cron ジョブ等が正常に実行されなかった場合等, 設定した期間と猶予期間の時間を超えるとステータスが Down に変わります. 期間だけを超える場合には Late というステータスになります. 以下は, API を利用して監視対象の状態を取得している実行例です.

$ curl -s http://localhost:9090/api/v1/checks/?tag=my-test --header "X-Api-Key: ${API_KEY}" | jq .
{
  "checks": [
    {
      "timeout": 60,
      "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
      "last_ping": "2018-12-19T23:50:16+00:00",
      "name": "my-first-check",
      "grace": 60,
      "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "n_pings": 3,
      "status": "down",
      "tags": "my-test",
      "channels": "",
      "next_ping": "2018-12-19T23:51:16+00:00",
      "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
    }
  ]
}

statusdown になっていることが判ります. ブラウザで確認すると以下のように Current Status が down となっていることが判ります.

f:id:inokara:20181220091136p:plain

以上

Cron ジョブの稼働監視を一覧化するにあたって, 以前に Jenkins を使うことを検討したことが有りました.

hogehuga.inokara.com

Jenkins の「外部ジョブの監視」を利用することで, Cron の実行結果の一覧を Jenkins で確認することは出来ることを確認しましたが, Healthchecks.io のように期間や猶予期間を指定するということは出来なかったと記憶しています (現在は可能かもしれませんが). 期間や猶予期間を指定出来ることで, Cron ジョブの監視以外にも定期的に実行される (それが Cron で実行されているのであれば, Cron ジョブ監視になってしまいますが...) バックエンドのサービス等の死活監視にも利用可能なのではと考えています.

今回は Docker を使って, 超簡単に Healthchecks.io をチュートリアルしてみました. 本当にシンプルで特に難しいこともなく基本的な機能を触ることが出来ました. Slack への通知等も簡単に行えるようなので, 時間を見つけて試してみたいと思います. また, サードパーティ製のライブラリをアプリケーションに組み込みんでみて, 実運用のアプリケーションでどのように使えるかも検証してみたいと考えています.

2018 年 12 月 19 日 (水)

ジョギング

  • 山王公園往復
  • 左足のくるぶしの周りもだけど, 右足の甲にも強い痛みがある...
  • えーって感じ, 靴を変えてみるかという思いになっている

日課

  • お休み

今日のランチ

あー, 博多ラーメンってこんな感じなのかな...ということで, 博多駅そばの「おっしょいラーメン」を食べた.

tabelog.com

麺をバリカタでオーダーしたら, 本当にバリカタで食べ終わるまで硬麺モードだった. スープは The 豚骨って感じでコクがあって美味しかった. 無料で紅生姜と辛子高菜を乗せ放題だったので, 辛子高菜を多めに乗せたら思いの外辛くて大汗をかいた. 美味しかったけど, やっぱり, 昨日の鶏塩ラーメンの方があっさりしてて好きかもしれない. もう, 豚骨ラーメンはキツイ年齢なのかもしれぬ.

Docker や docker-compose で TTY を有効にした場合, 標準出力の改行コードが CR+LF になる件

tl;dr

ギョームで Docker (docker-compose) を使ったちょっとしたコマンドラインツールを作った時に, 以下のように実行して標準出力をファイルに出力すると, 何故か ^M という改行コード (Carriage Return) が残ってしまってなんでやろうと思って調べたら Docker なんかよりももっといにしへの TTY の話まで掘り下がってしまって, すごく勉強になったのでメモっておきます.

docker-compose run foo > foo.txt

foo.txt の中身は以下のような感じになってしまいます.

foo1@example.com^M
foo2@example.com^M
foo3@example.com^M

なぜ, こんなことになるのか

まさに, 以下の Issue に記載されていました.

github.com

このコメントに対する返答を引用します.

Moral of the story, don't use -t unless you want a TTY. TTY line endings are CRLF, this is not Docker's doing.

TTY を有効にした場合, 行末には CRLF が付与されるとのこと. そして, これは Docker の仕業ではなく, TTY の仕業であるとのこと. CRLF が付与されることを避けたければ, TTY を無効 (Docker ではデフォルトが無効だが, docker-compose では有効になっている) にすれば良いとのこと.

ほうほう.

一応, 確認してみます. 上記の Issue コメントに書かれている方法を参考にして od コマンドを利用して確認してみます. 尚, 確認で利用している環境は以下の通りです.

$ docker version
Client: Docker Engine - Community
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:47:43 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:55:00 2018
  OS/Arch:          linux/amd64
  Experimental:     true

$ docker-compose version
docker-compose version 1.23.2, build 1110ad01
docker-py version: 3.6.0
CPython version: 3.6.6
OpenSSL version: OpenSSL 1.1.0h  27 Mar 2018

以下, 実行結果です.

# Docker コマンドで
# TTY 無効
$ docker run ruby:2.5-alpine sh -c 'echo "test"' | od -c
0000000    t   e   s   t  \n
0000005
# TTY 有効
$ docker run -t ruby:2.5-alpine sh -c 'echo "test"' | od -c
0000000    t   e   s   t  \r  \n
0000006

# docker-compose コマンドで
# TTY 無効 (-T で TTY を無効にする)
$ docker-compose run -T test sh -c 'echo "test"' | od -c
0000000    t   e   s   t  \n
0000005
# TTY 有効 (docker-compose はデフォルトで TTY が有効になっている)
$ docker-compose run test sh -c 'echo "test"' | od -c
0000000    t   e   s   t  \r  \n
0000006

確かに, TTY を無効にしている場合, \n のみで \r が付与されていないことが判ります.

なぜ, TTY の行末には CRLF が付与されているのか

なぜ, TTY の行末には CRLF が付与されているのか, 詳しい文献を見つけることが出来なかったのですが, 以下のような「screen コマンドの出力はなんで CRLF なんすか?」という記事を見つけたので転載しておきます.

unix.stackexchange.com

以下, グーグル翻訳した内容を一部意訳もつけて転載させて頂きます.

The deep reason for the discrepancy between program output and a captured tty stream (e.g. typescript) is that tty's used to be printers.

プログラム出力とキャプチャされた tty ストリームとの違いは, tty がプリンタであったことに由来する.

Before unix, text always had a CRLF at the end of a line, not because it was considered to be the logical representation of a line termination, but because the characters individually had real physical meaning: move the print head all the way to the left, and advance the paper.

Unix の前には, 行終端には常に CRLF が付いていた. 行終端の論理的な表現とみなされたわけではありませんでしたが, 実際には紙を前進させるという, 物理的な意味があります.

Unix took a radical new approach: it treats text files on disk as a useful object in their own right (not just instructions for a printer), and lines as logical entities. The two-character line terminator is unnecessarily complicated in the unix worldview.

UNIX は, ディスク上のテキストファイルをプリンタのための指示だけでなく, 論理的なエンティティとして有用なオブジェクトとして扱う. 2 文字の行終端文字 (CRLF) は, Unix の世界観では不必要に複雑である.

But they had to work with existing hardware - printers and CRT dumb terminals that didn't recognize a single "end of line" character, but only a CR to do half the job and an LF to do the other half. So a translation had to be done, and it was done at the closest possible place to that hardware - in the tty driver.

しかし, 既存のハードウェアプリンタやCRTダム端末では,「行末」文字は認識されませんでしたが, ジョブの半分を実行するCRと残りの半分を実行するLFだけが必要でした. 翻訳が完了しなければならなかったので, それは tty ドライバの中でそのハードウェアに最も近い可能な場所で行われました.

Since then, it's all been backward compatibility. So you have a terminal emulator that insists on CRLF, and a tty driver that supplies it when a program outputs a newline.

それ以来, それはすべて下位互換性があります. したがって, CRLFを主張する端末エミュレータと, プログラムが改行を出力するときにそれを供給する tty ドライバがあります.

どうやら, 歴史的な経緯の中で下位互換の維持の為, TTY の行末には CRLF が付与されるのではないかと読み取りました. Linuxソースコードとか読めば (読めれば), もう少し確証を持てる情報が得られるのではないかと考えていますが, ここまでの情報にたどり着くまでに TTY や CR, LF について参考になる記事を読むことが出来ました.

ありがとうございました.

参考文献

github.com

github.com

tty(4)

テレタイプ端末 - Wikipedia

developer.mozilla.org

www.granfairs.com