helen's blog

ずっとおもしろいことしてたいな。

nwdiagでただサンプルを動かすまでが長かった

nwdiagというMarkdownでネットワーク図を書ける素敵ツールを見つけたので
さくっと書こうと思ったらなぜか半日かかった苦しみを残します
だからpipは苦手なんだ...

nwdiag

Markdownを書けばネットーワーク図、パケットヘッダなどGenerateできる優れもの

http://blockdiag.com/en/nwdiag/index.html

インストール方法
pip install nwdiag

http://blockdiag.com/en/nwdiag/introduction.html

実行
nwdiag simple.diag

http://blockdiag.com/en/nwdiag/nwdiag-examples.html

みたいなのがさくっとできる

Symbol not found: _clock_gettime
nwdiag simple.diag
Traceback (most recent call last):
  File "/usr/local/bin/nwdiag", line 7, in <module>
    from nwdiag.command import main
  File "/usr/local/lib/python2.7/site-packages/nwdiag/command.py", line 18, in <module>
    import nwdiag.builder
  File "/usr/local/lib/python2.7/site-packages/nwdiag/builder.py", line 18, in <module>
    from nwdiag.elements import (Diagram, DiagramNode, DiagramEdge,
  File "/usr/local/lib/python2.7/site-packages/nwdiag/elements.py", line 17, in <module>
    import blockdiag.elements
  File "/usr/local/lib/python2.7/site-packages/blockdiag/elements.py", line 19, in <module>
    from blockdiag.utils import images, unquote, urlutil, uuid, XY
  File "/usr/local/lib/python2.7/site-packages/blockdiag/utils/images.py", line 20, in <module>
    from PIL import Image
  File "/usr/local/lib/python2.7/site-packages/PIL/Image.py", line 60, in <module>
    from . import _imaging as core
ImportError: dlopen(/usr/local/lib/python2.7/site-packages/PIL/_imaging.so, 2): Symbol not found: _clock_gettime
  Referenced from: /usr/local/lib/python2.7/site-packages/PIL/.dylibs/liblzma.5.dylib (which was built for Mac OS X 10.12)
  Expected in: /usr/lib/libSystem.B.dylib
 in /usr/local/lib/python2.7/site-packages/PIL/.dylibs/liblzma.5.dylib

pipでインストールするときって
うまくいくと大喜びするくらいうまくいかない..

エラーメッセージがおっしゃる通り、使ってるMacは10.11.6で
10.12で入る何かが足りないらしい

github.com

同じようなissueは見つかるけど
OSアップデートするのは嫌だし
brew update や brew upgrade, prune試しても変わらなかった

ライブラリのバージョンを下げる

github.com

$ pip list
Package         Version
--------------- --------
Pillow          5.1.0 # アウツ

$ pip install 'pillow!=5.1.0'

$ pip list
Package         Version
--------------- --------
Pillow          5.0.0 # 下げた

$ nwdiag simple.diag # Success!

pipでハマると普通に半日吹き飛んでつらいなぁ😥

terratestで遊んだけど明日になったら忘れてるのでメモするよ

github.com

ちょっとGoを書くだけでTerraformのテストができるよっていうツール

かなり初期までのa tour of goしかやってない自分でも
さっくりできてびっくりした

準備

  • 壊れても良い環境しかないようなAWSアカウント用意
  • terraform planまでは通るTerraform書く
  • Goのインストール

いいところ

はまったところ

フォルダ構成がだめ
provider.aws: no suitable version installed

# all logs
go test terraform_test.go
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 retry.go:64: Running terraform [destroy -force -input=false -lock=false]
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:52: Running command terraform with args [destroy -force -input=false -lock=false]
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: Plugin reinitialization required. Please run "terraform init".
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: Reason: Could not satisfy plugin requirements.
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: Plugins are external binaries that Terraform uses to access and manipulate
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: resources. The configuration provided requires plugins which can't be located,
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: don't satisfy the version constraints, or are otherwise incompatible.
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: 1 error(s) occurred:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: * provider.aws: no suitable version installed
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:   version requirements: "(any version)"
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:   versions installed: none
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: Terraform automatically discovers provider requirements from your
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: configuration, including providers used in child modules. To see the
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95: requirements and constraints from each module, run "terraform providers".
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:95:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:99:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:99: Error: error satisfying plugin requirements
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:99:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 command.go:99:
TestTerraformHttpExample 2018-05-18T20:16:10+02:00 retry.go:72: Returning due to fatal error: FatalError{Underlying: exit status 1}
--- FAIL: TestTerraformHttpExample (0.04s)
	destroy.go:11: FatalError{Underlying: exit status 1}
FAIL
FAIL	command-line-arguments	0.045s

エラーメッセージと全然結びついてないけど
testコードが見に行くTerraformを1つのディレクトリにまとめたらいい感じに動いてくれました

# ng: 平置きがだめ
- testcode_test.go
- terraform_resources
- main.tf
- sample.tfvars

# ok: test.goにTerraformのリソースの入ったディレクトリを参照させる
- testcode_test.go
- terraform_code/
実行上限にひっかかる
*** Test killed with quit: ran too long (10m0s).

S3 + Cloudfrontなstaticホスティング構成立ててhttpリクエストさせてのテストがタイムアウトした・・・
なんかあかんみたいね・・・
明日なおそ・・・・

Rspecみたいに実行状況を何も書かなくても吐いてくれたらいいのになって思ったのと
エラーがまだ人間に優しくないのかも(ドキュメントを読んでなさすぎるのも大いに有りすぎると思う)と思いました。

テストにそれなりに時間がかかるけどちゃんと書けば楽しそう
ちゃんと書けばね!

dentryキャッシュ対応に悩まされた話

原因は完全にこれ↓で

tools.knetik.io

要約すると、余裕がある時はめっちゃcurlしてキャッシュするっていう機能があって
放置するとmemoryをどんどん使っていくので
nss-softokenを3.16以上にしてオプション有効にしようね、という話

Bug 1044666 – Can curl HTTPS requests make fewer access system calls?
でも報告されていて、NSS_SDB_USE_CACHEをYESかNOにすると
sdb_measureAccessを呼ばなくなるらしい

自分のところではswap領域を使わないまま
約24時間でusedが7GB弱増えていました

export NSS_SDB_USE_CACHE=YES

を/etc/sysconfig/httpdに追加して経過観察してたけど全然効き目がなく
適当に設定をNOにしてみたり無意味に大文字小文字を変えてみたりの無駄な手順を試したけど当然効かず
でも放置するわけにもいかないので毎日dentryキャッシュを削除していました

f:id:heleeen:20180223021506p:plain

↑ キャッシュを削除する日々の図
最初はアラートで呼ばれたので対応して、
次の3回くらいはアラートを飛ばさないためにキャッシュ削除しただけで
その後は設定を入れてもうまくいかない戦いです
すごい徒労感があるね!

諸々のバージョン

$ httpd -V
Server version: Apache/2.4.25 (Amazon)

$ sudo yum list nss-softokn
nss-softokn.x86_64              3.16.2.3-14.4.39.amzn1 

$ curl -V
curl 7.51.0 (x86_64-redhat-linux-gnu) libcurl/7.51.0 NSS/3.28.4 

やってたこと

NSS_SDB_USE_CACHE=yesが効きそうか見る

access回数が減るので効果はあるはずなのに
apacheを再起動して数時間待つとなぜかメモリ消費してた
See. アプリケーション内でhttpsによる外部APIを叩いているサーバのメモリ使用量が増加し続ける件について - s_tajima:TechBlog

$ strace -fc -e trace=access curl 'https://www.google.com' > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000065           0      1626      1622 access # ここがおかしい
------ ----------- ----------- --------- --------- ----------------
100.00    0.000065                  1626      1622 total

$ NSS_SDB_USE_CACHE=yes strace -fc -e trace=access curl 'https://www.google.com' > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0        32        30 access # 効いてる
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    32        30 total

# noでもこれくらい
$ NSS_SDB_USE_CACHE=no strace -fc -e trace=access curl 'https://www.google.com' > /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   272  100   272    0     0   1786      0 --:--:-- --:--:-- --:--:--  1789
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0        58        56 access
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    58        56 total

オプションをつけずにcurlすると何度もaccessされるのがわかる

$ strace -e trace=access curl 'https://www.google.com' > /dev/null
...
access("/$HOME/.pki/nssdb/cert3.db", F_OK) = -1 ENOENT (No such file or directory)
access("/$HOME/.pki/nssdb/cert2.db", F_OK) = -1 ENOENT (No such file or directory)
access("/$HOME/.pki/nssdb/key3.db", F_OK) = -1 ENOENT (No such file or directory)
access("/$HOME/.pki/nssdb/key2.db", F_OK) = -1 ENOENT (No such file or directory)
access("/$HOME/.pki/nssdb/secmod.db", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/pki/nssdb/.3550898456_dOeSnotExist_.db", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/pki/nssdb/.3550898457_dOeSnotExist_.db", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/pki/nssdb/.3550898458_dOeSnotExist_.db", F_OK) = -1 ENOENT (No such file or directory)
...
設定反映されてないのかな

環境変数を見ると入っているのになぁ・・って思ってました

$ sudo od -S1 -An /proc/4057/environ # httpd
TERM=xterm
PATH=/sbin:/usr/sbin:/bin:/usr/bin
PWD=/
LANG=C
SHLVL=2
NSS_SDB_USE_CACHE=YES # ここ
_=/usr/sbin/httpd
直線で増加していくのっておかしくない?

httpdが原因ならアクセス数に比例するはずなのに
直線で増加していくのっておかしくない?ってようやく気づきました

内部でずっと動いてくれているものにすごく心当たりがあって・・・
出来心で/etc/sysconfig/mackerel-agentにも同じ内容追加して
エージェント再起動したのがこちら

f:id:heleeen:20180223153718p:plain

キャッシュ増加が止まったのがはっきりわかって
嬉しくて思わずslackにも流してしまったやつ

最初のブログにもhttpd以外にも必要なら入れてね!って書いてあったのに!!
逆にhttpdからその環境変数外すとどうなるんだろうと思って外したら
増加の仕方はとてもゆっくりという結果になりました・・
アプリケーションの負荷ェ.....

他のメトリックにも特に影響は見られなかったので
ひとまずは解決で良さそうだけど
特定プロセスに対してしか設定してないから
たとえばサーバ内でcurlされるとキャッシュは増加するまんま・・・(。ŏ﹏ŏ)
他にそういうツールとかいれたらまた同じことが発生するなぁ・・

Mackerelで他のオーガニゼーションのアラート状況もまとめて把握したかった

午前2:30くらいにCPU100%のアラートが来て
しばらくしても戻らなかったので
のそのそと布団から這い出て確認するとstealが100%になってました

f:id:heleeen:20180216193152p:plain

t2.microでCPUのstealが100%でググるといっぱいでてくるから割りとあることみたいなので
本番環境じゃなくてよかったなぁって思いつつ
インスタンス再起動を待ちながら所属するオーガニゼーションをフラフラと巡ってた

メインで見ているオーガニゼーションは
いつも通りのアラートが出ていて(アカン)
ああ、明日なんとかしよう・・と思って見なかったことにして(ちゃんと今日対応しました!)
サブのオーガニゼーションたちを見ると
そこにもアラートがちらほらしていてこれって誰か検知してるの?という状態でした

さすがに他のオーガニゼーションのアラート数を取得するというアグレッシブ機能はなくて
MackerelのAPI経由でアラート数を取得して投稿したらいいんじゃない?っていう声が近くからしたのでやってみました
今回はshellがあまりにも雑なので割愛します

f:id:heleeen:20180216193209p:plain

アラートを意図的に起こしてslackを騒がせたのでグラフもとても賑やかです😊

19時あたりは意図的に起こしたアラートをすべてクローズしたのに
0になっていない図となりました

来週やるぞ😵

ハムスターのために監視導入したら人間のための監視もしたほうが良さそうなことがわかりました

Mackerel Advent Calendar 2017 - Qiita の12/20の記事です

以前、【増枠】紅白 Milkcocoa 合戦!【祭り】 Milkcocoa Meetup vol12 - connpassでLTしたこれを

(要約:3時間で勝手にエアコンが切れるアパートで、
ハムスターのために温度が一定以上になったらラズパイでエアコンつけて夏を乗り切りました)

いろいろと事情が変わったので、今回はMackerelを使って改造してみました!

前回より

変わったこと

実は当時のアパートから引っ越ししたので事情がとても変わりました

  • エアコンが勝手に切れない!!
  • ハムスターたちとエアコンが遠いので、ハムスターのそばで温度を取ると赤外線が届かない
  • もしかして実はもう必要ないのでは...
当時の課題
  • 湿度を取っているのに表示していない、SPだと崩れてる
    • 得意でないフロントゴリゴリ実装でもう1個グラフを増やす気力が沸かなかった😂
  • 後追いでグラフを見て確認できるけど、状況をPushしていない
    • 当時をよく覚えていないけどHubot周りがうまくいかず諦めちゃった😂

ここにMackerelを導入してみました

Mackerelにカスタムメトリック投稿

物理的な実装はセンサーつないだだけなので割愛します

温度と湿度を取得して出力

ホストのカスタムメトリックを投稿する - Mackerel ヘルプ を参考にタブ区切りで出力

import time
import get_environment as env # 温度取得はmilkcocoa送信用に実装済みなので流用

# vars
epoch_seconds = str(time.time())

try:
    # get host_id
    with open('/var/lib/mackerel-agent/id') as mackerel_agent_id:
      host_id = mackerel_agent_id.read()

    # output datas
    print('\t'.join(['env.temp', env.temperature, epoch_seconds]))
    print('\t'.join(['env.hum', env.humidity, epoch_seconds]))

except Exception as e:
    print('failed in sending to mackerel')
    print(e)
実行結果
$ sudo /usr/bin/python /PATH_TO_SOURCE/mackerel_monitor_temperature.py
env.temp	22.40	1512901475.44
env.hum	36.40	1512901475.44
mackerel-agent.confに追記
# 追記内容
[plugin.metrics.raspi]
command = "sudo /usr/bin/python /PATH_TO_SOURCE/mackerel_monitory_temperature/mackerel_monitor_temperature.py"
agent起動
$ nohup sudo /usr/local/bin/mackerel-agent >> /var/log/mackerel-agent.log &
こうなる

青いグラフが湿度、オレンジが温度です

f:id:heleeen:20171211015744p:plain
※12/9の21時ごろに湿度がいきなりあがったのは冷しゃぶしたからです

監視を入れます

ハムスターにとって快適な温度は20〜26度で、
冬場は風邪を引かないための湿度は40〜60%が良いらしいのでこんな監視設定をします

$ mkr monitors
[
    {
        "id": "3bwDVM8jm1h",
        "name": "custom.env.hum over 60%",
        "memo": "ジメジメだよ(。>﹏<。)",
        "type": "host",
        "metric": "custom.env.hum",
        "operator": ">",
        "warning": 60,
        "critical": 65,
        "duration": 3
    },
    {
        "id": "3bwDQLE4bTS",
        "name": "custom.env.hum under 40%",
        "memo": "干からびちゃうよ(。ŏ﹏ŏ)",
        "type": "host",
        "metric": "custom.env.hum",
        "operator": "<",
        "warning": 45,
        "critical": 40,
        "duration": 3
    },
    {
        "id": "3bw5wNYbhN5",
        "name": "custom.env.temp over 26℃",
        "memo": "暑いよ(;´Д`)",
        "type": "host",
        "metric": "custom.env.temp",
        "operator": ">",
        "warning": 25,
        "critical": 26,
        "duration": 3
    },
    {
        "id": "3bw5memzmP3",
        "name": "custom.env.temp under 20℃",
        "memo": "寒いよ:;(∩´﹏`∩);:",
        "type": "host",
        "metric": "custom.env.temp",
        "operator": "<",
        "warning": 21,
        "critical": 20,
        "duration": 3
    }
]

監視設定した途端いきなりCRITICAL来た

f:id:heleeen:20171214005457p:plain

温度とか言ってる場合じゃない!!
(温度は無事20〜26度をさまよっていました)

朝の喉のイガイガ感の原因がはっきりしました

ここまでで

  • ちょっとPython書いたらメトリック投稿できた
  • フロント頑張らなくてもグラフ表示できる!!!
  • 簡単に湿度まで可視化できた!!
  • しかも実はラズパイの死活監視までできている

はまったところ

invalid JSONされる
2017/12/03 11:54:14 WARNING <command> metadata plugin "raspi": outputs invalid JSON: env.temp	22.50	1512302054.61

mackerel-agent.confの書き方がだめでした

# これでエラー
[plugin.metadata.raspi]
command = "sudo /usr/bin/python /home/pi/work/mackerel_monitory_temperature/mackerel_monitor_temperature.py"

# "plugin.metrics."ではじめないといけない
[plugin.metrics.raspi]
command = "sudo /usr/bin/python /home/pi/work/mackerel_monitory_temperature/mackerel_monitor_temperature.py"

ドキュメントろくに呼んでない自分が完全に悪いけど
エラーメッセージがもうちょっと親切だとありがたかったかも...
エージェント経由ってタブ文字区切りだとだめなの...?で数日悩みました( ;∀;)

カスタムメトリックってJSON書かないと監視できないのかと思っちゃった(●´ϖ`●)

f:id:heleeen:20171214000914p:plain

下まで見ても見つからず...

f:id:heleeen:20171214000928p:plain

入力すればよかったのか😂

おわりに

f:id:heleeen:20171219234519p:plain

アドベントカレンダー書くぞと帰ってきて加湿器つけてこんな感じで
湿度がCRITICALとWARNINGを行き来しています
お湯を800mlくらい蒸発させたときは湿度20%くらいあがって、すごい即効性がありました
やったことが数字になってわかるのもおもしろいね(●´ϖ`●)