ぐるっとぐりっど

日曜プログラマがいろいろ試してみたことを、後の自分のためにまとめておく場所

emacs25で追加されたdynamic moduleのサンプルを写経して動かしてみた

github.com

XWidgets芸人になるつもりはないので、dynamic moduleもどんなことできるか軽く動かしてみた

公式のサンプルに必要なことは一式書いてあるので、読むとだいたいわかる。いきなり他の英語の解説記事読むより、これに目をとおしてからの方が理解しやすかった。

https://github.com/emacs-mirror/emacs/blob/emacs-25/modules/mod-test/mod-test.c

できること

いくつかの規定どおりのソースをもとにしたsoファイルを作っておけば、emacsから、elispで書いたパッケージと同じようにrequireして、関数を呼ぶことができる

というか、Cのソースのほうで、provideを書いてるので、関数の実体だけCで書いて、あとはemacsパッケージを作っているような気分

とりあえず引数をうけとって、結果を返す関数は書けたので、なんか応用はききそう


なんかgolangで書くこともできるらしく、まあsoファイル作ってよみこむってのがわかれば、そうだよね、という気持ち

Writing Emacs modules with Go

あまりelisp力も高くないので、その辺を高めつつ面白そうなのを作れたらよい

Dockerのコンテナ間で通信させてリバースプロキシを作る

サーバを再構築するついでに、これまでサーバに直nginxなり各種サービスを入れていたのを、Dockerコンテナに載せてみることにした。

プライベートなページもいくつかあったり、監視ソフトの管理画面もあるので、その辺隠しておきたいので、nginxでリバースプロキシにして、BASIC認証でなんちゃって防御してるんだけど、ぐぐってもnginxでリバースプロキシを作る方法(というか、他のコンテナと通信する方法)がいまいち出てこなかったので、調べてなんとかした。

構成

こんなかんじ

f:id:grugrut:20171015210153p:plain

  • nginxがコンテナで動作していて、TCP80とホストのTCP80を対応させておく
  • /grafanaにアクセスされたら、grafanaにアクセスできるようにする
  • grafanaはnginxとは異なるコンテナで動作しており、grafanaはtcp3000で待ち受けている

設定

docker-composeを使っている

nginx側
  • docker-compose.yml
version: '2'
services:
  webserver:
    image: nginx
    volumes:
      - /path/to/www:/usr/share/nginx/html
      - ./default.conf:/etc/nginx/conf.d/default.conf
    ports:
      - "80:80"

networks:
  default:
    external:
      name: shared
  • nginxの設定
(前略)

        location /grafana/ {
          proxy_pass http://grafana:3000/;
        }

(後略)
grafana側
  • docker-compose.yml
version: '2'
services:
  grafana:
    image: grafana/grafana
    volumes:
      - ./grafana.ini:/etc/grafana/grafana.ini
    expose:
      - "3000"

networks:
  default:
    external:
      name: shared
  • grafanaの設定
root_url = http://example.com/grafana
設定のポイント

nginxのリバースプロキシ設定の、URLを、docker-compose.ymlで設定したサービス名にすること。
ここをlocalhostにしたり、ブリッジのIPアドレスにするとうまくいかない。

また、grafana側は、3000ポートをホストと結びつける必要はない(ホスト内部でしか通信しない)ので、portではなくてexposeでよい。

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

WSLでelectronが動作するようになった

以前、以下の記事を書いた。

grugrut.hatenablog.jp

そして、気付いたら、githubにissueができていて、かつ修正がされていた。

dbus problems when trying to run electron · Issue #2295 · Microsoft/BashOnWindows · GitHub

BashOnWindowsのリリースノートを見てみると、ビルド16273で修正されたらしい。

Bash on Ubuntu on Windows - Release Notes

今のところWindows Insider Programに参加していないとこのビルドは受けとれないはずだけど、きっと予定されている大型アップデート 「Windows 10 Fall Creators Update」にはとりこまれることでしょう。

ためしにHello, worldだけさくっと書いてみたけど、こんなかんじで如何にもな画面が表示される。

f:id:grugrut:20170908220314p:plain

試せてないけど、以前だめだったphantomjsなんかも動くようになってるのかな?

hubotでinfluxdbの収集データをグラフ化してSlackにアップロードする

自鯖の性能値管理に、InfluxdbをはじめとするTICKスタックを使ってるのだけど、なんか閾値設定がうまくいかなくて、閾値をまたぐたびにKapacitorがアラートを投げてきてうっとうしくなってきた。

そこで、hubotで定期的に収集したデータをグラフにして、slackにアップロードするようにしてみた。

ソースコードはこちら

github.com


グラフ化には、chartjs-nodeを使っている。canvasだったりchartjs、d3のNode.js用ライブラリがいろいろとあって、とくに最近実はスパイウェア混入してた事件とかもあって心配なんだけど、多分大丈夫のはず。

また、Hubotは一般的にはcoffee-scriptを使って書くようだけど、いまさらcoffee-scriptは微妙だと思って、pure javascriptで書いてる。

    var chartNode = new ChartjsNode(400, 300);

    request.get({url:'http://localhost:8086/query?pretty=true&db=monitoring&q='+encodeURIComponent('select mean(' + key +') from ' + name + ' where time > now() - 24h GROUP BY TIME(10m)')},
                function(error, response, body) {
                    if (error) {
                        console.log(error);
                        console.log(response);
                        return;
                    }
                    var parsedJson = JSON.parse(body);
                    var label = [];
                    var data = [];
                    for (let value of parsedJson['results'][0]['series'][0]['values']) {
                        var d = new Date(value[0]);
                        label.push(("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2) + ":" + ("0" + d.getSeconds()).slice(-2));
                        data.push(value[1]);
                    }
                    
                    chartNode.drawChart( {
                        type: 'line',
                        data: {
                            labels: label,
                            datasets: [{
                                label: parsedJson['results'][0]['series'][0]['name'],
                                data: data,
                                backgroundColor: "rgba(255, 0, 0, 0.5)"
                            }]
                        },
                        options: {
                            scales: {
                                yAxes: [{
                                    ticks: {
                                        beginAtZero: false
                                    }
                                }]
                            }
                        }})
                        .then(() => {
                            return chartNode.getImageStream('image/png');
                        })
                        .then(streamResult => {
                            return chartNode.writeImageToFile('image/png', '/tmp/testimage.png');
                        })

                        });
                    
                });
};

request使って、json型のデータをinfluxdbから取得して、最終的に/tmp/testimage.pngを作る。

そんなに複雑なことしてないつもり。

request.post({url:'https://slack.com/api/files.upload',
              formData: {
               token: process.env.HUBOT_SLACK_TOKEN,
               filename: 'testimage.png',
               file: fs.createReadStream('/tmp/testimage.png'),
               channels: 'develop'
              }},
             function(error, response, body) {
             });

作った/tmp/testimage.pngをslackにアップロードする。


アップロードされるグラフがこんな感じ

f:id:grugrut:20170805193356p:plain

いいかんじですね。

毎日コミット緑化計画とTILリポジトリ

なんか、時代遅れ感もするふたつのテーマですが

毎日githubに草を生やすという運動があります。一応補足しておくと、githubで管理しているリポジトリにコミットしたりissue書いたりといったcontributionをすると、githubのユーザプロファイルの活動記録が緑色になるので、草生やすといったり、緑化といったりします。(ingressじゃないんで、水没はしない)

私もさいきん、エンジニアリング的なことがご無沙汰になってきた気がしていて、危機感を覚えたので6月末から緑化しはじめました。

はじめてから3週間たったけど、飲み会で深夜まで飲んでた日をのぞいて、一応毎日なにかしらしています。

本来であれば、毎日コードを書くことで

  • ゲームとかそういった誘惑にまけずに、30分でもいいからソフトウェアエンジニアとして活動できる
  • 塵もつもればなんとやら、な感じで、成果が出る
  • 毎日コードに触れていると、頭のコンテキストスイッチの負担が小さくなりアイディアが生まれやすい

といったメリットがあるらしいです。

ただ、実際習慣化するまでは非常にきつい。どうしても昼間の仕事中はgithubやらの開発はできないので、無理がでてきてしまいます。

そうすると、本来であれば今日あそこまでできそうだけど、やりきってしまうと明日のコミットネタがなくなってしまうので、残りは明日にしよう、とか、何もできなかったからドットファイルだけちょっと更新しとこう、とか、なんかコミットが義務的になってしまいます。少なくとも自分はそうでした。

本来は、自己研鑽というか、自身のためを目的としてやっていたはずなのに、コミットすること自体が目的となるようなマインドでは本末転倒というものです。

正直そんなマインドでやっても苦痛なだけなので、もうやめようと、毎日緑化をはじめて2週間ぐらいで思ったのですが、そこで出会ったのがtilリポジトリです(なんか青汁の宣伝番組みたいなノリだな)。

tilリポジトリは、2016年の頭ぐらいから話題になっていたらしく、「Today I Learned」の略で、今日自分が学んだことをまとめる自習リポジトリらしいです。

githubはorg-modeだったり、markdownで書いたものが、ページ上で見れるし、シンタックスハイライトもあるので、コードスニペットをまとめておくのにも便利。別にqiitaに書いてもいいんだろうけれど、qiitaには本の感想は書きづらいし、なによりポエムばかりだと自分が逆の立場で見たらキレると思うので、qiitaにポエムは書きたくない。フィードバックがほしければはやりのプラットフォームにのっかっといたほうがよい面もあるのですが。

このtilリポジトリの大きな特徴は、学んだことをまとめるので、INPUTもコミットネタになるということです。よく毎日緑化の文脈で言われる、アウトプット偏重になってしまい、インプットがおろそかになってしまうので緑化はやめた、というのも防げます。

現に、最近ちょっと自身が、家でコード書きたい欲が下がり、かわりに別の趣味のほうのウェイトが上がっているので、毎日コミットが、だいたい読書記録になってます。

どうしても何もできないときは、今度読む予定の本のファイルだけ作っておくのですが、一応githubに公開しているという体面上、あまり空ファイルばっかり作るのも抵抗があり、良い歯止めになりそう。

そんなわけで、githubの1リポジトリでほそぼそとやってます。貯まったら、blogなりを自動生成できるようにするのもおもしろそうだなー。

github.com

topで負荷の高いプロセスN個を取り出す

以下の記事の通り、最近は、influxdbをはじめとするTICKスタックで、サーバのメトリクスを収集して問題ないかみている。

grugrut.hatenablog.jp

で、現在存在していないメトリクスで欲しいものは、自分でプラグインを書いてプルリク送ってみたりしてる。

github.com

裕福な人は違うかもしれないけど、一般的にVPSとかクラウド系のリソースで最初に厳しくなるのはメモリだと思う。ディスクだったりCPUが不足することはそうそうないけど、たいていメモリは50%は軽く越えてしまう。僕自身もその例に違わず、メモリが常日頃から不足する状況が続いていた。

でもろくに分析してないので、メモリが不足している原因が、1つのプロセスが食ってるのか、複数のプロセスに原因があるのかわかっていなかった。

直感的には、Jenkins(つまりはjava)プロセスがリソース食ってるのはわかってたんだけど、メモリ使用率に変動があったときに、どこに原因があるかはわからずじまいで対策が取りようになかったので、プロセスごとのCPU使用率、メモリ使用率をとってみることにした。全部取ると大変なことになってしまうので、今回はトップ5だけ取ってみる。

データの取得方法

もちろんgolangでちゃんとプラグインとして書いてもよいのだけど、面倒なので今回はtelegrafのexecプラグインを使う。execプラグインはコマンドを実行し、規定のフォーマットで標準出力に出力されたものを値として取り込むことができる。詳細は以下を見てほしい。

telegraf/README.md at master · influxdata/telegraf · GitHub

で、その形式というのが、

メトリクス名,タグ フィールド

なので、それに合わせて出力してやる必要がある。

スクリプト

topコマンドでさくっととれる。

#!/bin/bash

top -b -n 1 | tail -n +8 | head -5 | awk '{print "process,process="$12" cpu="$9}'
top -b -n 1 -o %MEM| tail -n +8 | head -5 | awk '{print "process,process="$12" mem="$10}'

topは -bオプションをつけるとバッチモードで標準出力にそのまま結果が流れる。 -nオプションはデータを取る回数。通常は無限ループするけど、-n 1としてやることで1回出力すればコマンドが終了する。その後のtailは、topコマンドのヘッダを消すため。その後のheadは、上位のプロセス5個を取り出している。

topコマンドはデフォルトだとCPU使用率の高い順に出力されるが、-oオプションにより、ソートするカラムを選ぶことができる。2つめのtopコマンドでは、-o %MEMとして、メモリ使用率の高い順にソートされるようにしている。

これをターミナルで実行すると以下のような結果になる。

$ process.sh
process,process=top cpu=12.5
process,process=systemd cpu=0.0
process,process=kthreadd cpu=0.0
process,process=ksoftirqd/0 cpu=0.0
process,process=kworker/0:+ cpu=0.0
process,process=java mem=29.1
process,process=influxd mem=8.4
process,process=node mem=3.2
process,process=php-fpm mem=3.1
process,process=php-fpm mem=2.9

あとは、telegrafの設定を変えて、execプラグインでこのシェルスクリプトを実行してやればOK。

 [[inputs.exec]]
   ## Commands array
    commands = [
      "/path/to/process.sh"
    ]
#   commands = [
#     "/tmp/test.sh",
#     "/usr/bin/mycollector --foo=bar",
#     "/tmp/collect_*.sh"
#   ]
#
#   ## Timeout for each command to complete.
   timeout = "5s"
#
#   ## measurement name suffix (for separating different commands)
#    name_suffix = "_mycollector"
#
#   ## Data format to consume.
#   ## Each data format has it's own unique set of configuration options, read
#   ## more about them here:
#   ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
   data_format = "influx"

このコマンドのデータフォーマットは、influx形式なので、data_formatもinfluxとしておくこと。

Chronografで見てみる

適当なタイミングでキャプチャした結果がこんな感じ。画面左側がCPU使用率、右側がメモリ使用率。そして、上側がサーバ全体、下側が上位5プロセスのもの。

f:id:grugrut:20170710002829p:plain

こうやって見ると、CPU使用率は一瞬を切り取るためか、あまり相関がないが、メモリ使用率は相関がある。はっきりわかんだね。

左側の赤色の丸は、プロセスが追加で起動したためサーバ全体のメモリ使用率が増え、右側の緑色の丸では、トップのプロセスのメモリ使用率が下がったのでサーバ全体のメモリ使用率も下がっていることがきれいにわかる。
プロセスごとのグラフは、現状それぞれの値で描いているけれど、スタックしてつみあげグラフにしてみてもおもしろそう。

上記のスクリプトは自由に使ってもらって構いませんが、既知バグがあって、同じ名前のプロセスがある場合にうまくinfluxdbに追加できないので要注意(タグがプロセス名なので、かぶってしまう)。

きれいにしてから、golangでリライトしてプラグインにしてもいいんだけど、すでにprocessesプラグインがあって名前に迷うなー。

Slackとorg-modeを連携したかった話

情報収集してますか?


これまでrssリーダ使ってたのも未読がたまってしまい鬱陶しかったので、rssをslackに移行するだけの個人Slackに今は切り替えてます。
ただ、rssのころもそうでしたが、後でよむ的操作と、保存しておきたい操作が、slackの場合難しいです。個人Slackなんだから、pinでもなんでもすりゃいいんだけど、再集約は別の場所にしたい。無料版だとslack、メッセージ数に制限があるしね。

iftttとzapier

というわけで、スターをつけたメッセージに対し、なにかしらしたかった。

そういう用途であれば、iftttとzapierあたりがあげられます。気にはなってたけど、これまで使ったことなく、必要性を感じることもこれまでなかったのですが、遂に使うことに。

で、結論ですが、zapierを使うことにしました。理由は明快で、スターをつけたメッセージをトリガーとすることが、iftttではできなかった。iftttは何らかのトリガーでslackに投稿することはできても、slackをトリガーとすることは現状できなかったのです。
あと、MicrosoftもFlowとかいうのを最近出したようですが、これもslackをトリガーとすることはできないらしい。
zapierの懸念としては、無料プランだと、月100回までしかタスクを実行できないらしい。せっかく作成したばかりだけど大丈夫かな?

スターをつけたメッセージをトリガーにする

というわけでzapierであります。

zapierではこういった処理のことをzapと呼んでいて、「Make a zap」ボタンで簡単に作ることができます。試しにSlackでスターをつけたメッセージを、後で読むサービスのPocketに投入する、というのを作ってみたら、ポチポチするだけで簡単に作れてしまいました。超簡単。

f:id:grugrut:20170625094352p:plain

org-modeとの連携

さて、前置きがかなり長くなりましたが、org-modeとの連携です。私は、org-modeで使っているorgファイルを、DropboxスマホやPC群で共有しています。
zapierのインテグレーションを見ていると、Dropboxがあり、インテグレーションの動作に「Append Text File」というのがあったので、これでできるのでは? とやってみることにしました。
設定はこんな感じ。

f:id:grugrut:20170625094252p:plain

結果

f:id:grugrut:20170625095011p:plain

まあ、設定画面にそんなこと書いてあったので、嫌な予感はしてたのですが、勝手に拡張子.txtを追加されてしまいました。.orgって拡張子自分でつけてるのに。
ただ中身を見てみると
f:id:grugrut:20170625095801p:plain
という感じで、ちゃんと複数行にわたって追記がされているので良いかんじ。

拡張子を変える方法があればもっとよくなるのに、この悲しみはどこに伝えるのがよいのだろうか。