kakts-log

programming について調べたことを整理していきます

ChromeのHeadlessモードを使ってみる。

Headless Chromeとは

chrome 59から、Headlessブラウザとしてchromeを使うことができるようになりました。
https://www.chromestatus.com/features/5678767817097216

2017年5月3日現在では chrome beta版でchrome 59、chrome canary版でchrome 60を利用することができます

https://www.google.co.jp/chrome/browser/beta.html https://www.google.co.jp/chrome/browser/canary.html

Headless ブラウザ

HeadlessブラウザとはGUIの無いブラウザのことで、モニター上では見ることができないですが、
指定したurlに対してhttp httpsで実際にローディングして、DOMやhttpヘッダー情報などを取得して操作することができます。
Headless computer - Wikipedia 主にUIのテストなどで活用されていて、現在までHeadlessブラウザとして有名だったphantom.jsは、今回のHeadless chromeの登場により 開発終了となるそうです。
https://groups.google.com/forum/#!topic/phantomjs/9aI5d-LDuNE

Headless Chromeを使えるようにする。

今回はGoogle本家の解説記事を参考に進めていきます。
Getting Started with Headless Chrome  |  Web  |  Google Developers

本記事では、chromeのcanary版を利用します。 利用OSはmacOSを前提に進めます。
2017年5月3日現在 chromeのバージョンは60.0.3088.0で、 バージョン59以降なら本記事の通りにHeadless Chromeを利用できます。
下記ページから chrome canary版をダウンロードしてください。 https://www.google.com/chrome/browser/canary.html

Headless Chromeを使うためには、ここでダウンロードしたchrome canary版をターミナルから直接実行することで利用できます。
macOSにおいて、chrome canary版のアプリは/Applications/Google Chrome Canary.appにインストールされるので、コレを実行するようにします。

まずターミナルで楽に使えるようにエイリアスを設定します。

~/.bash_profileに以下のものを記述します。
ここでは3つエイリアスに設定していますが。 chrome-canaryのみ使います。 chrome通常版がバージョン59以上になっている場合はchromeエイリアスを使って実行してください。

# chrome通常版が ver59以上の場合 コレを使う。  
alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"

# chrome canary版 本記事ではこのエイリアスを使って実行する。  
alias chrome-canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary"

# 本家の解説記事で書いてあるが、本記事では実際には使いません。  
alias chromium="/Applications/Chromium.app/Contents/MacOS/Chromium"

source ~/.bash_profile で設定を読み込んだ上で、canaryのバージョンを確認してコマンドが呼び出せるか確認します。

$ chrome-canary --version
Google Chrome 60.0.3088.0 canary

これで、chrome-canaryへのエイリアスが効いているのと、バージョンが59以上になっていることが確認できたのでHeadlessモードでchromeが使える状態になりました。

Headlessモードを使ってみる

ここでターミナルからchrome-canaryコマンドを使ってHeadlessモードを実際に試してみます。
注意点としてはHeadlessモードを使う際は必ず –headlessフラグを付ける必要があります。
–headlessフラグに加えて、いくつかのフラグを実行時に追加することで様々なことができます。
全てではないですが、利用可能なフラグは下記のソースで見ることができます。
https://cs.chromium.org/chromium/src/headless/app/headless_shell_switches.cc

指定urlのDOMを取得する

–dump-dom フラグを追加することで、指定urlでアクセスした際の、document.body.innerHTML の値を出力します。

$chrome-canary --headless --dump-dom https://www.chromestatus.com/
指定urlのinnerHTML出力
<body class="loading">

<!--<div id="site-banner">
  <a href="https://www.youtube.com/watch?v=Rd0plknSPYU" target="_blank">
  <iron-icon icon="chromestatus:ondemand-video"></iron-icon> How we built it</a>
</div>-->

<app-drawer-layout fullbleed="">
  <app-drawer swipe-open="" style="transition-duration: 200ms;">
    <div class="drawer-content-wrapper">
      
<h3>Chrome versions</h3>
..........

スクリーンショットを撮る

–screenshop フラグを追加して、 指定urlでブラウザでアクセスした際のスクリーンショットを撮ることができます。
–window-sizeを追加で指定することで特定のwindowサイズで表示した場合も撮ることができます。

chrome-canary --headless --screenshot https://www.chromestatus.com/
[0503/175140.000000:INFO:headless_shell.cc(437)] Written to file screenshot.png.

# Size of a standard letterhead.
chrome-canary --headless --screenshot --window-size=1280,1696 https://www.chromestatus.com/
[0503/175141.000000:INFO:headless_shell.cc(437)] Written to file screenshot.png.

# Nexus 5x
chrome-canary --headless --screenshot --window-size=412,732 https://www.chromestatus.com/
[0503/175142.00000:INFO:headless_shell.cc(437)] Written to file screenshot.png.

実行したカレントディレクトリにスクリーンショットの画像がダウンロードされます。

参考

Getting Started with Headless Chrome  |  Web  |  Google Developers

オライリー Docker 第3章までの読書メモ

オライリーのDocker本を買って読み始めました。 第3章までメモをとりつつ読み進めたので、箇条書きですがメモを公開します。

Docker

Docker

第1章 コンテナとは何か、そしてなぜ注目されているのか

コンテナとは

コンテナ: アプリケーションを依存対象とともにカプセル化したもの。どの環境であろうと同じように動作する環境を作れる。

コンテナがVMと似ているもの

・隔離されたOS環境をもち、その中でアプリケーションを動作させれる
→ コンテナは軽量な仮想マシンのように見える。

コンテナがVMよりも優れていること

  • 起動の速さ、効率性
    コンテナはホストOSとリソースを共有するので、はるかに効率的 コンテナの起動・停止が一瞬で行える。
    コンテナ内で動作するアプリのオーバーヘッドは ホストOS上のアプリと比較してもごくわずか
  • コンテナのポータビリティ
    どの環境でも全く同じ環境で動作できる
  • 軽量
    数十のコンテナを同時に実行可能 実働環境そのままの分散システムをエミュレートできる。
    VMに比べて 1台のホストマシンではるかに多くのコンテナを実行できる。
  • 設定やインストールが手軽
    ユーザは実行環境や利用可能な依存対象のさいを気にせずにすむようになる。

そもそも、VMとコンテナでは目指すゴールが違う。 VM: 異なる環境を完全にエミュレートする コンテナ: アプリケーションをポータブルにし、単体で動作できるようにする

1.1 コンテナとVM

VMを動作させるためには、下位層のOSやハードウェアへのアクセスを制御し、必要に応じてシステムコールを解釈するタイプ2ハイパーバイザが必要(タイプ2ハイパーバイザとは ホストOS上で動作するもの virtualboxvmwareなど)
それぞれのVMでは、OS、実行するアプリ、必要なライブラリなどの完全なコピーが必要

コンテナの場合は、ホストカーネルは実行されるコンテナと共有される。
つまり、コンテナは常にホストと同じカーネルを実行しなければならない。

アプリケーションYとZは同じライブラリを使っていて、そのデータはそれぞれのアプリで別々のコピーでなく、共有されている。
コンテナエンジンはハイパーバイザ上のVMと同様のやり方でコンテナの起動や終了を待ち受ける。
コンテナ内で動作しているプロセスは、ホスト上で直接動作しているプロセスと同等であり、ハイパーバイザ実行によるオーバーヘッドがない。

コンテナとVMでは、隔離の度合いが違っている。
コンテナの仕組みはまだ日が浅く、多くの組織では動作実績がつまれるまではコンテナの分離昨日を完全に使用するのをためらっている。 そのため,VMとコンテナのハイブリッドシステムがよく見られる。

1.2 Dockerとコンテナ

コンテナ自体はもともと古い概念で、chrootコマンドに代表されるファイルシステムの隔離機能が前からあった。
コンテナはいわば、chrootサンドボックスをプロセスにまで拡張したものと言ってよいものです。

Dockerは ポータブルなイメージと、ユーザフレンドリなインターフェースを中心とする様々な方法で、既存のコンテナ技術をラップして拡張し、コンテナの生成と配布のための完全なソリューションを提供している。
Dockerというプラットフォームには2つの構成要素があり、 1つはDockerエンジンで、 コンテナの生成と実行を待ち受ける。
もう1つはDockerHubで、コンテナを配布するためのクラウドサービスを指す。

Dockerエンジンは、動作中コンテナへの高速で便利なインターフェースを提供する。
DockerHubには ダウンロード可能な大量なコンテナの公開イメージがある。

Dockerエンジンのオープンソース化により、大きなコミュニティができ、コンテナ関連のデファクトになっており現在でも開発が活発である。

2章 インストール

linux環境やmacでのインストールについて解説しているが、ここでは長くなるため省略。

3章 はじめの一歩

3.1 イメージの実行

下記コマンドを実行するとhello worldが表示される。

 docker run debian echo "hello world"

docker run: コンテナの起動を受け持つコマンド
run に続くものは 使いたいイメージの名前(イメージ: コンテナのテンプレート的なもの)
debian: 最小限に抑えられたバージョンのdebian linux ディストリビューションを指定する

 $ docker run debian echo "hello world"  
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
Status: Downloaded newer image for debian:latest
hello world

docker runの実行時に、毎回イメージのローカルコピーがあるかチェックする。
ない場合はDocker Hubをオンラインでチェックして、最新版のdebianイメージをダウンロードする

イメージダウンロード完了すると dockerはそのイメージを実行中のコンテナに変え、その中で、指定されたコマンド echo “hello world"を実行する

まとめると、docker run実行により、コンテナに対して下記の処理を短い時間で行える。

  • コンテナをプロビジョニングして起動
  • 指定されたコマンド実行
  • コンテナシャットダウン

3.2 基本のコマンド群

コンテナを立ち上げた上で、コンテナ内でシェルを使う

$ docker run -i -t debian /bin/bash

コンテナ内のコマンドプロンプトが表示される。
リモートマシンでssh接続するのと似ている。

-i -tで、 dockerに対してtty月のインタラクティブセッションを要求する
シェルを終了するとコンテナも停止する。

コンテナが動作するのは、そのコンテナのメインプロセスが動作している間だけ。

コンテナにホスト名をつけて実行する

$ docker run -h CONTAINER -i -t debian /bin/bash

起動中のDockerコンテナは docker psで見れる。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
e7a1de88dd53        debian              "/bin/bash"         5 seconds ago       Up 3 seconds                            inspiring_poincare

docker inspect コマンドにコンテナ名やIDを入れると 指定したコンテナの詳細情報が見れる。

実行中のコンテナで変更されたファイルリストを見たい場合

docker psで表示されたコンテナ名を指定する
$ docker diff inspiring_poincare
C /bin
D /bin/bash
A /test

コンテナ内で起きたことの全リストを取得

$ docker logs inspiring_poincare
root@e7a1de88dd53:/# mv /bin/bash /test

3.3 Dockerfileからのイメージの構築

dockerfile Dockerのイメージを生成するための一連の手順を含む、テキストファイルのこと

debian環境でcowsayとfortuneをインストールしたイメージを作る場合 dockerfile というファイルで以下のものを記述する

FROM debian:wheezy

RUN apt-get update && apt-get install -y cowsay fortune

FROM: 使用するベースイメージを指定する。 wheezyというタグのバージョンを使うよう指定している。

Dockerfileのコメントを除く最初の命令は 必ずFROMでなければならない。

dockerfileを元にイメージを構築する。
dockerfileと同一ディレクトリ上で、docker buildコマンドを実行構築できる。

起動時に特定のコマンドを実行させたい場合はDockerfileの末尾にENTRYPOINT命令を指定する

COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

そして、entrypoint.shというファイルをDockerfileと同一ディレクトリ上に作成し、下記の処理を記述する。

#!/bin/bash

if[ $# -eq 0]; then
  /usr/games/fortune | /usr/game/cowsay
else
  /usr/games/cowsay "$@"
fi

引数がある場合は cowsayにそのまま渡す。 なければ fortuneの出力をパイプでcowsayに渡す。

Dockerfileを元にイメージを構築する

docker build -t test/cowsay-dockerfile .

構築したイメージからコンテナを立ち上げる

docker run test/cowsay-dockerfile

イメージ・コンテナ・union file systemについて

イメージとコンテナの関係を理解するためには Dockerのベースとなる技術であるUFSを理解する必要がある。

UFSは、複数のファイルシステムをオーバーレイし、単一のファイルシステムとしてユーザに見せてくれる。
Dockerイメージは複数のレイヤから構成され、イメージの各レイヤはread onlyのファイルシステムです。 新しいレイヤはDockerfileの命令毎に作成されて既存レイヤの上に置かれる。
イメージがコンテナに変換される(つまり、docker run もしくは docker createコマンドの実行時)場合、Dockerエンジンはイメージの上に読み書き可能なファイルシステムを追加する。
不要なレイヤはイメージを肥大化させるため、多くのDockerファイルでは1つのRUN命令で複数のコマンドを指定してレイヤ数を抑える試みが見られる。

コンテナの状態は以下の5つのいずれかになる。
- created : docker createコマンドで初期化されたがまだ起動していない。
- running : コンテナが起動中の状態。
- exited : 一般的には「停止」した状態としてみなされ、コンテナ内で実行中のプロセスがない状態を示す。 exitedになっているコンテナは一度でも起動されたことがある。
- restarting : 障害をおこしたコンテナをDockerエンジンが再起動しようとする際の状態 あまり見ることはない。
- paused : コンテナが一時停止している状態。

3.4 レジストリでの作業

作成したイメージはDocker Hubにアップして公開できる。 他人が作ったものも使うことができる。

https://hub.docker.com/ Docker hubでアカウントを作成する。

docker loginコマンドで作成したアカウントで認証させる。

先程作成したイメージを再構築して、DockerHubにアップロードする。

作成位したDockerHubのアカウント(リポジトリ)名の後に/をつけて、イメージ名をつける。 ここでは testuser/cowsayとする まずはdocker build docker build -t testuser/cowsay .

docker pushでアップロードする docker push testuser/cowsay

リポジトリ名のあとに:をつけて名前を入れれば その名前でタグが作れる

docker pullで他の人が作ったイメージをダウンロードできる。

Redisの公式イメージの使用

まずはredisのイメージを取得

$docker pull redis

redisコンテナを起動する。
-dという引数を付けてみる $ docker run –name myredis -d redis -dはバックグラウンドで実行するオプション

redisコンテナが立ち上がったので rediscliで接続する。

redis-cliを動作させるためのコンテナを立ち上げて、2つのコンテナをリンクするほうが簡単です。

$ docker run –rm -it –link myredis:redis redis /bin/bash これでコンテナ内のシェルを操作する

redis-cli -h redis -p 6379
> ping
PONG

>set "abc" 123
OK

get "abc"
"123"

上記でコンテナをリンクさせる際に指定した –link myredis:redisについて
これは新しいコンテナを既存の"myredis"コンテナに接続するようにDockerに指示する。
Docker側では、新しいコンテナの/etc/hostsにredisというエントリをセットアップし、そのエントリが"myredis"のIPアドレスを指すようにする。
これで、redis-cliコマンド指定時に -h redisと指定して、既存のredisコンテナに接続できる。

実際に、redis-cli用の新しいコンテナ内でのシェルで/etc/hostsを見ると以下のようにredisが指定されている。

# cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  redis 238a0b42046b myredis

ここで2つのコンテナでredisサーバとクライアントの接続ができるようになった。
しかしredisサーバの方のデータの永続化ができていないため、コンテナを停止したらデータが消えてしまう。
コンテナとホスト、または他のコンテナ間でデータを共有したい。

それを実現するためにボリュームという概念がある。
ボリュームはUFSの一部でなく、ホスト側に直接マウントされているファイルまたはディレクトリのことです。 つまり、ボリュームは他のコンテナと共有できて、すべての変更はホストのファイルシステムに対して行われます。

ボリュームは、DockerfileないでVOLUME命令を使うか、 docker run時に -v フラグを使って指定できる。
デフォルトでは、ホスト上のDockerをインストールしたディレクトリ(/var/lib/docker/が多い)

Dockerfileに指定する場合
コンテナ内の/dataにマウントされる。
VOLUME /data

docker runで指定する場合
$ docker run -v /data test/webserver

これで一旦redisイメージを使ってコンテナを立ち上げ、 redis-cli用コンテナから接続することができました。

参考

www.infoq.com

CentOS node.js 6.x系最新版を ansibleでインストールする

CentOS でnode.js 6.x系のインストール方法

CentOSサーバにて、node.js6.x系最新版をインストールする際、 公式のドキュメントにインストール方がまとまっています。
パッケージマネージャを利用した Node.js のインストール | Node.js
このドキュメントの記載に従ってインストールを行うことができます。

まずは手動でインストールする

サーバ内で6.x系のセットアップスクリプトcurlで取った上でbashを実行します。

sudo curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash -

ここでcurlで取得しているセットアップスクリプトは、github上で公開されていて、気になる人は読んでみると良いです。
https://github.com/nodesource/distributions/blob/master/rpm/setup_6.x

このスクリプトの実行により、yumでnode.js 6.x系の最新版パッケージが利用可能になります。 実際に、yum listで利用可能なパッケージを見てみます。

$ yum list nodejs
読み込んだプラグイン:fastestmirror, security
Loading mirror speeds from cached hostfile
 * base: www.ftp.ne.jp
 * epel: ftp.riken.jp
 * extras: www.ftp.ne.jp
 * updates: www.ftp.ne.jp
利用可能なパッケージ
nodejs.i686   0.10.48-3.el6        epel      
nodejs.x86_64   →6.10.2が利用可能になっている  2:6.10.2-2nodesource.el6    nodesource

これでnodejsパッケージをインストールする準備ができましたので、yum installを実行します。
確認のため、インストール後にnode.js と npmのバージョンを確認します。

$sudo yum install nodejs

# node -v
v6.10.2

# npm -v
3.10.10

補足

ここでは、特に必要ないので行わないですが、 もしネイティブアドオンのビルドをするために、デベロップメントツールが必要な場合は
以下のものもインストールする必要があります。

yum install gcc-c++ make

ansible playbookでインストール手順を書いてみる

ansibleのplaybookに、前項で手動で行った処理を書いてみます。

---
- hosts: node_servers
  remote_user: ope_user
  tasks:
    - name: setup nodejs6.x
      become: yes
      shell: curl -sL https://rpm.nodesource.com/setup_6.x | sudo -E bash -
    - name: installing latest version of node.js
      become: yes
      yum:
        name: nodejs
        state: latest

セットアップスクリプトのインストール時、shellモジュールを使ってパイプで bash - を実行したのですが、
root権限が無いためにsudo権限を追加しています。 https://github.com/nodesource/distributions/blob/master/rpm/setup_6.x#L9

curl -sL https://rpm.nodesource.com/setup_6.x | sudo -E bash -

ローカルpcでansible-playbookを実行すると、 対象サーバにnode.js6.x系最新版がインストールされます。

Hive posexplode関数を使った配列操作について (配列のインデックスを保持したまま処理を行う方法)

Hiveをつかってクエリを書く際に、配列データのクエリでの操作についてハマったのでメモ。

複数の配列データを持ったテーブルの操作

ユーザ毎に複数のアイテムIDとアイテム名をもたせた配列を それぞれitem_ids, item_namesとして、 以下のような構造のuser_itemというテーブルがあるとします。

user_itemテーブル

user_id item_ids item_names
user1 [item_a, item_b, item_c] [“アイテムA”, “アイテムB”, “アイテムC”]

ここでは、item_idsとitem_namesの配列の同じインデックスの要素同士で1対1に対応するとします。
例えば、 item_aに紐づくアイテム名は “アイテムA” とします。
このデータを以下のような感じで 対応するアイテムIDとアイテム名毎に1行ずつ出力させたいとします。

出力させたい構造

user_id itemId itemName
user1 item_a “アイテムA”
user1 item_b “アイテムB”
user1 item_c “アイテムC”

この場合 hiveにデフォルトで用意されているビルトイン関数のexplodeを使ってitem_idsの各要素に対してテーブル操作ができますが、
item_idsの各要素のインデックス番号が取れないため、 item_names配列から対応するアイテム名を取ることができません。

posexplode 関数を使って 複数配列間で同一のインデックス番号を対応させる

複数の配列データに対して、配列のインデックスの順序を保ったまま処理させたい場合、 Hive0.13.0から導入された posexplodeというビルトイン関数を使えば実現できます。
LanguageManual UDF - Apache Hive - Apache Software Foundation

LATERAL VIEW句で、 以下のようにposexplodeを使うことで、item_idsの各要素とインデックス番号を取得できます。

LATERAL VIEW (item_ids) item_ids_table AS item_index, itemId

ここで仮に指定している item_ids_table は、posexplode実行時にできる内部テーブルのテーブル名となります。
本記事では特にこの内部テーブルを使わないので、特に説明はしません。

LATERAL VIEW句で posexplode関数を使うことで、カンマ区切りで item_idsの各要素と、そのインデックスを取ることができます。
下記のような感じでitem_names配列に対して取得したインデックスを指定すると 対応したアイテム名も取得できます。

SELECT
  itemId,
  item_names[item_index] AS itemName # itemIdのインデックスに対応したアイテム名を item_names配列から取得
FROM
  user_item
LATERAL VIEW (item_ids) item_ids_table AS item_index, itemId

参考

stackoverflow.com

qiita.com

ansible commandとshellモジュールの違い

ansibleで使って対象ノードで特定のコマンドを実行する際、
デフォルトで用意されているcommandモジュールとshellモジュールを使うことができます。
環境変数や、パイプを使ったコマンドを実行させる場合 この2つは挙動が異なるのでまとめてみました。

command モジュール

まずはcommandモジュールについて
command - Executes a command on a remote node — Ansible Documentation

The given command will be executed on all selected nodes. It will not be processed through the shell,
so variables like $HOME and operations like “<”, “>”, “|”, “;” and “&” will not work (use the shell module if you need these features).

commandモジュールはシェルを介して実行されないため、 環境変数($HOMEなど)や、 “<”, “>”, “|”, “;” などのパイプやリダイレクトは使えません。
commandモジュールの意図として、ユーザ環境に依存せずにセキュアにコマンドを実行することがあげられます。
ユーザ環境変数や、パイプ・リダイレクトを使った処理を行いたい場合は shell モジュールを利用するように公式のドキュメントにも書かれています。

If you want to run a command through the shell (say you are using <, >, |, etc), you actually want the shell module instead. The command module is much more secure as it’s not affected by the user’s environment.

shell モジュール

shell - Execute commands in nodes. — Ansible Documentation

commandモジュールの章でも説明したとおり、このshellモジュールは、指定したコマンドをシェル(/bin/sh)を介して実行します。
実行環境に依存した環境変数や、パイプ・リダイレクトを使った処理を実行できます。
これは悪い点もあり、もし実行時に playbookないで変数を使っていて、その変数が意図しない者の場合、そのまま対象ノードに対して実行されてしまうので危険です。
shell moduleで変数を使う場合は、サニタイズのために “{{ var }}” のかわりに “{{ var | quote }}“ を使うべきです。

shell commandモジュール双方のデメリット

qiita.com 上記の記事に、この2つの問題点が書いてあり、読んでみましたが、概ね同意です。
この2つのモジュールをつかってplaybookを書く場合 コマンド実行による冪等性の保証が困難であり、
playbookを読んだだけではシステムの本来あるべき姿(ansbile playbookは本来システムのある「べき」状態を記述するのが正しいはず)がわからなくなること、
そして実行処理は本来シェルスクリプトに任せればよいと思います。
playbookを書く際には他のモジュールを調べた上で、どうしても他のモジュールでは記述できないときにだけ、このshell commandモジュールを使えばよいかと思います。

iostatでのディスクI/Oの指標を見る

iostatとは

「I/O statics」の略称 iostatコマンドを使って、ディスク毎のI/O統計を集計して ディスクI/Oの使用率・飽和度を示す指標をみることができます。
利用シーンとしては、主にディスクI/O関連の調査を行う場合に使われます。

主なオプション

iostatを実行する際の主なオプションは以下のとおりです。

オプション 説明
-c cpu統計を表示
-d ディスク統計を表示
-k 表示サイズ変更 ブロック数(512バイト)→ kb
-m 表示サイズ変更 ブロック数(512バイト)→ mb
-p 使用されているブロックデバイスと、そのパーティション毎の統計を表示する
-x 通常項目に加え、いくつかの拡張統計を表示する

デフォルトでは、 -c -dが有効になっていて、cpu統計・ディスク統計を見ることができます。
具体的には以下のような感じで各統計データを見ることができます。

$ iostat
Linux 2.6.32-431.17.1.el6.x86_64 _x86_64_   (2 CPU)

#cpu統計
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.02    0.00    0.02    0.03    0.00   99.92

#ディスク統計
Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
vda               0.46         2.63         9.55    2239142    8134170
vdb               0.00         0.00         0.00       1754          8
dm-0              1.27         2.61         9.47    2221322    8069280
dm-1              0.00         0.01         0.01       6288       6392

各項目の値の示す意味はman iostatで調べることができるので詳細を知りたい場合は読んでみると良いかもです。
ディスク統計の方の各項目について説明すると以下の通りになります。

項目 説明
tps 秒間あたりのトランザクション
Blk_read/s Blk_write/s 秒間あたりに(read | write)されたブロック数
Blk_read Blk_write read | writeの合計数

ブロック数の単位を変えたい場合は -m -kオプションを使って変えることができます。

-x オプションをつかって詳細なI/O統計を表示させる

iostat実行時に-xオプションを付けることで、より詳細なディスクの統計データを表示できます。

# ディスクの詳細な統計データを表示
$ iostat -dx

Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.01     0.87    0.06    0.41     2.62     9.52    26.17     0.00    6.71    2.31    7.30   1.71   0.08
vdb               0.00     0.00    0.00    0.00     0.00     0.00     8.39     0.00    1.22    1.00   49.00   1.22   0.00
dm-0              0.00     0.00    0.06    1.21     2.60     9.44     9.50     0.10   75.09    2.88   78.71   0.63   0.08
dm-1              0.00     0.00    0.00    0.00     0.01     0.01     8.00     0.00   45.32    2.91   87.04   0.90   0.00
項目 説明
rrqm/s 秒間あたりに読み込みキューに登録され、マージされた読み出し要求数
wrqm/s 秒間あたりに読み込みキューに登録され、マージされた書き込み要求数
r/s 秒間あたりにディスクデバイスに発行された読み出し要求数
w/s 秒間あたりにディスクデバイスに発行された読み出し要求数
rsec/s 秒間あたりにディスクデバイスから読み出されたセクタ数
wsec/s 秒間あたりにディスクデバイスから書き込まれたセクタ数
await I/O応答平均時間(ミリ秒) ドライバの要求キーで待っている時間と実際のI/O応答時間を合わせたもの
r_await awaitデータの読み込み処理のみのデータ(ミリ秒)
w_await awaitデータの書き込み処理のみのデータ(ミリ秒)
%util バイスがI/O処理をしていたことによるビジー状態の時間の割合(使用率)

この中で、もっとも重要な指標は awaitで、要求が発行されてからI/Oの応答が終わるまでの時間を表すものです。
%utilも重要な指標ですが、あくまでビジー状況の計測値を表すもので、複数ディスクからなる仮想デバイス環境ではあまり参考にならない指標と言われています。

rrqm/s wrqm/sの値は、パフォーマンス向上のために、複数の読み込み・書き込み要求が1つにマージされていることを表す指標で、
シーケンシャルなワークロードが処理された兆候を表します。

参考

詳解 システム・パフォーマンス

Understanding iostat (Example)

https://stackoverflow.com/questions/4458183/how-the-util-of-iostat-is-computed

Interpreting iostat Output - Server Fault Blog

Ansible でjenkins用サーバをセットアップする

macOSのPCから特定のサーバに対してansibleをつかってパッケージをインストールする方法を解説します。
ここでは、特定のサーバに対してjenkinsとsvnをインストールし、起動させるためにansible playbookを書いていきます。

ansibleのインストール

macでのansibleのインストールは下記にまとまっており、pipを使います。 Installation — Ansible Documentation

今回は、せっかくなので最近でた最新版のansible2.3.0をインストールします。

www.ansible.com

2.3.0はsshでのコネクション周りで大きく改善されており、ansibleの実行速度がかなり改善されているようです。

#pipをインストールする
$ sudo easy_install pip

# pipをつかってansibleをインストールする
$ sudo pip install ansible

playbookを作成

ansibleを実行する際 特定のグループまたは単一のサーバに対してplaybookとよばれるYAML形式のファイルで サーバにインストールするパッケージや起動するプロセスなどを指定することができます。 今回は、単一のサーバに対してplaybookを作るため、シンプルに下記の構成でファイルを作っていきます。

$ tree
.
├── README.md
├── hosts                           // サーバグループとipを設定する
├── jenkins-playbook.yml // jenkinsサーバ用のplaybook

ここで今回設定するサーバのホスト名を"jenkins"として設定します

hostsファイルの設定

ホスト名と実際のサーバのipのひもづけを hostsファイルにて設定します。
今回は単一のサーバに対してのみなので、ipは1つのみ設定します。 ipを192.168.0.1として 下記のように設定します。

./hosts

[jenkins]
192.168.0.1

playbook

ここでは指定したサーバに対して jenkins(最新の安定バージョン)とsvn(1.7.22)をインストールした上で jenkinsを起動させるplaybookを書きます。

./jenkins-playbook.yml

----
- hosts: jenkins
  remote_user: ${YOUR_ACCOUNT}
  tasks:
    - name: Install svn1.7.22 
      become: yes
      yum:
        name: http://opensource.wandisco.com/rhel/6/svn-1.7/RPMS/x86_64/subversion-1.7.22-1.x86_64.rpm
        state: present

    - name: ensure open JDK 1.6 is at the latest version
      become: yes
      yum:
        name: java-1.6.0-openjdk
        state: latest

    - name: get the Jenkins repository
      get_url:
        url: http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
        dest: /etc/yum.repos.d/jenkins.repo

    - name: add the Jenkins repository
      rpm_key:
        key: http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key

    - name: ensure jenkins is at the latest version
      become: yes
      yum:
        name: jenkins
        state: latest

    - name: ensure jenkins is running and enabled
      become: yes
      service:
        name: jenkins
        state: started
        enabled: yes

ansibleのplaybookでは、tasks項目で上から設定した順にサーバに変更が適用されていきます。
ここでは最初にsvnの特定のバージョンをrpm指定でyumインストールさせます。

最初の項目でyumと書いていますがこれはansibleのyumモジュールを使うことを意味しています。 yum項目の配下にnameやstateを指定していますが、ここで特定のパッケージや、そのパッケージがどういう状態にしたいか(最新版になっている、removeされているなど)
を指定することができます。
yum - Manages packages with the yum package manager — Ansible Documentation

以下ではplaybookの各taskの内容を解説していきます。

svnの特定バージョンをインストールした状態にする

ここではsvn1.7.22のバージョン指定をしたうえでインストールさせるための設定を書いています。
rpmパッケージはopensource.wandisco.comから選んだものを指定しています。

    - name: Install svn1.7.22    #タスク実行時の名前
      become: yes                      #yum installするために、sudo で実行させる
      yum:
        name: http://opensource.wandisco.com/rhel/6/svn-1.7/RPMS/x86_64/subversion-1.7.22-1.x86_64.rpm     #特定のrpmに対してyum installさせる
        state: present  # nameで指定したパッケージをインストールした状態にする

jenkinsの最新の安定バージョンをインストールし、起動させる

svnの設定に続いてjenkinsに関しての設定を記述しています。
jenkinsの起動に必要なjdkのインストールから、jenkins最新の安定版のインストール、 最後にansibleのserviceモジュールを使って、yumでインストールしたjenkinsのserviceを有効にし、起動させるように記述します。

service - Manage services. — Ansible Documentation

    - name: ensure open JDK 1.6 is at the latest version
      become: yes
      yum:
        name: java-1.6.0-openjdk    
        state: latest     #jdk1.6.0最新版をインストールする


    - name: get the Jenkins repository  urlからファイルをダウンロードする
      get_url:
        url: http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo   #ダウンロード元のurl
        dest: /etc/yum.repos.d/jenkins.repo  #ダウンロード先のファイル名指定

    - name: add the Jenkins repository
      rpm_key:
        key: http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key

    - name: ensure jenkins is at the latest version
      become: yes
      yum:
        name: jenkins  
        state: latest  #jenkins最新版をインストールする

    - name: ensure jenkins is running and enabled
      become: yes
      service:
        name: jenkins
        state: started    # nameで指定したserviceを起動した状態にする
        enabled: yes     #  nameで指定したserviceを有効にする

以上で設定は終わりです。

ansible-playbookコマンドを実行して設定をサーバに反映させる

一通り設定がおわりましたので、サーバにplaybookで記述した設定を反映していきます。
ansibleをダウンロードした際に、ターミナルで ansible-playbookというコマンドも使えるようになっています。
このコマンドは、ホストに対して、playbookに書かれた設定を反映させるときに使えるものです。
一般的には以下のような形式でコマンドを打つと実行できます。

ansible-playbook {ホスト名} -i {hostsファイル}

-i でhostsファイルの指定がない場合は、デフォルトで /etc/ansible/hosts にあるファイルから読み込むようになっています。 今回は先程記述したhostsファイルを指定します。 さらには、今回yum でのパッケージインストールや、serviceの起動など、sudo権限が必要な処理を行うため、実行時に–ask-sudo-passオプションを付けて
実行時に対象サーバのユーザのパスワードを入力するようにします。

$ ansible-playbook jenkins -i ./hosts  --aks-sudo-pass

これを実行することでサーバへの設定適用が完了します。