ときどきAnsible日記

主にITインフラ基盤の自動化に関する事を書いているブログです

Ansibleでテストを試してみる

お疲れ様です。伊藤です。

先日インフラの自動化に関するセミナーに参加してきました。無料のセミナーでしたがなかなかの規模で確か定員300名のところにそれ以上の応募が来て抽選になる状態。何とか当選して行ってまいりましたが、特にAnsible関連のところは人が多かった印象です。席に座れずに立ち見まで出てましたんで。。

こんなスマホ防水(防滴?)ポーチもらいました。
f:id:pj_doaa:20170810095906j:plain


でその中でインフラ試験についてもちょっと話が出ていました。簡単に言うとインフラ試験についてもAnsibleでやれるよ、みたいな話。このブログでもTestInfraというツールを使ってみようと思っていましたし、世の中的にはServerSpec全盛なので、テストを全てAnsibleに任せるのは少々敷居が高そうですが、実用できそうかどうかちょっと検討してみたいと思います。

  • Moduleによるテスト

基本的にAnsibleには冪等性という、「何度実行しても同じ結果を保証する」性質があります。
そして、実行結果から

  1. 値を変更した
  2. 値を変更していない(する必要がない)
  3. 値を変更したかったけどできなかった

がわかります。これを利用すればAnsibleを実行して「すべて値の変更する必要なし」となれば設定値の確認完了、と言えてテスト完了となります。
がしかし現実はそうはいきません。たとえAnsibleが正常終了したところでPlaybookが間違っていたら元も子もないし、間違っていなかったとしてもModuleが誤動作を起こしてないと保証できるのか!と言われたら厳しいところ。ディレクトリ変更はPlaybook通り出来ています、といったところで「lsの結果を見るまで信用できん!」というお客様も多いかと思います(私も不安です)
というわけで。

  • シェルを使ったテスト

結局はディレクトリだったらfindで全部取ってくるとか、ユーザ情報は/etc/passwdをcatするとか、そういうことが必要になるかと思います。が、今までであればシェルを作り、各サーバに配布して、結果をリダイレクトして、そのファイルをftpでもってきて、ファイル消して、シェルも消して、みたいなことをやっていました。これがAnsibleで自動化出来たらそれだけでもまあまあ有益です(この作業を100台やるかと思うとぞっとしますし)

Ansibleでこのようなことをやりたい場合にはshellかcommandのどちらかのMoudleを使います。違いは次のような感じのようです。

  • shell
    • 実行環境の環境変数に依存。パイプとかリダイレクトとか使える。
  • command
    • Playbookに書かれた変数しか使わない。パイプとかリダイレクトとか使えない。

ん~、一長一短ありますね。。
一応公式としては実行環境に影響を受けないcommandを推奨している模様。とりあえずcommandで試してみます。

ちょいと調べてこんな感じ

- name: dir check
  command: find / -type d -printf "%M %u %g %TY-%Tm-%Td %TH:%TM:%TS %p\n"
  register: result

- name: dir disp
  debug: var=result

リダイレクトは使えないので結果はregisterを使ってresultに突っ込み、その後にdebugで結果を標準出力に吐き出します。これでcommandに書いたfindの結果が表示されるはず。実行してみると。。。

       "stdout_lines": [
            "dr-xr-xr-x root root 2017-07-27 14:07:30.2480000000 /",
            "dr-xr-xr-x root root 2017-06-21 17:20:41.8637935380 /boot",
            "drwx------ root root 2017-06-21 17:19:35.7020000000 /boot/grub2",
            "drwxr-xr-x root root 2017-06-21 17:12:18.7280000000 /boot/grub2/themes",
            "drwxr-xr-x root root 2016-08-30 00:26:32.0000000000 /boot/grub2/themes/system",
            "drwxr-xr-x root root 2017-06-21 17:19:00.1140000000 /boot/grub2/i386-pc",
            "drwxr-xr-x root root 2017-06-21 17:18:59.6520000000 /boot/grub2/locale",
            "drwxr-xr-x root root 2017-06-21 17:18:59.6640000000 /boot/grub2/fonts",
            "drwxr-xr-x root root 2017-08-10 10:09:27.0460000000 /dev",
            "drwxr-xr-x root root 2017-08-10 10:09:24.6970000000 /dev/vfio",

一応こんな感じで表示されます(前半部分に全ても文字列がつながったものが出ましたが、その後に上記の出力が出ます)ただしこのままだと標準出力にだらっと出てきちゃって複数台なんてやったら大変なことになりそうです。結果をファイルとかに出力できるといいんだけど。。。


shellだったらリダイレクトがつかえるので簡単にできそう、やってみます。どりゃ

- name: dir check
  shell: find / -type d  -printf "%M %u %g %TY-%Tm-%Td %TH:%TM:%TS %p\n" > /tmp/{{inventory_hostname}}.dir

- name: file get
  fetch: src=/tmp/{{inventory_hostname}}.dir dest=/tmp/

- name: file del
  file: path=/tmp/{{inventory_hostname}}.dir state=absent

リダイレクトでファイルにfind結果を出力(inventory_hostnameはマジック変数と言われる定義済みの変数で、インベントリファイルで設定したホスト名が入ります)、fetchコマンドでリダイレクト結果を管理サーバ側に持ってきて、fileのabsentで削除します。これを実行

[root@RHEL7]# ansible-playbook -i development site.yml -u root

PLAY [webservers] *************

TASK [Gathering Facts] ********
ok: [192.168.1.105]

TASK [common : dir check] *****
changed: [192.168.1.105]

TASK [common : file get] ******
changed: [192.168.1.105]

TASK [common : file del] ******
changed: [192.168.1.105]

PLAY RECAP ********************
192.168.1.105              : ok=4    changed=3    unreachable=0    failed=0

[root@RHEL7]# ls -al /tmp/192.168.1.105/tmp/192.168.1.105.dir
-rw-r--r--. 1 root root 825623 Aug 10 02:29 /tmp/192.168.1.105/tmp/192.168.1.105.dir

[root@RHEL7]# view /tmp/192.168.1.105/tmp/192.168.1.105.dir
dr-xr-xr-x root root 2017-07-27 14:07:30.2480000000 /
dr-xr-xr-x root root 2017-06-21 17:20:41.8637935380 /boot
drwx------ root root 2017-06-21 17:19:35.7020000000 /boot/grub2
drwxr-xr-x root root 2017-06-21 17:12:18.7280000000 /boot/grub2/themes
drwxr-xr-x root root 2016-08-30 00:26:32.0000000000 /boot/grub2/themes/system
drwxr-xr-x root root 2017-06-21 17:19:00.1140000000 /boot/grub2/i386-pc
drwxr-xr-x root root 2017-06-21 17:18:59.6520000000 /boot/grub2/locale
drwxr-xr-x root root 2017-06-21 17:18:59.6640000000 /boot/grub2/fonts
drwxr-xr-x root root 2017-08-10 10:09:27.0460000000 /dev
・
・
・

ふう。。何とか成功。。
出力されたファイルのパスがあれなのは、出力対象の/tmpの配下に元のディレクトリ構成が再現されているからですね。一応管理サーバ側に変なファイルがないことを確認して完了です。


まだまだ試行錯誤中ですが何とかテスト的なことはAnsibleでできそうです。今後はこのラインで攻めていきたいと思います。

以上です。お疲れ様でした。

Dockerコンテナの概要

お疲れ様です。伊藤です。

先にインストールについて書いてしまったので順序が逆ですが、Dockerコンテナの概念的なことを記事にさせていただきます。
いまいちコンテナと言っても何を指しているかわからないですよね。。特にインフラに絡んでいない方には。。というわけで私のわかる限りでコンテナについて書いておきます。基本はGoogleで調べればわかることではあるので、「そんなの知ってるよ」という方は読み飛ばしてください。


まず、コンテナって何?というところですが、私の感覚では小さい仮想マシン、という認識です。実はこれはDockerコンテナについてはちょっと語弊を産む表現なのですが、その辺がまたややこしいところです。まぁ、いったんここは呑み込んでいただいて。。。


なぜコンテナは小さくて済むのか?についてですが、これは簡単。ホストOSのカーネルを兼用している為です。ハイパーバイザ型の仮想マシンというのはホストOSの上にゲストOSのカーネルを実装しています。そのために非常に容量やCPUを使うのですが、コンテナはホストOSのカーネルを共有しています。要はただのアプリケーションの扱いなんです。そのためにLinuxマシン上ではLinuxのOSしか動かせません。このあたりがハイパーバイザ型との大きな違いになります(ちなみにDockerは現時点ではLinuxしか対応していません)2017/11/16 訂正 WindowsServerにも対応しております。DockerのWindows対応について - ときどきAnsible日記参照


f:id:pj_doaa:20170808151703p:plain

コンテナはただのアプリケーションですが、ユーザとかメモリ領域とかネットワークとかを他のコンテナに影響させないように切り分けたものになります。疑似的にマシンを作っている、という形ですね(まあ仮想マシンってそういうものですが)


その切り分けに使っているのが名前空間(ネームスペース)と呼ばれる技術になります。ちょっとわかりづらいですよね。。直訳してるから。。。まあ、そういうものだと思ってもらえばいいです。で切り分けられるのは下記です。

  • プロセス管理
  • ネットワーク管理
  • IPCリソースアクセス管理
  • マウントポイント管理
  • カーネル・バージョン管理
  • ユーザ管理

これらの情報がそれぞれのコンテナで別々に使えます。この分離するための技術にカーネルバージョン3.1以上(RHEL7相当)の技術を使っているので、それ以前バージョンでは使えません。(Dockerのバージョンが古ければRHEL6でも対応してましたが、最新バージョンは動きません。docker1.10以前ぐらいまでは動くかも)


コンテナの概要について書いてきましたが、コンテナも大きく二つに分かれます。それがLinuxコンテナとDockerコンテナです。違いは下記の通り。

  • Linuxコンテナ(LXC)
    • 小さい仮想マシンを意識している
    • 仮想マシン意識なので色々乗っている
    • 色々乗ってるが故に管理がめんどくさい
    • ハイパーバイザ型と同じように使える
  • Dockerコンテナ
    • アプリケーションの実行環境を意識している
    • 必要最低限なものしか載っていない
    • 本来であればOS起動時に動くプロセスも動かない
    • すぐに作ってすぐ壊すポリシーみたい

う~ん、、ちょっと偏ってるかもしれませんが私の認識はこんな感じ。結果として今流行っているのはDockerです。すぐに作って(すぐに壊せる)というのが今の需要に合っていると思われます。ただし今後もDockerが使われ続けるかは??。噂ではすでに業界から・・・・という話も。。。

今後の状況を見据えつつ使っていきましょう。
以上です。お疲れ様でした。