早いもので以下のエントリから1年経ちました。
入社した 3/1 に入社して1年経ちましたエントリを書こうと思ったけど、エイプリールフールに入社エントリを書くのは面白かったので、4/1まで待ちました。
ということで、この1年(と1ヶ月)の間、何をしていたかの振り返りです。
続きを読む早いもので以下のエントリから1年経ちました。
入社した 3/1 に入社して1年経ちましたエントリを書こうと思ったけど、エイプリールフールに入社エントリを書くのは面白かったので、4/1まで待ちました。
ということで、この1年(と1ヶ月)の間、何をしていたかの振り返りです。
続きを読む手元環境で Dockerfile から docker イメージを作る時はいちいち docker build
コマンドを直接実行するのはダルいのでラッパースクリプトなどで実行するようにしています。
管理している Dockerfile や docker イメージの種類が多くなってくると素朴なラッパースクリプトでは作成したい docker イメージを狙い撃ちで生成するにはラッパースクリプトで一工夫が必要になります。これだとラッパースクリプトが必要以上に多機能になってしまい、作業の本質以外に気を取られてしまいます。
古くから使われている GNU make を使えば、Dockefile から docker イメージを作成するルールをいい感じに作れたので、作り方のメモを書いておきます。
まず、Makefile のルールの書き方は
生成物(ターゲット名): 生成元のリスト
といった感じに書いていきます。ターゲット名で指定しているファイルと生成元のリストで列挙されているファイルのタイムスタンプを比較して、生成物よりも新しい生成元のファイルがあればルールが実行されます。
ただし、docker build
で生成されるのは docker イメージなので、ファイルのタイムスタンプを取ることが GNU make の世界ではできません。そこで docker build
の後に docker inspect コンテナイメージ | jq -r .[].RepoTags[] > .build
といったように生成したコンテナイメージの情報を書いたファイルを GNU make の世界での生成物とするうにします。以下のような感じです。
.build: Dockerfile
docker build -t hoge:latest -f Dockerfile .
docker inspect hoge:latest | jq -r .[].RepoTags[] > .build
生成物である .build
ファイルに記述する内容は生成した docker イメージが特定できればなんでも良いと思いますが、 make clean
などで消す時の利便性を考えて docker イメージのレポジトリとタグ名を入れています。clean
ターゲットは以下のように書いています
clean: cat .build | xargs -I {} docker rmi {}
また、docker で multi stage build を使用している場合はターゲットの生成元にベースになる Docker イメージを生成した時の .build
ファイルを指定しておけば依存関係に組み込まれて便利です。
.build-base: Dockerfile.base docker build -t base:latest -f Dockerfile.base . docker inspect base:latest | jq -r .[].RepoTags[] > .build-base .build: Dockerfile .build-base docker build -t hoge:latest -f Dockerfile . docker inspect hoge:latest | jq -r .[].RepoTags[] > .build
さらに Dockerfile
内で ADD
命令や COPY
命令などでコンテナイメージにファイルを配置しておきたい場合は Dockefile
を置いているディレクトリに roo-hogehoge
ディレクトリをコンテナ内の /
として見立てて配置しておくと Makefile
のターゲットでは $(shell find root-hogehoge -type f)
として依存関係に組み込んでいます。
具体的には nginx を nginx-build
で作るときに -c
で指定するスクリプトをコンテナ内の /tmp/nginx-build/nginx_configure.s
として使用するときは以下のように配置しています。
. ├── Dockerfile ├── Makefile └── root └── tmp └── nginx-build └── nginx_configure.sh
このときの Makefile
は以下のようにターゲットを指定しています。
.build: Dockerfile $(shell find root -type f) docker build -t nginx:latest -f Dockerfile . docker inspect nginx:latest | jq -r .[].RepoTags[] > .build
実際に使っている Makefile は以下のようになっています
MAKEFLAGS = -j 4 DOCKER_BUILD_ARGS := --no-cache --squash --rm IMAGE_NAME := varnish USER_NAME := $(shell whoami) BUILD_FILES = .build-4.1 .build-5.2 .build-6.2 .build-6.0lts .PHONY: build build: $(BUILD_FILES) .build-4.1: Dockerfile.jessie docker build $(DOCKER_BUILD_ARGS) --build-arg VARNISH_VERSION=41 -t '$(USER_NAME)/$(IMAGE_NAME):jessie-4.1' -f Dockerfile.jessie . docker inspect '$(USER_NAME)/$(IMAGE_NAME):jessie-4.1' | jq -r '.[].RepoTags[]' > .build-4.1 .build-5.2: Dockerfile.jessie docker build $(DOCKER_BUILD_ARGS) --build-arg VARNISH_VERSION=52 -t '$(USER_NAME)/$(IMAGE_NAME):jessie-5.2' -f Dockerfile.jessie . docker inspect '$(USER_NAME)/$(IMAGE_NAME):jessie-5.2' | jq -r '.[].RepoTags[]' > .build-5.2 .build-6.2: Dockerfile.stretch docker build $(DOCKER_BUILD_ARGS) --build-arg VARNISH_VERSION=62 -t '$(USER_NAME)/$(IMAGE_NAME):stretch-6.2' -f Dockerfile.stretch . docker inspect '$(USER_NAME)/$(IMAGE_NAME):stretch-6.2' | jq -r '.[].RepoTags[]' > .build-6.2 .build-6.0lts: Dockerfile.stretch docker build $(DOCKER_BUILD_ARGS) --build-arg VARNISH_VERSION=60lts -t '$(USER_NAME)/$(IMAGE_NAME):stretch-6.0lts' -f Dockerfile.stretch . docker inspect '$(USER_NAME)/$(IMAGE_NAME):stretch-6.0lts' | jq -r '.[].RepoTags[]' > .build-6.0lts .PHONY: clean clean: $(BUILD_FILES) cat $^ | xargs -I {} docker rmi {} rm -f $^
BUILD_FILES
に対象となる .build
相当のファイルを列挙して、build
ターゲットや clean
ターゲットで指定しておくことで -j
オプションで並列化できるので便利です。
なんらかの CI/CD パイプラインを構築している場合はこのままでは使えないけど、手元でテストする分にはこんな感じで割と便利に使えています。
2018年から2019年の年末年始は 1/4(金) を有給にして、12/29 から 1/6 までガッツリと休みを確保したので、チマチマとコードを書いていた。
Linux の proc/net
以下に出ている情報をなんとかして、mackerel で表示できたら便利だよなーと思っていたんだけど、ちょうど時間がガッツリとれたので、年末年始の書き納めと書き初めという体で以下の3つのプラグインを作ってみた。
github.com github.com github.com
mackerel-plugin-proc-net-ip_vs_stats_percpu
2018 年のコードの書き納めとして作りました。
/proc/net/ip_vs_stats_percpu
を情報源に CPU コアごとに処理したパケットの統計情報が取れる。LVS-HOWTO の 33. LVS: Monitoring では /proc/net/ip_vs_stats
でいい感じな情報が取れる、ということだったけど、僕が確認した kernel 3.6 系だと real server ごとの統計情報が表示されていなかった。そのかわり /proc/net/ip_vs_stats_percpu
では CPU コアごとに処理したパケット数とバイト数が取れるようだったので、こっちを使うことにした。 /proc/net/ip_vs_stats_percpu
は linux/ip_vs_ctl.c at master · torvalds/linux · GitHub を見る限り、意図した情報が取れそうな気配です。
mackerel-plugin-proc-net-ip_vs_stats_percpu
では引数に -cpus
で CPU コア数を明示できるようにしていますが、内部で runtime.NumCPU()
で CPU コア数を取得するようにもしています。なんでこんなことをしているか、というと仮想化されたホストで LVS を使っていると /proc/net/ip_vs_stats_percpu
で表示される CPU コアが実際のコア数よりも多くなっているケースがあるからです。runtime.NumCPU()
に任せれば良えやんという話もあるかもしれませんが、なんとなくオプションで渡してあげると便利かも、と思ってつけました。
mackerel-plugin-proc-net-arp
2019 年のコードの書き初めとして作りました。
/proc/net/arp
を情報源にホストの ARP テーブルのサイズが取れます。本当は Flags
ごとの統計も取れたら便利かなーと思ったんですけど、とりあえずテーブルサイズだけでも取っておけば、ARP テーブル溢れとかに気付けるかと思って、最小限の機能だけにしました。
mackerel-plugin-proc-net-ip_vs
mackerel-plugin-proc-net-ip_vs_stats_percpu
を作っているときに LVS-HOWTO や linux/net/netfilter/ipvs at master · torvalds/linux · GitHub を眺めていて、 ipvsadm -nL
相当の情報を /proc/net/ip_vs
から取得できそうだったので作りました。
ipvsadm -nL
の出力を情報源にする、というアプローチもあると思いますが、個人的には ipvsadm
という cli ツールに頼らずに procfs から情報が取れるなら、procfs を利用したほうが依存関係がスッキリしていいんじゃないかと思っています。
今年も健やかにコードが書けることを祈念して、書き初めをしてました。今年も良い年でありますように。
Mackerel Advent Calendar 2018 - Qiita の 11日目です。昨日は id:koudenpa さんの.NET で動くアプリケーションを Mackerel で監視できるかな? でした。
今回は mackerel-agent-plugin の mackerel-plugin-squid を使おうとしたところ、運用上欲しいメトリックが対象となっていなかったので、エイやと機能を追加して、取り込んでもらったので、その体験談です。
今回は既存の plugin に欲しい項目を付け加えるので、コードを読んでみました。
squid には各種情報をとるためのインターフェースがいくつか用意されていて、mackerel-plugin-squid では mgr:info
を情報源にしていました。どのような情報が取れるかはリンク先を参照してもらうとして、今回、僕が是非とも加えたいと思ったのは、以下の項目です。
それぞれ、mgr:info
から取得するには以下の項目を参照すれば良さそうです。
Resource usage for squid:
の CPU Usage, 5 minute avg:
File descriptor usage for squid:
あたりを丸ごとCache information for squid:
の Storage Swap size:
や Storage Mem size:
あたりが使えそうMemory accounted for:
の memPoolAlloc calls:
と memPoolFree calls:
あたりが使えそうmackerel-agent-plugin の書き方は整備されたドキュメントが公開されているので、そこを参考に書き方を調べます。
今回は既存の plugin に修正するので、既存のコードを眺めます。ポイントはグラフ定義部分とメトリック値を入れているところです。
グラフ定義部分は GraphDefinition()
という関数の中で graphdef
を返しているだけなので、graphdef
を眺めてなんとなく雰囲気を掴みます。今回は Memory accounted for:
の memPoolAlloc calls:
と memPoolFree calls:
の値はカウンター値なので、そこだけ気をつけてあげれば良さそうです。
また、メトリック値を取得しているところは僕が最初に確認した時は FetchMetrics()
の中で TCP ソケットを開いて GET cache_object://localhost:3128/info HTTP/1.0\n\n
というような文字列を直接流し込んでいました。最近の squid だと localhost:3128
など cache_manager のポートに HTTP 通信をさせると、取得できるのですが、このプラグンが最初に作られた時は squid 2 系についても考慮する必要があったので、TCP ソケットと直接通信させる必要があったようです。また、値については応答内容を愚直に regexp.MustCompile()
で正規表現で拾い上げているようでした。
あと、コードを読みながら気づいたのですが、このプラグインにはテストが書かれていなかったので、テストが書きやすい構造に直してあげる必要がありそうです。
というわけで、諸々で書いた結果以下のような PR が出来上がりました。
https://github.com/mackerelio/mackerel-agent-plugins/pull/534
今までの PR の内容をみつつ、雰囲気を感じながら拙い英語で PR を出したところ、わりとさっくりとマージしてもらえました。
mackerel-plugin-squid は go-mackerel-plugin-helper を使っています。このライブラリはレポジトリの README.md に書かれている通り、現在は go-mackerel-plugin の使用が推奨されています。実際に最初に参照した開発向けドキュメントでも go-mackerel-plugin の使用を前提としてます。修正するときに一緒にライブラリも変更しようかと思いましたが、今回はあまり時間がとれなかったので、ライブラリの変更を見送ったのが心残りです。
mackerel-agent だけでなく、mackerel-agent-plugins も Apache License, Version 2.0 で公開されているので、自分が欲しい機能などがあれば積極的に PR を送っていきたいですね!
とあることで MySQL さんの働きっぷりを dtrace で追いかけようと思ったけど、ubuntu が提供しているバイナリでは、dtrace 向けのオプションが付いていない状態でビルドされていた。
$ sudo /usr/share/bcc/tools/tplist -l `which mysqld` $
MySQL :: MySQL 5.7 Reference Manual :: 2.9.4 MySQL Source-Configuration Options を見ると cmake に -DENABLE_DTRACE=1
を渡せば良いらしい
というわけで、deb パッケージの作り方をググりながら MySQL を作り直してみた、というメモです。
まずはビルドに必要な最小限のパッケージを取ってくる
$ sudo apt install build-essential devscripts systemtap-sdt-dev $ sudo apt build-dep mysql-server
で、ubuntu のレポジトリから MySQL パッケージを作成するために必要なファイル1式を取ってくる
$ mkdir tmp $ cd tmp $ apt source mysql-server
この状態で作業用ディレクトリには以下のようにファイルとディレクトリが生成されているはず。
$ ls -F mysql-5.7-5.7.23/ mysql-5.7_5.7.23-0ubuntu0.16.04.1.debian.tar.xz mysql-5.7_5.7.23-0ubuntu0.16.04.1.dsc mysql-5.7_5.7.23.orig.tar.gz $
deb パッケージ作成時にしようする cmake のオプションは mysql-5.7-5.7.23/debian/rules
に書いてあるので、修正してあげる。
ここまできたら以下を実行して deb パッケージが作れるはず
$ cd mysql-5.7-5.7.23 $ debuild -uc -us -b
出来上がったバイナリを tplist -l
で確認すると以下のようにそれっぽい感じになっている。わーい。
$ sudo /usr/share/bcc/tools/tplist -l mysql-5.7-5.7.23/builddir/sql/mysqld | wc -l 56 $
趣味活動で unbound の dnstap とか EDNS Client Subnet の挙動を確認したかったので、unbound のコンテナイメージを作っていたんだけど、最後に /usr/local/etc/unbound
以下の環境を作るところで、エラー終了してホゲーとなっていた。問題になっていたのは以下の RUN
命令部分。
RUN addgroup unbound && adduser -S -G unbound unbound && \ /usr/local/sbin/unbound-control-setup && \ /usr/local/sbin/unbound-anchor -a /usr/local/etc/unbound/root.key && \ mkdir -p /usr/local/etc/unbound/dnstap && \ chown unbound:unbound /usr/local/etc/unbound/dnstap
で、ブログの表題でほとんどネタバレしているんだけど、原因になっていたのは /usr/local/sbin/unbound-anchor -a /usr/local/etc/unbound/root.key && \
の部分。unbound を運用している人にとっては当たり前かもしれないけど、unbound-anchor
でトラストアンカーを更新した時は終了コードが1になるらしい。unbound-anchor のマニュアルにも以下のようにキッチリ明示されている。
EXIT CODE This tool exits with value 1 if the root anchor was updated using the certificate or if the builtin root-anchor was used. It exits with code 0 if no update was necessary, if the update was possible with RFC5011 tracking, or if an error occurred.
You can check the exit value in this manner: unbound-anchor -a "root.key" || logger "Please check root.key" Or something more suitable for your operational environment.
しかも、解決方法も書いてあるし...
とりあえず、以下のように手元の Dockerfile を書き直して最後まで完走できることは確認した。
RUN addgroup unbound && adduser -S -G unbound unbound && \ unbound-control-setup && \ /usr/local/sbin/unbound-anchor -a /usr/local/etc/unbound/root.key || echo "hoge" && \ mkdir -p /usr/local/etc/unbound/dnstap && \ chown unbound:unbound /usr/local/etc/unbound/dnstap