Ubuntu 15.10でLXDとAnsibleを使う

Dockerは便利だけど、もうちょっと素のコンテナが使いたい。ということでLXDを使ってみるけど、その場合の構成管理ツール?ってなんなんでしょう。よくわからなくてとりあえずAnsibleを使ってみたときのメモ。

LXDをインストール

github.com

sudo add-apt-repository ppa:ubuntu-lxc/lxd-git-master && sudo apt-get update
sudo apt-get install lxd

(最新版がほしいのでPPAを使ってますが、Ubuntu 15.10だともう通常のAPTレポジトリに入ってます。バージョンは0.20でした)

Ansibleをインストール

Installation — Ansible Documentation

sudo apt-add-repository ppa:ansible/ansible && sudo apt-get update
sudo apt-get install ansible

LXDのイメージをつくる

# イメージをインポート
lxd-images import ubuntu --alias ubuntu

# u1というコンテナを立ち上げる
lxc launch ubuntu u1

lxc listで起動しているコンテナが見えるはずです。

$ lxc list
+------+---------+-----------+------+-----------+-----------+
| NAME |  STATE  |   IPV4    | IPV6 | EPHEMERAL | SNAPSHOTS |
+------+---------+-----------+------+-----------+-----------+
| u1   | RUNNING | 10.0.3.61 |      | NO        | 0         |
+------+---------+-----------+------+-----------+-----------+

SSHの設定

lxc_containerというモジュールがあるのでSSH不要なのでは?と思うんですが、うまくいかなかったのでふつうにSSHでやります(やり方ご存知の方は教えてください...)。

秘密鍵を生成

ssh-keygen -f ~/.ssh/lxc

ファイルをコピー

lxc file pull/pushというコマンドでファイルをコピーできます。コンテナのファイルパスはコンテナ名/path/to/targetという形式で指定するみたいです。

# 念のためバックアップ
lxc file pull u1/root/.ssh/authorized_keys authorized_keys.bk

lxc file push .ssh/lxc.pub u1/root/.ssh/authorized_keys

# ログインできるか確認
ssh root@10.0.3.61 -i .ssh/lxc

Ansibleの設定

Ansibleは~/.ansible.cfgにデフォルトの設定を書けます。ここにユーザ名と秘密鍵を書いておきます。

cat > ~/.ansible.cfg <<EOF
[defaults]
remote_user = root
private_key_file = ~/.ssh/lxc
EOF

で、これで準備完了かと思いきや、実行されません。

$ ansible -m ping u1
No hosts matched

Ansibleは、実行対象のホストをあらかじめinventry fileにリストアップしておく必要があります。

Ansibleのinventry fileにホスト名を書き出す

Dynamic Inventory — Ansible Documentationという手もありますが、JSONで結果を返すのがシェルワンライナーではちょっと無理そうだったので今回はパスして、静的なファイルに書き出しておきます。 lxc listの結果はパースしづらいですが、AWK芸で頑張ります。(--formatというオプションがそのうち導入されるらしいです)

lxc list | awk '$NF > 1 && $2 != "NAME" {print $2}' | dd of=/etc/ansible/hosts

で、これでいよいよ準備完了かと思いきや、エラーが出ます。

# ansible -m ping u1
u1 | FAILED => SSH Error: ssh: Could not resolve hostname u1: Name or service not known
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.

そう、sshするので名前解決できないといけません。

dnsmasqをresolv.confに

Ubuntuのパッケージの場合は、lxd(というかlxc?)をインストールするとdnsmasqが立って、コンテナの名前解決をしてくれるようになっています。ただ、resolv.confには入らないので手動で入れます。

echo 'nameserver 10.0.3.1' | sudo tee -a /etc/resolvconf/resolv.conf.d/head
sudo resolvconf -u

これで名前解決ができるようになります。ほんとは.lxdとかいうドメインを設定したほうがいいのかも。

$ dig u1

; <<>> DiG 9.9.5-11ubuntu1-Ubuntu <<>> u1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49270
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1280
;; QUESTION SECTION:
;u1.                            IN      A

;; ANSWER SECTION:
u1.                     0       IN      A       10.0.3.61

;; Query time: 1 msec
;; SERVER: 10.0.3.1#53(10.0.3.1)
;; WHEN: Fri Nov 06 09:58:19 EST 2015
;; MSG SIZE  rcvd: 47

ping

成功。

$ ansible -m ping u1
u1 | success >> {
    "changed": false,
    "ping": "pong"
}