仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Jujuで構築するKubernetes

最近弊社ではKubernetesの検証を始めています。

Kubernetesは、展開、スケーリング、コンテナー上で動くアプリケーションの管理を自動化するために設計されたオープンソースのプラットフォームです。2014年にKubernetesプロジェクトがGoogle主導のもと始まりました。

Kubernetesには次のような特徴があります。

  • 疎結合である
  • 負荷に応じてスケールできる
  • ホストOSから抽象化したレイヤーでアプリケーションを実行できる
  • 迅速にアプリケーションを展開できる
  • その場でアプリケーションをスケールできる
  • シームレスに新機能をロールアウトできる
  • 必要なリソースだけにハードウェアの使用率を制限できる

Kubernetesは色々なOS上で動かすことができますが、今回はUbuntu ServerとJuju、MAASを使って、Kubernetes環境を構築してみました。

Jujuはいわゆるアプリケーションの構成管理ツールの一つです。アプリケーションの構成管理ツールというと、AnsibleとかPuppetとかが知られていると思います。それらとJujuの相違点として、OSのデプロイメントから行う点、接続関連の設定も行う点が挙げられます。使い方も比較的簡単なので、ドキュメントさえ見れば初めての人でも簡単に小規模から大規模のアプリケーションを構成することができます。

Jujuは色々なノードにデプロイメントできますが、今回はベアメタルサーバー上に環境を構築するためにMAASを利用します。次のドキュメントに従って、それぞれが準備できていることが前提です。

Jujuのドキュメント

jujucharms.com

MAASのドキュメント

https://docs.ubuntu.com/maas/2.3/en/docs.ubuntu.com

MAASの必須要件

MAASでは組み込みのDHCPが提供したいネットワークセグメント上で動いていることが要件です。また、JujuとJujuによってデプロイするマシンとの関連づけのためにMAASのタグ機能を使います。識別しやすいタグを設定しておきましょう。

Jujuの必須要件

当たり前のことを言って恐縮ですが、JujuとMAASの組み合わせで利用する場合はJujuがMAASサーバーとネットワークの疎通があることが要件です。JujuはbootstrapというプロセスをMAASで管理されているノードにデプロイする必要があります。Jujuを操作するクライアント(CLI、GUI)からの命令をbootstrap経由でほかのノードに対して実行するような仕組みです。

Jujuとデプロイメント

JujuにはCharmとBundleというものがあります。Charmはアプリケーションと設定ファイルが含まれたパッケージで、GUIやCLIでアプリケーション単体をデプロイするものです。

一方Bundleはアプリケーションをデプロイするためのマシンの確保からOSのデプロイメントとアップデート、アプリケーションのデプロイメント、アプリケーションの設定、サービスの再起動、アプリケーション間の接続のための設定などを自動で行うことができるパッケージです。CharmもBundleもYAMLファイルで独自の設定を含めてデプロイメントできます。

JujuでKubernetesをデプロイしよう

環境さえ用意できれば次のコマンドだけでサーバー9台のマシンにKubernetes環境をデプロイメントできます。

% juju deploy canonical-kubernetes

設定はこちらのページに掲載されているファイル一覧のbundle.yamlに記載されており、ここを書き換えることでユーザーの好みの構成で環境をデプロイメントできます。

jujucharms.com

以下はYAMLの記述例です。ちなみにCharmストアのパッケージを使う場合、CharmやBundleのデプロイに必要なのは実はbundle.yamlだけです。このファイルをwgetやcurlコマンドで手元に持ってきて、後は好きな構成に書き換えれば公式のマシン数以外でのデプロイが可能になります。

さて、BundleのYAMLファイルの記述方法ですが、machinesにはどのようなスペックのマシンを何台、この環境構築に用いるのかを指定します。 servicesにはアプリケーションを記述しています。num_unitsにはそのアプリケーションをどれだけスケールするかを指定します。2以上を指定した場合はHA構成のための設定が自動的にセットアップされます。num_unitsの下のtoでデプロイ先のJuju Machineを指定します。数字だけを記述するとベアメタル上にアプリケーションを配備して、lxd:Xのように記述するとLXCコンテナー上にアプリケーションをデプロイメントします。relationsでアプリケーション間の「繋がり」を定義します。

description: A 3-machine Kubernetes cluster, appropriate for PoC. Includes a 2 Kubernetes worker nodes.
machines:
  '0':
    series: xenial
    constraints: "arch=amd64 tags=bay10" 
  '1':
    series: xenial
    constraints: "arch=amd64 tags=bay11"
  '2':
    series: xenial
    constraints: "arch=amd64 tags=bay12"
services:
  easyrsa:
    annotations:
      gui-x: '450'
      gui-y: '550'
    charm: cs:~containers/easyrsa-23
    num_units: 1
    to:
    - lxd:0
  etcd:
    annotations:
      gui-x: '800'
      gui-y: '550'
    charm: cs:~containers/etcd-59
    num_units: 1
    to:
    - '0'
  flannel:
    annotations:
      gui-x: '450'
      gui-y: '750'
    charm: cs:~containers/flannel-35
  kubeapi-load-balancer:
    annotations:
      gui-x: '450'
      gui-y: '250'
    charm: cs:~containers/kubeapi-load-balancer-37
    expose: true
    num_units: 1
    to:
    - '0'
  kubernetes-master:
    annotations:
      gui-x: '800'
      gui-y: '850'
    charm: cs:~containers/kubernetes-master-65
    num_units: 1
    options:
      channel: 1.9/stable
    to:
    - '0'
  kubernetes-worker:
    annotations:
      gui-x: '100'
      gui-y: '850'
    charm: cs:~containers/kubernetes-worker-69
    expose: true
    num_units: 2
    options:
      channel: 1.9/stable
    to:
    - '1' 
    - '2'
relations:
- - kubernetes-master:kube-api-endpoint
  - kubeapi-load-balancer:apiserver
- - kubernetes-master:loadbalancer
  - kubeapi-load-balancer:loadbalancer
- - kubernetes-master:kube-control
  - kubernetes-worker:kube-control
- - kubernetes-master:certificates
  - easyrsa:client
- - etcd:certificates
  - easyrsa:client
- - kubernetes-master:etcd
  - etcd:db
- - kubernetes-worker:certificates
  - easyrsa:client
- - kubernetes-worker:kube-api-endpoint
  - kubeapi-load-balancer:website
- - kubeapi-load-balancer:certificates
  - easyrsa:client
- - flannel:etcd
  - etcd:db
- - flannel:cni
  - kubernetes-master:cni
- - flannel:cni
  - kubernetes-worker:cni

独自のコンフィグレーションが終わったら、次のように実行して後は待つだけでKubernetes環境が出来上がります。デプロイの状況はJuju GUIやJuju CLIのjuju statusコマンドで確認できます。

% juju deploy ./deploy.yaml

最小構成のシステムを構成するならざっと四、五十分程度でできるでしょうか。Jujuもほかの構成管理ツールと同様、冪等性があるツールです。同じBundleを使えば同じ構成でシステムのコピーを作れますし、作ったり壊したりも容易です。

今回細かくは触れませんが、JujuはModelというもので「アプリケーション軍」を管理しています。モデルで環境を分ければ、Jujuを使ってKubernetes環境やOpenStack環境、MySQLのクラスター環境などを一元管理できたりします。その辺りの話はまた今度取り上げたいと思います。

構築した環境はkubernetes-masterにログインしてkubectlコマンドなどで操作します。Jujuでデプロイした環境へはjuju sshコマンドでログインできますので、次のように操作してください。

% juju ssh kubernetes-master/0
ubuntu@bay10:~$ kubectl get nodes
NAME           STATUS    ROLES     AGE       VERSION
bay11          Ready     <none>    4d        v1.9.2
bay12          Ready     <none>    4d        v1.9.2

ただ、Kubernetes環境でデプロイするたびにログインするのも少し面倒です。次のように実行すると、必要なコマンドが手元の環境に導入されている前提で、Kubernetesの操作ができます。マスターノードからクレデンシャルファイルをjuju scpコマンドで持ってくれば良いわけです。ちなみに転送してきたファイルをホームディレクトリーの同じパスにおけば、色々なところのクライアントでKubernetesを操作できます。

% juju scp kubernetes-master/0:config ~/.kube/config
% kubectl get nodes
NAME           STATUS    ROLES     AGE       VERSION
bay11          Ready     <none>    4d        v1.9.2
bay12          Ready     <none>    4d        v1.9.2

と、こんな感じで割と簡単にKubernetesの環境を作ることができます。YAMLファイルにきちんと「構成したい構成」を書いておけば、後はJujuとbootstrapがその通りの環境を作ってくれるわけです。Juju、すごい。

ちなみにKubernetes関連のBundleは私が使い始めた頃よりも充実してきました。コミュニティによるBundleも含めると、16個ほど色々な構成をデプロイすることができるBundleが用意されています。

jujucharms.com

日本仮想化技術では従来の仮想化だけではなく、OpenStackやKubernetesについても力を入れていきたいと思っています。導入や検証検討の際は是非ご用命ください。

Packstackで構築したOpenStackをOcataからPikeにアップグレードする

ここ数日、Packstackで構築したOpenStackをOcataからPikeにアップグレードする方法を調べていました。 昔と比べると、そんなに苦労することなくアップグレードできることが確認できました。情報を共有したいと思い、こちらのブログに書かせていただきました。

ちなみに手動インストールで構築した場合でも、CentOS 7でOVSを使ってインストールした環境であれば、同様にアップグレードできると思います。バージョンアップグレードの参考になれば幸いです。

前提条件

今回の環境構築の前提条件は次の通りです。

  • OpenStack Ocata
  • NeutronはOVSを利用
  • OpenStackを標準インストールしたCentOS 7.4上に構築
  • OpenStack OcataバージョンをPikeバージョンにアップグレードする

アップグレードの流れ

OpenStackバージョンのアップグレードの流れは基本的には

  • 新しいOpenStackリリースリポジトリーの有効化
  • 新しいOpenStackパッケージの「インストール」
  • なんちゃらマネージ db sync なんちゃら の実行
  • 関連サービスの再起動

で良いようです。インストールするパッケージや実行するdb syncのコマンドはインストールガイドを確認します。

OpenStack Docs: Install OpenStack services

アップグレードの前に

OpenStackは疎結合なシステムです。従って、コンポーネントごとに別のOpenStackバージョンを使うことも可能です。

実際のアップグレード作業に入る前に、次のサイトの情報を確認し、OpenStackのアップグレードについて理解を深めてください。

superuser.openstack.org

OpenStack Pikeリポジトリーの追加

CentOS 7ではOpenStackパッケージをRDOのリポジトリーか、CentOS Cloud SIGが提供するリポジトリーのパッケージを利用することができます。CentOS Cloud SIGが提供するパッケージを使いますので次のように実行します。

# yum install centos-release-openstack-pike

Keystoneのアップグレード

新しいパッケージをインストールします。

# yum install openstack-keystone httpd mod_wsgi

Keystoneのdb_syncを実行します。

# su -s /bin/sh -c "keystone-manage db_sync" keystone

現在のKeystoneはHTTPバックエンドで動いているため、Apacheを再起動します。

# systemctl restart httpd.service

正常に起動しない場合はKeystoneのログを確認します。

Glanceのアップグレード

新しいパッケージをインストールします。

# yum install openstack-glance

Glanceのdb_syncを実行します。変換が行われます。

# su -s /bin/sh -c "glance-manage db_sync" glance

/usr/lib/python2.7/site-packages/oslo_db/sqlalchemy/enginefacade.py:1328: OsloDBDeprecationWarning: EngineFacade is deprecated; please use oslo_db.sqlalchemy.enginefacade
  expire_on_commit=expire_on_commit, _conf=conf)
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade ocata01 -> pike01, drop glare artifacts tables
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
Upgraded database to: pike01, current revision(s): pike01

関連のサービスを再起動します。

# systemctl restart openstack-glance-api.service openstack-glance-registry.service

正常に起動しない場合はGlanceのログを確認します。

Novaのアップグレード

Packstackで作ったOcata環境はnova-manage.logをroot権限で読み書きしてしまいます。このままだとPikeでは不具合があるため、次のように実行して権限を書き換えてください。

# chown nova.nova /var/log/nova/nova-manage.log

本件に関しては次のバグを参照してください。

bugs.launchpad.net

新しいパッケージをインストールします。

# yum install openstack-nova-api openstack-nova-conductor openstack-nova-console openstack-nova-novncproxy   openstack-nova-scheduler openstack-nova-placement-api

Novaのnova-manageコマンドを各種実行します。

# su -s /bin/sh -c "nova-manage api_db sync" nova
# su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova
# su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova
# su -s /bin/sh -c "nova-manage db sync" nova

関連のサービスを再起動します。

# systemctl restart openstack-nova-api.service  openstack-nova-consoleauth.service openstack-nova-scheduler.service   openstack-nova-conductor.service openstack-nova-novncproxy.service

正常に起動しない場合はNovaのログを確認します。

Nova-Computeのアップグレード

新しいパッケージをインストールします。

# yum install openstack-nova-compute

関連のサービスを再起動します。

# systemctl restart libvirtd.service openstack-nova-compute.service

正常に起動しない場合はNova-Computeのログを確認します。

Neutron のインストール前に

公式のインストール手順書はLinux Bridgeを利用しています。 PackstackはOpenvSwitchを使うため、linuxbridgeをopenvswitchに置き換える必要があります。

Neutron (controller)側の設定

コントローラー側に必要なNeutronパッケージをインストールします。

# yum install openstack-neutron openstack-neutron-ml2 \
  openstack-neutron-openvswitch ebtables

neutron-db-manageを実施してNeutronデータベースを上書きします。

# su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neutron.conf \
  --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron

INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
  Running upgrade for neutron ...
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade a9c43481023c -> 804a3c76314c, Add data_plane_status to Port
INFO  [alembic.runtime.migration] Running upgrade 804a3c76314c -> 2b42d90729da, qos add direction to bw_limit_rule table
INFO  [alembic.runtime.migration] Running upgrade 2b42d90729da -> 62c781cb6192, add is default to qos policies
INFO  [alembic.runtime.migration] Running upgrade 62c781cb6192 -> c8c222d42aa9, logging api
INFO  [alembic.runtime.migration] Running upgrade c8c222d42aa9 -> 349b6fd605a6, Add dns_domain to portdnses
INFO  [alembic.runtime.migration] Running upgrade 349b6fd605a6 -> 7d32f979895f, add mtu for networks
  OK

nova-apiサービスを再起動します。

# systemctl restart openstack-nova-api.service

Neutronの関連サービスを再起動します。

# systemctl restart neutron-server.service \
  neutron-openvswitch-agent.service neutron-dhcp-agent.service \
  neutron-metadata-agent.service

Neutron L3サービスを再起動します。

# systemctl restart neutron-l3-agent.service

ステータスを確認します。

# systemctl status neutron-server.service \
  neutron-openvswitch-agent.service neutron-dhcp-agent.service \
  neutron-metadata-agent.service neutron-l3-agent.service

Neutron (compute)側の設定

次にコンピュート側のOVSエージェントプラグイン側のアップグレードをします。

関連するパッケージをインストールします。

# yum install openstack-neutron-openvswitch ebtables ipset

関連サービスを再起動します。

# systemctl restart openstack-nova-compute.service
# systemctl restart neutron-openvswitch-agent.service

CentOS 7+CentOS Cloud SIG版で構成するOpenStackのOcataバージョンからPikeバージョンへの最低限のアップグレードは以上で完成です。

その他のパッケージの更新

現在はRabbitMQ、MariaDB、OVS、openstack-dashboard、python-memcachedなどが古いバージョンの状態です。 弊社環境では全てアップグレードして関連サービスを再起動するだけでアップグレードがうまくできましたが、少しずつコンポーネント単位でアップグレードするにはYUMプラグインのversionlockを使うと便利です。

まず、次のようにコマンドを実行して、アップグレードの影響がありそうなパッケージをバージョンロックします。

# yum versionlock add openvswitch openstack-dashboard python-django-horizon python-memcached
# yum update

まずはDashboardを更新してみましょう。 yum versionlock deleteコマンドでバージョンロックしたパッケージをロック解除できます。

# yum versionlock delete openstack-dashboard python-django-horizon python-memcached
# yum update
# systemctl restart httpd.service memcached.service

最後にOVSを更新します。この手順で問題なく更新できましたが、正直言うと無理にアップグレードしないでも良いのかなと思っています。OVSサービスを再起動すると、ovs-vsctl statusの結果が新しいバージョンに更新されます。

# yum versionlock delete openvswitch
# yum update
# systemctl restart openvswitch

無事にアップグレードが成功することを祈っています。

GPUパススルーを利用したKVM仮想マシンが不安定なときのチェックポイント

前回は、KVM環境でGPUパススルーをする方法について構築手順を紹介しました。

しかしながら、環境によってはいくつかの要因が重なり手順どおりにはいかないことがあります。

ここでは、KVM仮想マシンでGPUパススルーが動作しない または 不安定なときの確認ポイントを紹介いたします。

BIOSのバージョン確認

BIOSの不具合等により最新のGPUカードが正しく認識しないことがあります。メーカーのリリースノート等を確認し、該当しそうな不具合が見つかったら最新版のBIOSへアップデートします。

BIOSの設定確認

複数のGPUを利用する場合、4GB以上のMemory mapped I/O addressがサポートされていないとホストシステム上でGPUカードが正しく認識されないことがあります。

BIOSの設定にabove 4G decodingという項目がある場合は設定を有効にします。

KVM仮想マシンのチップセット設定

仮想マシンのOSがLinuxでGPUパススルーを利用する場合はQ35が安定すると言われています。仮想マシンを作成するとき、特別な理由がない限りチップセットはQ35を選択することを推奨します。

(参考:https://wiki.lime-technology.com/UnRAID_Manual_6#Creating_Your_Own_Virtual_Machines

KVM仮想マシンのCPUモード設定

仮想マシンのCPUモードが適切なものに設定されていないと仮想マシン上でGPUが正しくに動作しない場合があります。ライブマイグレーション機能を利用しない場合は "host-model" にすることを推奨します。

$ virsh edit [仮想マシン名]

### CPU Mode 設定例 ###
 <cpu mode='host-model'>
   <model fallback='allow'/>
 </cpu>

KVMホスト側の設定

PCI Expressでのデータ破損を防止するACS(Access Control Service)が有効になっていると、KVM環境では逆に不具合の要因となる場合があります。動作が不安定なときは /etc/libvirt/qemu.conf (Ubuntu 16.04の場合)を開き、以下の設定を加えてACSを無効化してみます。

relaxed_acs_check = 1

認識されているPCI Expressの世代の確認

GPUが想定していたほど性能を出していないときは、ホスト上でPCI Expressの世代が低く認識されていたり、何らかの理由でPCI Expressの転送速度が落ちている場合があります。まずは PCI Express の世代が正しく認識されているか確認します。

$ nvidia-smi -q

--- コマンド結果から抜粋 --- 
        GPU Link Info
            PCIe Generation
                Max                 : 3
                Current             : 3
            Link Width
                Max                 : 16x
                Current             : 16x
        Bridge Chip
            Type                    : N/A
            Firmware                : N/A
        Replays since reset         : 0
        Tx Throughput               : 0 KB/s
        Rx Throughput               : 0 KB/s

ここで仮想マシン上の環境では結果がGen1となっていた場合でも、物理マシン上では本来の世代で認識されていて、転送スピードを測定するとGen1の規定値以上になることがあります。次項を参考にバススピードも測ってみます。

GPUバススピードの確認方法

バススピードの実測値を測定して適切な値となるか確認します。 前回も軽く触れましたが、バススピード測定ツールはCUDAに添付されているサンプルプログラムに含まれているので、それを実行してみます。

### サンプルプログラムをまだコンパイルしていない場合は make を実行
$ cd ~/NVIDIA_CUDA-8.0_Sample
$ make

### バススピードの測定
$ cd ~/NVIDIA_CUDA-8.0_Samples/bin/x86_64/linux/release/
$ ./bandwidthTest

<出力例>
[CUDA Bandwidth Test] - Starting...
Running on...

 Device 0: Tesla P40
 Quick Mode

 Host to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         11537.8

 Device to Host Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         12961.7

 Device to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         240433.7

Result = PASS

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

実測値が1世代前の制限値より低い場合は、ハードウェアやソフトウェアに何らかの問題が起きている可能性があります(ハードウェアの相性問題であることもあります)。

各世代の制限値(一方向)

  • Gen1: 4.0 GB/sec
  • Gen2: 8.0 GB/sec
  • Gen3: 16.0 GB/sec
  • Gen4: 32.0 GB/sec

(参考:https://ja.wikipedia.org/wiki/PCI_Express

ベンチマーク

バススピードに問題がない場合は、GPUへ直接負荷をかけてみます。ベンチマークを長時間稼働させたとき、処理数が一定量で増えない場合はなんらかの問題が発生していると考えられます。ベンチマークツールの一つとして、GPU Burnを紹介します。

なお、実行する際にはGPUの温度の変化に注意して下さい。

<実行例>

$ ./gpu_burn 60

GPU 0: Tesla P40 (UUID: GPU-1f4d9f28-51e7-065d-2db9-af4397809c49)
Initialized device 0 with 22912 MB of memory (22552 MB available, using 20297 MB of it), using FLOATS
13.3%  proc'd: 3798 (9453 Gflop/s)   errors: 0   temps: 51 C
    Summary at:   Tue Dec 19 11:47:57 JST 2017

25.0%  proc'd: 7596 (9443 Gflop/s)   errors: 0   temps: 54 C
    Summary at:   Tue Dec 19 11:48:04 JST 2017

40.0%  proc'd: 12660 (9438 Gflop/s)   errors: 0   temps: 58 C
    Summary at:   Tue Dec 19 11:48:13 JST 2017

51.7%  proc'd: 16458 (9444 Gflop/s)   errors: 0   temps: 60 C
    Summary at:   Tue Dec 19 11:48:20 JST 2017

63.3%  proc'd: 20256 (9451 Gflop/s)   errors: 0   temps: 60 C
    Summary at:   Tue Dec 19 11:48:27 JST 2017

75.0%  proc'd: 24054 (9441 Gflop/s)   errors: 0   temps: 61 C
    Summary at:   Tue Dec 19 11:48:34 JST 2017

90.0%  proc'd: 29118 (9446 Gflop/s)   errors: 0   temps: 63 C
    Summary at:   Tue Dec 19 11:48:43 JST 2017

100.0%  proc'd: 32916 (9440 Gflop/s)   errors: 0   temps: 64 C
Killing processes.. done

Tested 1 GPUs:
    GPU 0: OK

Kernelログの調査

NVIDIAドライバでなんらかしらの問題が発生したとき、syslogへXidメッセージが出力されることがあります。XidメッセージにはIDが振られており、そのIDを元に公式ドキュメントを調べることでメッセージの詳細を得ることができます。

<出力例>
NVRM: Xid (PCI:0000:00:09): 32, Channel ID 0000000e intr 00008000

上記の場合、Xidは32になります。

モジュールパラメーターの設定・確認

環境によってはNVIDIAドライバのモジュールパラメータを指定することで改善される場合があります。パラメーターの項目はNVIDIAドライバのヘッダーファイル内にドキュメントがあります。

現在のパラメータの設定は以下のコマンドで確認することができます

$ cat /proc/driver/nvidia/params

パラメータを任意の値に設定するにはUbuntuの場合、以下の手順で設定します。

1. パラメーターの指定

nvidiaモジュールの設定ファイルを新たに作成します。

  • ここでは、パラメータ NVreg_CheckPCIConfigSpace=0 と NVreg_EnableMSI=1 を設定しています。
  • XXXにはNVIDIAドライバーのバージョンが入ります。
$ vi /etc/modprobe.d/nvidia-params.conf  # ←ファイルは新規に作成します

--- ファイル内容 ---
options nvidia_XXX NVreg_CheckPCIConfigSpace=0 NVreg_EnableMSI=1
--- ここまで ---

2. Initramfsの更新

$ update-initramfs -u

3. VMの再起動

$ sudo shutdown -r now

KVMでGPUパススルーを使った仮想マシンを構築

最近のGPU性能は著しく向上しており、GPUのグラフィック処理以外での利用(GPGPU)が増えてきています。とくにディープラーニングやデータマイニングなど、人工知能分野での利用が大きな注目を集めております。

KVM仮想マシン上でGPUを利用する方法の一つとしてPCIパススルーを利用する方法があります。ここではUbuntu 16.04でKVMの構築方法と仮想マシンでUbuntu 16.04の環境を作成方法までを紹介いたします。

前提条件

KVMホストとなるサーバーへUbuntu 16.04 Serverと仮想マシンマネージャーをインストールしておいて下さい。仮想マシンマネージャのインストールは別のマシンでも構いません。仮想マシンマネージャの詳細については以下のサイトを参照して下さい。

環境構築手順

1. 事前準備

KVMホストとなるマシンへKVMとLinuxブリッジをインストールします。

$ sudo apt install libvirt0 qemu-kvm libvirt-bin virt-manager bridge-utils

Ubuntu server 16.04 のISOイメージをダウンロードします。

$ wget http://releases.ubuntu.com/16.04/ubuntu-16.04.3-server-amd64.img
$ sudo mv ./ubuntu-16.04.3-server-amd64.img /var/lib/libvirt/images

2. 仮想マシンの作成

仮想マシンを作成する前に、GPUに割り当てられているPCIアドレスと接続状況の確認します。

$ lspci | grep -i nvidia
03:00.0 3D controller: NVIDIA Corporation Device 1b38 (rev a1)

$ virsh nodedev-list --tree

<出力結果の一部>
  +- pci_0000_00_02_0
  |   |
  |   +- pci_0000_03_00_0
  |

virt-installコマンドを使って仮想マシンを作成します。

$ virt-install --accelerate --hvm \
    --connect qemu:///system \     # 接続先(ローカルの場合)
    --name gpuvm01 \               # 仮想マシン名
    --vcpus 1 \                    # 仮想CPU
    --ram 2048 \                   # メモリサイズ
    --file-size 24 \               # 仮想ディスク
    --network type=direct,source=eno1,model=virtio \ # ネットワーク
    --file "/var/lib/libvirt/images/gpuvm01.img" \
    --os-variant ubuntu16.04 \     # OSの種類
    --boot hd,cdrom,menu=on \
    --cdrom "/var/lib/libvirt/images/ubuntu-16.04.3-server-amd64.img" \
    --machine q35 \                # チップセットを Q35 に設定
    --host-device=pci_0000_03_00_0 # GPUを指定

3. 仮想マシンへUbuntu Server 16.04をインストール

仮想マシンマネージャを使って作成した仮想マシンへUbuntu Server 16.04をインストールします(仮想マシンマネージャの使用方法についてはここでは省略します)。

  • 仮想マシンマネージャを起動します。
  • [ファイル] - [新しい仮想マシン] を開き、KVMホストへ接続します。
  • 作成した仮想マシンを起動します。
  • 仮想マシンのコンソールを開きインストーラーを進めます。

4. 仮想マシンへNVIDIAドライバーをインストール

GPUが仮想マシン上で認識されていることを確認します

$ lspci | grep -i nvidia

aptへリポジトリを追加し、NVIDIAドライバーをインストールします。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
$ apt-cache search '^nvidia-[0-9]+'
$ sudo apt install nvidia-XXX
$ sudo reboot

再起動後、nvidia-smiコマンドでGPUのステータスが出力されることを確認します。

$ nvidia-smi -q

5. CUDAのインストール

NVIDIAのサイトへアクセスし、CUDAをダウンロードします https://developer.nvidia.com/cuda-downloads

CUDAをインストールします

$ dpkg -i cuda-repo-ubuntu1604-8-0-local-ga2_8.0.61-1_amd64.deb
$ sudo apt update
$ sudo apt install cuda

CUDAのインストールが正常に完了したら、サンプルプログラムをコンパイルします。

$ export PATH=/usr/local/cuda/bin${PATH:+:${PATH}}
$ export LD_LIBRARY_PATH=/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
$ ./cuda-install-samples-8.0.sh ~
$ cd ~/NVIDIA_CUDA-8.0_Samples
$ make

Tips

サンプルプログラムの一つcudaDecodeGLのコンパイルは、インストールされているnvidiaドライバのバージョンと UBUNTU_PKG_NAME の値が合っていないとmakeに失敗します。 失敗した場合は正しい値に修正し、もう一度実行します。

$ vi 3_Imaging/cudaDecodeGL/findgllib.mk

<編集>
UBUNTU_PKG_NAME = "nvidia-384"

動作確認

サンプルプログラムの一つである bandwidthTest を実施してみます。プログラムが正しくコンパイルできたことと、バススピードが妥当な値であることを確認します。

$ ~/NVIDIA_CUDA-8.0_Samples/bin/x86_64/linux/release/bandwidthTest

<出力結果例>
[CUDA Bandwidth Test] - Starting...
Running on...

 Device 0: GeForce GTX TITAN
 Quick Mode

 Host to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         11437.2

 Device to Host Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         13225.2

 Device to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         227939.5

Result = PASS

トラブルシューティング

うまく動作しなかった場合の対処法について、別エントリで紹介いたします。

tech.virtualtech.jp

HoloLens雑感

先日開催されたマイクロソフトのイベント「Connect();」の協賛連動企画で、Twitterでリツイートのキャンペーンに参戦し、景品のHoloLensをいただきました。

Microsoft Connect ();2017 - Microsoft Events & Seminars

バタバタしていたのでなかなか触れなかったのですが、やっと開封できたので、雑感を書き残しておこうかと思います。

f:id:tmiyahar:20171130125528j:plain 本体とクリッカー

f:id:tmiyahar:20171130125559j:plain キャリングケース

f:id:tmiyahar:20171130125620j:plain 開封

f:id:tmiyahar:20171130125750j:plain 装着してみた

この手のゴーグルで一番経験があるのはPS VRですが、ケーブルがない分取り回しがいいけど、重さはかなりあります。かなりのフロントヘビー。かつ、ゴーグル部分に傷をつけないようにと注意深く扱わないといけないのがやや難点かな。仕方ないですけどね。

最初はメガネをかけずに使っていたのですが、文字が読めないので仕方なくメガネの上から。でも、フロントヘビーのため、段々とずり下がってきてしまいます。視界からすると、ゴーグル部分の上端が少し黒っぽく見えるので、どうしても視界が遮られる感じに。逆に上に持ち上げていくと、液晶画面部分を少し見下ろすような感じになってしまって、どうも収まりが悪い。ここは上下に縁があるようなゴーグルにして、もう少し視野の安定感を出して欲しいなあと感じたところ。

指のジェスチャーによる操作ですが、なかなか難しい。慣れるまで時間がかかりました。また、スクロールさせる時、速度がかなりセンシティブなので、感度の調整ができるといいですね(多分どこかで設定できるはず)。

基本的な機能を試した後、おすすめされた「Robo Raid」をインストールして遊んでみました。

RoboRaid - 拡張現実 FPS ゲームの誕生 | HoloLens

壁が必要なので、会議室に一人こもって遊んでみましたが、何コレ楽しい。 前面だけでなく、側方にも視点移動ができるし、奥行き立体感もあるのが良いですね。PS VRにも同じようなゲームがありましたが、それに比べるとVR酔いも少ない(乗り物酔いしない私も、さすがに長時間プレイの後は調子が悪くなった)ので、ゲームデバイスとしてはアリな気がしました。

一方で、職業訓練用のシミュレータとしての利用などが考えられているようですが、現時点では視野が狭すぎることや、結局目の前にある程度の実物が必要なことを考えると、今すぐにこのデバイスで、というのは難しそう。むしろ、PC部分は別付けにして、必要最低限の表示情報だけをワイアレスに送信、表示してくれた方が使いやすいような気がしました。これはあくまでSDKで、今後は多分、そういう方向になっていくのでしょうけど。

あと、操作がジェスチャー+クリッカーだけはさすがに厳しい。ゲームパッドのような操作デバイスを有効活用できた方がいいですね。音声認識もあるんですが、「Select」を認識してくれない!?LとRの発音を聞き分けているのでしょうね。ネイティブ日本人には無理です・・

Juju/MAASでデプロイするOpenStackでLXDを使う方法

Juju/MAASを使ってOpenStackをデプロイ...と言いますか、Nova Computeチャームを使ってデフォルト設定のままデプロイすると、virt-type KVMとしてデプロイされます。インスタンスを起動するとVMが作成され、その中で指定したOSが起動します。

これをNova ComputeでLXDを使うには次のような内容のyamlファイルを書き、juju deployコマンドを実行します。Nova-LXDを動かすにはデプロイノードに2つのストレージボリュームが必要です。そのうち1つには起動フラグを設定しておく必要があります。

yamlファイル例

nova-compute:
    openstack-origin: "cloud:xenial-pike"
    enable-live-migration: yes
    enable-resize: yes

nova-compute-lxd:
    openstack-origin: "cloud:xenial-pike"
    enable-live-migration: yes
    enable-resize: yes
    virt-type: lxd

juju deployコマンド例

% juju add-machine --constraints tags=lxd1
(lxd1タグを持つJuju Machineを追加)

% juju machines
(Juju Machine番号を確認)

% juju deploy --config lxd-compute.yaml nova-compute nova-compute-lxd --to 10
% juju deploy lxd && juju config lxd block-devices=/dev/sdb storage-type=lvm
(Juju Machine番号が10の場合の実行例)

f:id:virtualtech:20171018141927p:plain:w480

KVMと比べると利用できるOSは制限されるものの、インスタンスの作成や削除、起動が速くてちょっと感動してしまいました。Juju/MAASを使ってOpenStackを構築する際にはぜひ、Nova-LXDをお試しください。

ちなみに参考サイトの一番下にリンクを貼りましたが、Nova-KVMとNova-LXDの共存をする方法をまとめています。必要であれば参考情報としてどうぞご覧ください。

参考サイト

Ubuntu JujuでデプロイしたマシンをAnsibleで管理するには

はじめに

最近、JujuとMAASを使ったOpenStack環境の構築を検証しています。 こちらでその辺りの情報を公開しています。

Jujuは様々なインフラにアプリケーションのデプロイと構成管理を行うツールで、MAASはMetal As a Serviceを提供するツールです。 これらはオープンソースで開発されており、ユーザーは公開されたドキュメントとパッケージを使って、自由にインストールして使うことができます。 サポートが必要であれば、Ubuntu Advantageを結ぶことで、 Canonicalによる技術支援を受けることができます。

JujuはAWSやAzureといったクラウド環境のほか、MAASで管理するサーバーを使うこともできるため、JujuとMAASを組み合わせることで既存のサーバーを使ってOpenStackやHadoop、最近流行りのKubernetes環境なども構築可能です。

Jujuはアプリケーションの展開を物理層にデプロイできるだけではなく、コンテナーにも展開できます。例えばApache Webサーバーを任意のノードに展開する場合は次のようにコマンドを実行することで簡単にデプロイすることができます。

ytooyama@maas:~⟫  juju deploy apache2 --to 1

これで、Jujuのマシン番号1のサーバーに対して物理環境にOSをインストールして、apache2をセットアップします。一方、コンテナーにデプロイする場合は次のようにコマンドを実行します。

ytooyama@maas:~⟫  juju deploy apache2 --to lxd:1

これで、Jujuのマシン番号1のサーバーに対してコンテナーを動かすために物理環境にOSのインストールとLXD/LXC環境を構築してコンテナーを起動、コンテナー上にapache2をセットアップします。

実際はapache2のインストール、サービスの起動、ポートの開放などの処理が行われます。コンテナーにデプロイした場合は、ブリッジ接続のコンフィグレーションも行われます。必要な場合は特定の形式(yaml形式)で記述した設定を元にカスタマイズの上デプロイすることもできます。

Jujuについては次のドキュメントをご覧ください。

jujucharms.com

Jujuには視覚的でわかりやすい、Juju GUIというものが用意されており、このDashboardを使ってデプロイしたアプリケーションの管理(アップデート、設定変更など)ができますし、スケールの拡大、縮小も可能です。同じ操作をJuju CLIで行うこともできます。

ただし、対象の台数が多くなってくると、Juju GUIやCLIツールを使って状況の確認をしたり、場合によってssh接続して様々なログを確認したりする事になります。数台規模の環境であればそれでも十分ですが、50台から100台規模になってくると結構しんどいですよね。

そこでようやく本題になるのですが、JujuでデプロイしたアプリケーションやOSを管理するためにAnsibleを使おうという話です。

Juju関連のこと

Jujuをセットアップすると、Jujuがアプリケーションを展開する前にOSをその環境にセットアップします。現状はOSとしてUbuntuが使われます。Jujuが構成管理をする際、インストールしたときに自動生成したキーペアを使って公開鍵認証によってリモートアクセスします。生成されるキーペアは、~/.local/share/juju/sshのパスの配下に展開されます。

AnsibleはSSHプロトコルとPythonを利用してノードを構成管理するツールです。構成管理を適用するノードにアクセスする際に公開鍵認証かパスワード認証を用いますが、Jujuがデプロイする環境ではパスワードが設定されません。従って、自動生成された鍵を使って公開鍵認証をする形になります。

Jujuがデプロイしたアプリケーションノードの一覧はJuju machenesコマンドで一覧表示できます。実際にコマンドを実行すると次のような結果が表示されます。

ytooyama@maas:~⟫ juju machines 
Machine  State    DNS            Inst id              Series  AZ       Message
0        started  172.17.29.223  cqd8ba               xenial  default  Deployed
0/lxd/0  started  172.17.29.225  juju-575e9e-0-lxd-0  xenial  default  Container started
0/lxd/1  started  172.17.29.227  juju-575e9e-0-lxd-1  xenial  default  Container started
0/lxd/2  started  172.17.29.193  juju-575e9e-0-lxd-2  xenial  default  Container started
0/lxd/3  started  172.17.29.194  juju-575e9e-0-lxd-3  xenial  default  Container started
0/lxd/4  started  172.17.29.195  juju-575e9e-0-lxd-4  xenial  default  Container started
0/lxd/6  started  172.17.29.201  juju-575e9e-0-lxd-6  xenial  default  Container started
1        started  172.17.29.224  4pp3th               xenial  default  Deployed
1/lxd/0  started  172.17.29.226  juju-575e9e-1-lxd-0  xenial  default  Container started
1/lxd/1  started  172.17.29.228  juju-575e9e-1-lxd-1  xenial  default  Container started
1/lxd/2  started  172.17.29.196  juju-575e9e-1-lxd-2  xenial  default  Container started
1/lxd/4  started  172.17.29.197  juju-575e9e-1-lxd-4  xenial  default  Container started
1/lxd/5  started  172.17.29.198  juju-575e9e-1-lxd-5  xenial  default  Container started
1/lxd/6  started  172.17.29.199  juju-575e9e-1-lxd-6  xenial  default  Container started
1/lxd/7  started  172.17.29.200  juju-575e9e-1-lxd-7  xenial  default  Container started
2        started  172.17.29.222  kcnfd8               xenial  default  Deployed
2/lxd/0  started  172.17.29.229  juju-575e9e-2-lxd-0  xenial  default  Container started

Machineはそれぞれの環境につけられたJujuが管理するマシン番号で、番号しか表示されていないものは物理サーバー、lxdの記述のあるものはコンテナーを示しています。例えば0/lxd/1ならば、マシン番号0のサーバーのコンテナーの1番ということがわかります。マシン番号0番には6個のコンテナーが存在することがわかります。

この出力結果の中でAnsibleでノードを管理するときに必要な情報はIPアドレスです。awkコマンドを使って抜き出してみましょう。

ytooyama@maas:~⟫ juju machines|awk '{print $3}'
DNS
172.17.29.223
172.17.29.225
172.17.29.227
172.17.29.193
172.17.29.194
172.17.29.195
172.17.29.201
172.17.29.224
172.17.29.226
172.17.29.228
172.17.29.196
172.17.29.197
172.17.29.198
172.17.29.199
172.17.29.200
172.17.29.222
172.17.29.229

うまくいった...とおもいきや、1行目のDNSがちょっと邪魔です。インベントリーファイルに書き込んでから一行目を削除する方法でも良いですが、つぎのようにフィルタリングできます。

ytooyama@maas:~⟫ juju machines|awk 'NR>1 {print $3}'
172.17.29.223
172.17.29.225
172.17.29.227
172.17.29.193
172.17.29.194
172.17.29.195
172.17.29.201
172.17.29.224
172.17.29.226
172.17.29.228
172.17.29.196
172.17.29.197
172.17.29.198
172.17.29.199
172.17.29.200
172.17.29.222
172.17.29.229

いい感じです。次のように実行して、Ansibleのインベントリーファイルを作っておきます。 hostsという名前で作成したインベントリーファイルにはIPアドレスの一覧のみ追記されます。

ytooyama@maas:~⟫ juju machines|uniq|awk 'NR>1 {print $3}' > hosts

Ansibleコマンドによる管理

Ansibleがシステムにインストールされており、インベントリーファイルも作成済みであれば、Ansibleとモジュールを使ってノードの管理が可能になります。AnsibleではインベントリーファイルにAnsibleで操作する対象のノードをIPアドレスかFQDNで記述しておく必要があります。Ansibleで操作する想定でないノードを誤操作しないようにする予防策というわけですね。

ansibleコマンドでノードを操作するにはインベントリーファイルを-iオプションで指定します。そのほか、利用するモジュールやユーザー認証に関わる情報(ユーザー、パスワードやキーペアなど)も必要です。これらはインベントリーファイルに記述することができますが、とりあえず次のようにコマンドにオプション指定することで実行可能です。

ytooyama@maas:~⟫ ansible -i hosts 172.17.29.223 -m ping -u ubuntu --private-key=~/.local/share/juju/ssh/juju_id_rsa

実はこのままだとエラーで失敗します。Ansibleは対象のノードにPythonのバージョン2がインストールされている必要があるためです。 ただ、Python 2は現行は利用可能ですが、サポート期限が迫っているという現状があります。また、Linux ディストリビューションによってはPython 2はデフォルトでインストールされず、必要な場合は別途インストールする必要が出てきます。例えばUbuntu 16.04とか。

現行のAnsibleをインストールする場合はPython2が依存パッケージとして同時にインストールされますが、「Ansible 2.2でPython3サポート」が行われたため、オプションを追加することでPyton 3.5以降がインストール済みであることを条件として、その条件にマッチしたノードをサポートするようになりました。

Ansible 2.2以降でのPython3サポートについては先ほどのリンク先の情報に書かれているように大体のコードは正常に動くが動かない場合もあると書かれています。うまく動かない場合はノードにPython2をインストールして対応しましょう。

ytooyama@maas:~⟫ ansible -i hosts 172.17.29.223 -m ping -u ubuntu --private-key=~/.local/share/juju/ssh/juju_id_rsa --extra-vars=ansible_python_interpreter=/usr/bin/python3
172.17.29.223 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}

これで当初の目的は達成できるわけですが、コマンドとオプションが長すぎて入力が大変です。そこで、インベントリーファイルに必要な情報を書き込んでみます。

[remote]のようにグループを作成して、その下にIP、FQDNを記述するとコマンドを実行するときにそのグループを指定して複数のターゲットに対してコマンドを実行できます。また、[remote:vars]でそのグループの設定を記述します。公式のマニュアルに記述例が掲載されています。

[remote]
172.17.29.223
172.17.29.225
172.17.29.227
172.17.29.193
172.17.29.194
172.17.29.195
172.17.29.201
172.17.29.224
172.17.29.226
172.17.29.228
172.17.29.196
172.17.29.197
172.17.29.198
172.17.29.199
172.17.29.200
172.17.29.222
172.17.29.229

[remote:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=ubuntu
ansible_ssh_private_key_file=/home/ytooyama/.local/share/juju/ssh/juju_id_rsa

このインベントリーファイルを使ってansibleコマンドでpingを実行してみます。全てのサーバーにpingを実行できます。

ytooyama@maas:~⟫ ansible -i hosts remote -m ping
172.17.29.193 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}
...
172.17.29.229 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}

Ansible Playbookコマンドによる管理

ansibleコマンドは一つの処理を行うには十分ですが、複数の処理を一括で実行する場合は不向きです。そんなときにはAnsible Playbookを使います。Ansible PlaybookはYAML形式で処理を記述します。例えばpingを実行したい場合は次のようにPlaybookを作成します。 Playbookの先頭にはハイフンを3つ入れてください。そのあとに処理や実行先の情報、ユーザー情報を指定したり、変数などを定義します。

---
- hosts: remote
  tasks:
   - name: try ping
     ping:

早速実行してみましょう。

ytooyama@maas:~⟫ ansible-playbook ping.yaml -i hosts

PLAY [remote] ********************************************************************************************

TASK [Gathering Facts] ***********************************************************************************
ok: [172.17.29.194]
ok: [172.17.29.227]
ok: [172.17.29.225]
ok: [172.17.29.193]
ok: [172.17.29.223]
ok: [172.17.29.195]
ok: [172.17.29.201]
ok: [172.17.29.228]
ok: [172.17.29.224]
ok: [172.17.29.226]
ok: [172.17.29.196]
ok: [172.17.29.198]
ok: [172.17.29.199]
ok: [172.17.29.200]
ok: [172.17.29.197]
ok: [172.17.29.222]
ok: [172.17.29.229]

TASK [try ping] ******************************************************************************************
ok: [172.17.29.223]
ok: [172.17.29.194]
ok: [172.17.29.227]
ok: [172.17.29.193]
ok: [172.17.29.225]
ok: [172.17.29.195]
ok: [172.17.29.201]
ok: [172.17.29.224]
ok: [172.17.29.226]
ok: [172.17.29.228]
ok: [172.17.29.196]
ok: [172.17.29.197]
ok: [172.17.29.198]
ok: [172.17.29.200]
ok: [172.17.29.199]
ok: [172.17.29.222]
ok: [172.17.29.229]

PLAY RECAP ***********************************************************************************************
172.17.29.193              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.194              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.195              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.196              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.197              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.198              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.199              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.200              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.201              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.222              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.223              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.224              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.225              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.226              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.227              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.228              : ok=2    changed=0    unreachable=0    failed=0   
172.17.29.229              : ok=2    changed=0    unreachable=0    failed=0   

ここまでできれば、あとはPlaybookの書き方次第で様々なことを実現可能です。 AnsibleのPlaybookのサンプルがドキュメントやGithub上に公開されているので、色々試してみたら楽しいかと思います。

ちなみにUbuntuで新しいバージョンのAnsibleを使うにはAnsible PPAを追加すると便利です。ページに書かれているコマンドを実行すると、Ubuntuのサポートされたバージョンで最新のAnsibleが利用できます。このPPAはRed Hat社のAnsibleチームが管理しているので安心です。Ubuntu 14.04 LTSや16.04 LTSなどで利用することを推奨します。