2019年6月25日火曜日

golang でリトライ処理を試してみる

概要

retry-go というライブラリがあったので試してみました

環境

  • macOS 10.14.5
  • go 1.11.5
  • dep 0.5.0
    • retry-go 2.3.0

基本

  • vim $GOPATH/src/github.com/hawksnowlog/a/main.go
package main

import (
    "errors"
    "fmt"
    "github.com/avast/retry-go"
    "math/rand"
    "time"
)

func random() error {
    rand.Seed(time.Now().UnixNano())
    n := rand.Intn(10)
    if n >= 5 {
        return nil
    }
    return errors.New("error")
}

func main() {
    fmt.Println("start")
    err := retry.Do(
        func() error {
            ret := random()
            return ret
        },
        retry.DelayType(func(n uint, config *retry.Config) time.Duration {
            fmt.Println(n)
            return 0
        }),
    )
    fmt.Println(err)
}
  • dep init
  • go fmt github.com/hawksnowlog/a
  • go build github.com/hawksnowlog/a
  • ./a

少し解説

random メソッドは今回のロジックには関係ないので省略します
内容は 0 から 9 の数字をランダムに返すだけです

リトライさせたい処理を retry.Do で囲みます
デフォルトではリトライ回数は 10 になっています
後でリトライ回数を変更する方法を紹介します
retry.Do メソッドは 2 つの引数を持ちます
一つ目はリトライさせたい関数でもう一つは Option になります
リトライする条件は対象のメソッドが error の場合にリトライします
errornil の場合にはリトライせず次の処理に進みます

上記では Option の部分に retry.DelayType メソッドを指定しています
このメソッドの返り値が Option になっています
さらに retry.DelayType にはメソッドを指定できます
これはもし error が返ってきてリトライする場合にリトライ前に実施したい処理を指定することができます
上記ではリトライ前に fmt.Println しかしていませんが何かさせたい場合にはここに記載します
n uint にはリトライ回数が代入されています
もしデフォルトの 10 回のリトライの場合には 0 からカウントして最大 8 までインクリメントします

返り値が time.Duration になっていますがここを 0 以外にするとリトライ前にウェイトさせることができます

リトライ後に少しディレイを持たせる

例えばリトライ回数 x 1秒待たせる場合には以下のようになります

func main() {
    fmt.Println("start")
    err := retry.Do(
        func() error {
            ret := random()
            return ret
        },
        retry.DelayType(func(n uint, config *retry.Config) time.Duration {
            fmt.Println(n)
            return time.Duration(n) * time.Second
        }),
    )
    fmt.Println(err)
}

return time.Duration(n) * time.Second とすることで実現できます

リトライ回数を変更する

retry.Attempts を使います
これも Option を返すので retry.DelayType の後に続いて書けば OK です

func main() {
    fmt.Println("start")
    err := retry.Do(
        func() error {
            ret := random()
            return ret
        },
        retry.DelayType(func(n uint, config *retry.Config) time.Duration {
            fmt.Println(n)
            return time.Duration(n) * time.Second
        }),
        retry.Attempts(3),
    )
    fmt.Println(err)
}

上記の場合は 10 -> 3 回リトライします

最後に

retry-go を試してみました
既存の処理に対してリトライ処理を入れるのも簡単にできます

またリトライ時には必ずといっていいほど出る Exponential Backoff も簡単に実装できます (参考: BackOffDelay)

参考サイト

2019年6月24日月曜日

Zabbix4.2 でネットワークディスカバリ機能を使ってみた

概要

指定の IP の範囲に Zabbix Agent がいる場合にそれを検知して何かしらのアクションを起こすことができます
今回は検知したホストを自動で Hosts に登録することをやってみました
今回は docker 上で機能を試してみました

環境

  • Zabbix サーバ
    • Ubuntu 16.04 LTS
    • docker 18.09.6
    • Zabbix Server 4.2
  • Zabbix エージェント
    • macOS 10.14.5
    • docker 18.09.2
    • Zabbix Agent 4.2

Zabbix サーバ起動

Ubuntu 16.04 上で起動します
前回の記事で紹介しているのでそちらを参考にしてください
Zabbix サーバが起動していればいいので docker でなくても OK です

Zabbix Agent 起動

  • docker run -d -e ZBX_HOSTNAME="c2" -e ZBX_SERVER_HOST="192.168.99.200,172.17.0.1" -p 10050:10050 zabbix/zabbix-agent

こちらもコンテナでなくて OK です

ディスカバリ作成

まずはディスカバリを作成します
特定のネットワーク上にエージェントが出現したら発見させるようなディスカバリにします

Configuration -> Discovery
で「Create discovery rule」or 既存のルールを選択します
下記は既存の「Local network」を変更しています

  • IP range・・・192.168.99.1
  • Update interval・・・10s
  • Checks・・・Zabbix agent "system.uname"
  • Device uniqueness criteria, Host name, Visible name・・・Zabbix agent "system.uname"

IP range は 192.168.99.1-254192.168.99.0/24 などの範囲指定フォーマットもサポートしています

Update interval は好きな値を設定してください
今回はテストなので 10s にしています
数字が小さいと負荷が上がります

Checks は zabbix_agent -s 192.168.99.1 -k system.uname の値が取得できるかどうか判断するようにします
他にも ping や特定の tcp ポートでもチェックできます

Device uniqueness criteria, Host name, Visible name はすべて `Zabbix agent "system.uname" にしていますがこれも好きなものを設定してください
例えば Host name を IP address にするとホストが登録された際に IP で登録されます

作成 or 編集後のディスカバリは以下のような感じです

アクション作成

次に作成したディスカバリが真の場合に実行するアクションを作成します

Configuration -> Actions
で右上のプルダウンの「Event source」を「Discovery」にします
「Create action」でも OK です
以下は既存の「Auto discovery. Linux servers.」を編集しています

  • Conditions・・・Discovery rule equals Local network -> Add を押す
  • Enabled・・・チェック

次に Operations タブを選択します
Operations -> New を選択します

  • Operations・・・Add host -> Add を押す

これで OK です
Update を押して作成しましょう

作成 or 編集後のアクションは以下の通りです

動作確認

しばらくするとディスカバリされホストが追加されるはずです
まずは Monitoring -> Discovery を見てみましょう
ここでホストが見つからないとアクションも実行されます

アクションも問題なく実行されれば Configuration -> Hosts にホストが登録されています
今回は system.uname を Host name に使っているので以下のように少し長いホスト名として登録されます

Zabbix Server のログ的には 177:20190621:040419.777 enabling Zabbix agent checks on host "Linux be1c04e1d4aa 4.9.125-linuxkit _1 SMP Fri Sep 7 08_20_28 UTC 2018 x86_64": host became available が出ていれば成功です

トラブルシュート

手順的にはサクっとできますが実はいろいろハマっています、、
自分がトラブルシュートした方法をいくつか紹介します

Zabbix Server のロギングレベルを上げる

docker の場合は .env_srvZBX_DEBUGLEVEL=3 を 4 にすれば OK です
これで再度 zabbix-server コンテナを down -> up すれば OK です

IP range を短くする

ディスカバリのルールはあっているのに中々 Monitoring -> Discovery に登場しない場合はこれを試してみてください
確証はないですが Zabbix Server は当然していの範囲を精査します
アクションや発見したホストの登録を実行するタイミングがもしかすると精査後になっているので unreachable な IP が多いほどアクションが実行されるタイミングが遅くなっているのかもしれません
(ソースまで終えていないので自信なし)

最後に

Zabbix4.2 でディスカバリの機能を試してみました
機能自体は昔からあるので今更感がありますが UI はだいぶ変わっているのでその辺りは参考になるかなと思います

サーバもエージェントもコンテナなのでバイナリを直接ホストで動かしてる場合は少し設定値は変わるかなと思いますが流れは基本的に同じかなと思います

参考サイト

2019年6月23日日曜日

Zabbix4.2 で Inventory 機能を使ってみた

概要

Inventory 機能はアイテムで取得した値を Inventory という特別な領域に登録することができます
Inventory に登録した情報を使ってホストを検索したり GROUP BY してカウントしたりできます
今回は docker 上で機能を試してみました

環境

  • Zabbix サーバ
    • Ubuntu 16.04 LTS
    • docker 18.09.6
    • Zabbix Server 4.2
  • Zabbix エージェント
    • macOS 10.14.5
    • docker 18.09.2
    • Zabbix Agent 4.2

Zabbix サーバ起動

Ubuntu 16.04 上で起動します
前回の記事で紹介しているのでそちらを参考にしてください
Zabbix サーバが起動していればいいので docker でなくても OK です

Zabbix Agent 起動

Agent も docker で起動します
ホストを準備するのが面倒な場合に便利です

  • docker run -d -e ZBX_HOSTNAME="c1" -e ZBX_SERVER_HOST="192.168.99.200,172.17.0.1" -p 10050:10050 zabbix/zabbix-agent

ZBX_HOSTNAME はサーバ上に登録するホストの名前と同じにします
マシンのホスト名である必要がありません
ZBX_SERVER_HOST は Zabbix サーバの IP アドレスを指定します
2 つ指定しているのは Zabbix サーバの Incomming と Outgoing の IP が docker の場合異なっているからです
普通に VM などで Zabbix サーバを起動している場合は Incomming と Outgoing が同じになるので 1 つで OK です

Zabbix Agent コンテナが起動したログを確認してみましょう

  • docker logs -f 069e4e9ee319

active check configuration update from [172.17.0.1:10051] started to fail (cannot connect to [[172.17.0.1]:10051]: [111] Connection refused) というログが出ていますが無視で OK です
先程説明した Zabbix サーバコンテナの Outgoing IP にはアクセスしようとしているため出ているだけです
もし Zabbix サーバコンテナの Outgoing IP を指定しない場合は以下のエラーになりうまく監視対象に入りません

failed to accept an incoming connection: connection from "172.17.0.1" rejected, allowed hosts: "192.168.99.200"

Configuration -> Hosts 登録

サーバとエージェントが起動したらサーバ側に監視するホストの情報を登録しましょう (今回はテスト用のコンテナですが)
Zabbix は pull 型の監視がベースのためホスト側に監視対象の情報がないとデータの収集が始まりません

UI にアクセスして Configuration -> Hosts -> Create Host を選択します
そして以下のように登録します

  • Host name・・・c1
  • Groups・・・Linux servers
  • Agent Interfaces -> IP address ・・・192.168.99.1

まだ登録しません
Templates タブを選択し以下の通り入力します

  • Link new templates・・・Template OS Linux
  • Add を押す

忘れずに Add を押しましょう
これでホストを登録します

Inventory にデータを登録するためのアイテムを登録する

先程登録したホストに新規でアイテムを登録します
テンプレートを紐づけたのでテンプレートにアイテムを追加しましょう

Configuration -> Templates から Template OS Linux を選択します

そして Items タブを選択して Create tem を選択します
入力フィールドが出るので以下のように入力しましょう

  • Name・・・system.sw.arch
  • Key・・・system.sw.arch
  • Type of information・・・Text
  • Populates host inventory field・・・HW architecture

Name は何でも OK です
Populates host inventory field も正直何でも OK です
取得できるアイテムにあった項目を選択してください
今回はシステムアーキテクチャが取得できるのでそれっぽいのを選択しました

ホストの Inventory を有効にする

最後にホストの Inventory を有効にします
デフォルトではアイテムで取得できたとしても Inventory には登録してくれません
まずは Configuration -> Hosts で c1 ホストを選択しましょう

そして Inventory タブを選択して Automatic を選択します
すると Name や OS で使われるアイテムが右に表示されます

更に下に行くと HW architecture の欄があるので登録したアイテム名が割り当てられていることを確認しましょう

動作確認

しばらく (30秒) するとデータが入ってきます
まずは Monitoring -> Latest data で確認してみましょう
アイテム登録時にアプリケーションを指定していないので other にあります

あとは Inventory を確認してみましょう
Inventory -> Overview で右上のプルダウンから HW architecture を選択します
すると x86 ホストを GROUP BY してカウントしてくれるのが確認できると思います
今回は 1 台しかいないので 1 になれば OK です

Hosts タブでは Inventory 情報から検索して対象の Inventory を持つホストを探すことができます

最後に

Zabbix4.2 で Inventory 機能を試してみました
Inventory 機能自体は 2 系から登場しているので今更感しかないですがよくわからに機能だったので試してみました
うまく使えばおもしろそうなデータが見えるようにはなりそうですが、正直監視に必須な機能ではないかなと思います

今回はすべて docker 上で行いましたがバイナリでも同じようにできると思います

参考サイト

2019年6月22日土曜日

Zabbix4.2 を docker で立ち上げてみた

概要

公式の docker-compose ファイルがあったので試してみました

環境

  • Ubuntu 16.04 LTS
  • docker 18.09.6
  • docker-compose 1.24.0
  • Zabbix 4.2

Zabbix サーバ構築

  • git clone https://github.com/zabbix/zabbix-docker.git
  • cd zabbix-docker

デフォルトブランチは master ではなくバージョンのブランチになっているようです

  • git branch

=> 4.2

いくつか docker-compose ファイルを選択できます
alpine + mysql だったり ubuntu + postgres などが選択できます
今回は alpine + mysql にしました
また _local を使うと git clone した各種リソースを使ってイメージをビルドしてから立ち上がります

  • docker-compose -f docker-compose_v3_alpine_mysql_latest.yaml up -d

イメージのダウンロードが始まるので待ちましょう
最終的に 9 つのコンテナが起動すれば OK です

  • docker-compose -f docker-compose_v3_alpine_mysql_latest.yaml ps
               Name                             Command                       State                         Ports              
--------------------------------------------------------------------------------------------------------------------------------
zabbix-docker_db_data_mysql_1        sh                               Exit 0                                                   
zabbix-docker_mysql-server_1         docker-entrypoint.sh mysql ...   Up                                                       
zabbix-docker_zabbix-agent_1         /sbin/tini -- /usr/bin/doc ...   Up                                                       
zabbix-docker_zabbix-java-           docker-entrypoint.sh             Up                                                       
gateway_1                                                                                                                      
zabbix-docker_zabbix-proxy-mysql_1   /sbin/tini -- /usr/bin/doc ...   Up                      0.0.0.0:10071->10051/tcp         
zabbix-docker_zabbix-proxy-          /sbin/tini -- /usr/bin/doc ...   Up                      0.0.0.0:10061->10051/tcp         
sqlite3_1                                                                                                                      
zabbix-docker_zabbix-server_1        /sbin/tini -- /usr/bin/doc ...   Up                      0.0.0.0:10051->10051/tcp         
zabbix-docker_zabbix-snmptraps_1     /usr/bin/supervisord -c /e ...   Up                      0.0.0.0:162->162/udp             
zabbix-docker_zabbix-web-apache-     docker-entrypoint.sh             Up (health: starting)   0.0.0.0:443->443/tcp,            
mysql_1                                                                                       0.0.0.0:80->80/tcp               
zabbix-docker_zabbix-web-nginx-      docker-entrypoint.sh             Up (healthy)            0.0.0.0:8443->443/tcp,           
mysql_1                                                                                       0.0.0.0:8081->80/tcp

各役割ごとにコンテナが起動しています
ホストのポートを結構たくさんバインドするのですでに使っているポートがある場合は該当のプロセスを停止してから起動しましょう

管理画面にアクセスするには http://192.168.99.200 などのホストの IP に接続すれば OK です
パスワードは Admin/zabbix です (これはいいのだろうか、、)

ログインするといきなり zabbix-agent が zabbix-server を見つけられないエラーが、、

バグっぽいですが解決してあげます

  • docker-compose -f docker-compose_v3_alpine_mysql_latest.yaml logs zabbix-agent

no active checks on server [zabbix-server:10051]: host [07890bd93e4d] not found なるエラーが出ていました
この 0be108601a3f は zabbix-agent のホスト名でした

設定ファイルを確認してみます

  • docker-compose -f docker-compose_v3_alpine_mysql_latest.yaml exec zabbix-agent grep -v '^\s*#' /etc/zabbix/zabbix_agentd.conf |grep -v '^\s*$'

特に問題なさそうです
エラー的には zabbix-server が 0be108601a3f という名前のホスト名を探せないということなので怪しいのは Zabbix Server 側っぽいです
サーバ側のログを見てみます

  • docker-compose -f docker-compose_v3_alpine_mysql_latest.yaml logs zabbix-server | grep 'cannot send list of active checks to'

cannot send list of active checks to "172.16.239.6": host [0be108601a3f] not found

つまり agent が 0be108601a3f というホストが Zabbix Server だよ送っているのに実際に zabbix-server コンテナが 0be108601a3f に聞きにいこうとしてもそんなホストは見つからないと言っているのです

で実際どこを変更すれば良いかと言うと Configuration -> Hosts で Zabbix Server の設定を開きます
そして Host name に zabbix-agent 入力し Agent interfaces の DNS name にも zabbix-agent を入力します
Connect to のトグルスイッチも DNS 側に変更しましょう
これで Zabbix Server 用の agent である zabbix-agent コンテナに名前でアクセスできるようになるため問題が解決します

また実は YAML ファイルも変更しています
やらなくてもステータスは緑になりますがエラーログが出続けるのでやってもよいかなと思います

  • git diff
git diff
diff --git a/docker-compose_v3_alpine_mysql_latest.yaml b/docker-compose_v3_alpine_mysql_latest.yaml
index 166b431..d82e759 100644
--- a/docker-compose_v3_alpine_mysql_latest.yaml
+++ b/docker-compose_v3_alpine_mysql_latest.yaml
@@ -269,6 +269,7 @@ services:

  zabbix-agent:
   image: zabbix/zabbix-agent:alpine-4.2-latest
+  hostname: zabbix-agent
   ports:
    - "10050:10050"
   volumes:

ただこれは結局 Zabbix Server のためのエージェントではなく zabbix-agent コンテナのエージェントの情報を監視しているだけなので意味はありません

proxy のエラーも出ている

以下のエラーも Zabbix Server のログに出ていました
必須ではないですが何となく対応してみました

zabbix-server_1            |    175:20190619:095634.153 cannot parse proxy data from active proxy at "172.16.238.7": proxy "zabbix-proxy-mysql" not found
zabbix-server_1            |    178:20190619:095634.154 cannot parse proxy data from active proxy at "172.16.238.4": proxy "zabbix-proxy-sqlite3" not found

これも UI にデータを入れれば OK です
Administration -> Proxies -> Create proxy でエラーになっているホストと IP アドレスの情報を登録すれば OK です

  • Proxy name・・・zabbix-proxy-mysql
  • Proxy address・・・172.16.238.7

  • Proxy name・・・zabbix-proxy-sqlite3
  • Proxy address・・・172.16.238.4

ステータスが緑になれば OK です

ただしこの方法だと各プロキシの IP がコンテナの再作成で変わる可能性があるので、その場合は再度登録してください

ZabbixAgent をコンテナとして動作させるには

方法としてはシステムディレクトリをマウントすればエージェントをコンテナで起動できるっぽいのですがあまりよろしい感じはしません (参考)
正直自分でも zabbix/zabbix-agent コンテナの使い方というか用途というか使う場面が思い浮かびません
docker ホストの監視をしたい場合は素直に zabbix-agent をインストールするのが良いと思います

強いて言えば適当なホストを追加したいときに zabbix-agent コンテナを立ち上げればホストの追加になるのでテスト用途として使う感じかなと思います

コンテナを監視するには

Zabbix Docker Monitoring というコンテナを開発してくれている方がいるのでこれを使います
テンプレートなどもあるのでそれを使えばアイテムなども Zabbix Server に登録されます
Zabbix Docker Monitoring については別記事で紹介したいと思います

やり直したい場合は

MySQL などのデータはコンテナを再作成しても残ります
なので再度一からやり直したい場合は以下のディレクトリのデータを削除しましょう

  • sudo rm -rf zbx_env/var/lib/mysql/*

最後に

Zabbix を docker で使う場合には

  • Zabbix Server はコンテナで OK
  • Zabbix Agent は素直にバイナリをホストにインストールする
  • コンテナの監視には Zabbix Docker Monitoring を使う

というのが無難かなと思います

2019年6月21日金曜日

goquic 超入門

概要

QUIC (Quick UDP Internet Connections) は UDP 上で TCP のデータのやり取りをする高速かつ安全なプロトコルです
現在も開発が進められていますが golang でとりあえず触れる環境があったので試してみました

環境

  • Ubuntu 16.04 LTS (vagrant)
    • cmake 3.5.1
    • ninja-build 1.5.1
    • gcc 5.4
    • golang 1.12.6
  • goquic (rev: 1e49c0fcf10725575edc12e5834bc7d003da1581)

golang インストール

  • wget 'https://releases.hashicorp.com/vault/1.1.3/vault_1.1.3_linux_amd64.zip'
  • sudo tar -C /usr/local -xzf go1.12.6.linux-amd64.tar.gz
  • vim ~/.bashrc
export GOPATH="/home/vagrant/go"
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

一度ログアウトして再度ログインしましょう

ビルドに必要なパッケージのインストール

  • sudo apt -y install cmake
  • sudo apt -y install ninja-build

これ以外に g++ or gcc などの C/C++ のコンパイラが必要になります
自分はすでにインストールされていたので省略しています
各種バージョンは環境のところに記載しています

ソース取得

  • go get -u -d github.com/devsisters/goquic

goquic はソースからビルドして動作させます
go get で取得しましょう

ビルド

  • cd $GOPATH/src/github.com/devsisters/goquic
  • ./build_libs.sh

でビルドが始まります
失敗する場合はエラー内容を見てトラブルシューティングするしかありません
自分は一発でいけたので同じ環境 (vagrant + ubuntu/xenial) なら問題なくビルドできると思います
完了すると libgoquic.a が作成されます

  • ls -l lib/linux_amd64/libgoquic.a

server と client のサンプルをビルドする

実際に libgoquic.a を使ったサンプルのサーバとクライアントがあるのでそれをビルドして使ってみます

  • go build $GOPATH/src/github.com/devsisters/goquic/example/server.go
  • go build $GOPATH/src/github.com/devsisters/goquic/example/client.go

他に reverse_proxy.go もありますが特に使いませんでした

サーバを起動する

サーバの起動には証明書と鍵ファイルが必要になります
自分は Let’sEncrypt で取得した証明書 を使いましたが openssl や Mac であればキーチェインアクセスでも OK です

作成した証明書と鍵を指定してバイナリを実行しましょう

  • ./server -cert fullchain.pem -key privkey.pem

これで 8080 で LISTEN したサーバが起動します

動作確認

確認方法はコマンドとブラウザでもできます
コマンドの場合は以下のように実行すれば結果が取得できます

  • ./client -url "http://localhost:8080/numbers"

0 から 9999 までの数字が返ってくると思います
Chrome で https://192.168.99.200 にアクセスしても確認できます
証明書の警告が出ますが無視で OK です
トップページには動作確認ようのリンクが用意されています

「Numbers test」にアクセスすると先程コマンドで実行した結果と同じものがブラウザでも確認できます

「Files」はおそらくファイルの確認やダウンロードを確認するページかと思われます
デフォルトだと /tmp の内容を表示しているのでここにファイルなどをおけばリストやダウンロードの確認ができます
flag.StringVar(&serveRoot, "root", "/tmp", "Root of path to serve under https://127.0.0.1/files/")

おまけ: curl もやってみた

ヘッダ情報を確認しやすいので curl も実行してみました
QUIC を使っている場合ヘッダにいろいろと情報が付与されるようです
結果を貼っておきます

  • curl -k -sSL -D - https://localhost:8080
HTTP/1.1 200 OK
Alt-Svc: quic=":8080"; ma=86400; v="36,35,34,33,32,31,30"
Alternate-Protocol: 8080:quic
Content-Type: text/html; charset=utf-8
Trailer: AtEnd1, AtEnd2
Trailer: AtEnd3
Date: Thu, 20 Jun 2019 05:03:28 GMT
Transfer-Encoding: chunked

This HTTP response has both headers before this text and trailers at the end.<br/><a href='/numbers'>Numbers test (0~9999)</a><br/><a href='/files'>Files</a><br/>127.0.0.1:40472
Atend1: value 1
Atend2: value 2
Atend3: value 3

最後に

goquic で QUIC を使ったアプリにとりあえず触ってみました
これだけだと効果を実感することはできないので実際は QUIC を使っていない HTTP 環境と使ってる HTTP 環境で速度検証などをしたほうが良いかなと思います

golang だけではありますがサーバアプリの実装も難しそうではないので試しにチャレンジしてみるのも良いのかなと思います

2019年6月20日木曜日

docker-compose では link を指定しないでも同一ネットワーク内なら名前解決できる

概要

タイトル通りです
link が deprecated になり同一ネットワークにコンテナを配置することでホスト名でアクセスできるようになっているので動作確認してみました

環境

  • macOS 10.14.5
  • docker 18.09.2
  • docker-compose 1.23.2

docker-compose

  • vim docker-compose.yml
version: '2'
services:
  client:
    image: redis:latest
    command: ["redis-cli", "-h", "server", "info", "server"]
    depends_on:
      - "server"
  server:
    image: redis:latest

ポイントは command の部分で -h server という感じでホスト名を指定するところです
これで問題なく動作するか確認します

server が起動する前に確認のコマンドを投げないように depends_on を使っています

動作確認

  • docker-compose up -d
  • docker-compose logs client

info server の情報が表示されることを確認します
networks を指定しない場合は xxxx_default という名前のネットワークを自動で作成してそこに接続されます

  • docker inspect try_no_link_client_1 -f '{{.NetworkSettings.Networks}}'

=> map[try_no_link_default:0xc4205980c0]

参考サイト

2019年6月19日水曜日

Ruby で Dynamic Inventory 入門

概要

DynamicInventory は Ansible がスクリプトを実行しその実行結果のインベントリ情報を使って playbook を流すことができる機能です
スクリプトは出力結果が決められたフォーマットになっていればどんな言語で書いても OK です
今回は Ruby でやってみました

環境

  • macOS 10.14.5
  • ansible 2.5.5
  • Vagrant 2.1.1
  • Ruby 2.6.2p47

テストマシン

今回は Vagrant で構築していますが SSH で接続できれば何でも OK です

  • vim Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "private_network", type: "dhcp"
  config.vm.network "private_network", ip: "192.168.99.200"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "4096"
  end
end
  • vagrant up

SSH できるようにするがめ ssh-config を書き出します

  • vagrant ssh-config >> ~/.ssh/config

playbook

とりあえずテストマシンに playbook が流せる環境を作ります

  • vim example.yml
---
- hosts: role_web1
  tasks:
    - name: Install nginx
      shell: "amazon-linux-extras install nginx1.12"
      become: yes
    - name: Start nginx
      systemd:
        name: nginx.service
        state: started
      become: yes

インベントリファイルもとりあえずベタ書きします

  • vim inventory
[web1]
default

nginx をインストールして起動する playbook です
これでとりあえず実行できることを確認しましょう

  • ansible-playbook -i inventory example.yml -e 'ansible_python_interpreter=/usr/bin/python3'

Dynamic Inventory

さてここから Ruby を使った Dynamic Inventory を作成していきます
今回は特に動的に生成してる感じはないですが結果として「こんな感じの JSON が出力されれば良い」ということが理解できることを目的にしています

まずは単純なインベントリ情報を出力するスクリプトを書いてみます

  • vim inventory.rb
#! /usr/local/opt/ruby/bin/ruby
require 'json'

i = {
  :web1 => {
    :hosts => [
      'default'
    ]
  }
}
puts i.to_json
  • chmod +x inventory.rb

ファイルを指定するだけで実行できるようにシェバングを指定しています
シェバングのパスは環境によって異なると思うので適宜変更してください

このスクリプトを実行するとわかりますが単純な JSON が返ってきます

  • ./inventory.rb

=> {"web1":{"hosts":["default"]}}

このスクリプトを使って ansible-playbook を実行することができます

  • ansible-playbook -i ./inventory.rb example2.yml -e 'ansible_python_interpreter=/usr/bin/python3'

_meta

インベントリファイルには host_varsgroup_vars を書くことができます
Dynamic Inventory を使っても書くことができるので試してみました
スクリプトを以下のように書き換えましょう

  • vim inventory.rb
#! /usr/local/opt/ruby/bin/ruby
require 'json'

i = {
  :web1 => {
    :hosts => [
      'default'
    ],
    :vars => {
      :gvar => "gvalue"
    }
  },
  :_meta => {
    :hostvars => {
      :default => {
        :hvar => "hvalue"
      },
    }
  }
}
puts i.to_json

group_vars はホストグループの定義配下に vars を使って定義します
host_vars_meta を使って定義します
_meta 配下に hostvars を定義しその配下に key/value を定義することで参照することができるようになります

確認のための playbook も書き換えます

  • vim example.yml
---
- hosts: web1
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
      become: yes
    - name: Start nginx
      systemd:
        name: nginx.service
        state: started
      become: yes
    - name: Debug host_vars
      debug:
        msg: _meta host_vars is {{hvar}}
    - name: Debug group_vars
      debug:
        msg: _meta group_vars is {{gvar}}

debug を使って変数の内容を表示しているだけです
これで先程同様に実行すると変数が問題なく参照できるのが確認できると思います

  • ansible-playbook -i ./inventory.rb example2.yml -e 'ansible_python_interpreter=/usr/bin/python3'

最後に

Dynamic Inventory を Ruby で試してみました
当然ですが ansible-playbook コマンドを実行するマシンに ruby がインストールされている必要があります
少し調べた感じだと --list--host オプションを実装したほうが良さそうだったのですが実装しないでも動作しました
スクリプトがインベントリファイルの形式で出力できたほうが良い場合などは実装すると良いかなと思います

実際は API や Terraform の .tfstate ファイルなどをパースしてインベントリ情報の JSON を生成することになると思います

参考サイト