概要
やりたいこと
- ローカルの ~/ansible/work/ にチェックアウトした myapp のソースコードを、サーバの /var/ma2saka/myapp に転送したい
- サーバは vagrant でローカルに立ててる Cent OS 6.5
- もともとスクリプトは AWS サーバ用に書いていて動作しているもの
先に解決策
ポート番号が違ってもホスト名部分が一緒だと誤動作する。
インベントリファイルで直接IP書かずに、host1 ansible_ssh_host=127.0.0.1
みたいに指定してホスト名称部分がかぶらないようにするとよい。
失敗してたパターン
書いた定義
- name: sync source code
synchronize:>
dest=/var/ma2saka/myapp
src=/Users/ma2saka/ansible/work/myapp/
recursive=yes
links=yes
rsync_opts="--exclude='.git'"
インベントリには
[dev]
127.0.0.1
[dev:vars]
ansible_ssh_user=vagrant
ansible_ssh_port=2222
vagrant で立てたサーバがローカルの 2222 で待ち受けてる。
以下のようにしてあらかじめ公開鍵は登録している。
ssh-add -D
ssh-add ~/.ssh/id_rsa
ssh-copy-id -p 2222 vagrant@127.0.0.1
エラーになる
TASK: [deploy | sync source code] *********************************************
failed: [127.0.0.1 -> 127.0.0.1] => {"cmd": "rsync --delay-updates -FF --compress --archive --rsh 'ssh -S none -o StrictHostKeyChecking=no -o Port=2222' --exclude='.git' --out-format='<<CHANGED>>%i %n%L' \"/Users/ma2saka/ansible/work/myapp/\" \"/var/ma2saka/myapp\"", "failed": true, "rc": 23}
msg: rsync: change_dir "/Users/ma2saka/ansible/work/myapp/" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1039) [sender=3.0.6]
FATAL: all hosts have already failed -- aborting
いや、msg: rsync: change_dir "/Users/ma2saka/ansible/work/myapp/" failed: No such file or directory (2)
とか言われてもさ。あるからねそのディレクトリ。どう見てもさ。
brew で入れてる 1.8.2 だからかと疑って pip で入れなおしてみるもアカン
1.9.1 でも特に変化なし。
amazonとか別のサーバだとうまくいく
[dev]
myapp1.amazon.example.com
myapp2.amazon.example.com
myapp3.amazon.example.com
[dev:vars]
ansible_ssh_user=ec2-user
ansible_ssh_port=22
問題なく期待通り動作する。
127.0.0.1 に /etc/hosts で別名つけたら動作した
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
127.0.0.1 this.is.it
[dev]
this.is.it
[dev:vars]
ansible_ssh_user=vagrant
ansible_ssh_port=2222
これで実行すると。
.. 略 ..
TASK: [deploy | sync source code] *********************************************
changed: [this.is.it -> 127.0.0.1]
.. 略 ..
動くし・・・。
期待通り動くのでこれはこれでいいんだけど釈然としないものが残るな。
ホスト名を localhost にするとそもそも繋がらない
IP指定してやるのがダメなら localhost だとどうよと思ったら、
TASK: [deploy | sync source code] *********************************************
failed: [localhost -> 127.0.0.1] => {"cmd": "rsync --delay-updates -FF --compress --archive --rsh 'ssh -S none -o StrictHostKeyChecking=no -o Port=2222' --exclude='.git' --out-format='<<CHANGED>>%i %n%L' \"/Users/ma2saka/ansible/work/myapp/\" \"/var/ma2saka/myapp\"", "failed": true, "rc": 12}
msg: ssh: connect to host localhost port 2222: Connection refused
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]
えーーー。
つまり実際のところ、ホストの「名前」が問題なわけ? と遅ればせながら気がつく。
ansible_ssh_host の設定で解決
ひっかかっていたのはまさにこの現象でした。
ローカルホストでポートフォワードしているホストに ansible で接続する場合、インベントリファイルで適当な別名を付与するのがよいやり方のようです。
[dev]
# lvh.me とか this.is.it とか書かなくていい
host1 ansible_ssh_host=127.0.0.1
[dev:vars]
ansible_ssh_user=vagrant
ansible_ssh_port=2222
だいたい synchronize モジュールのコードとか実行時に転送されてるスクリプトも確認したので挙動は理解したけど、これは罠だなー。だいたいエラーメッセージが不親切すぎる。という愚痴をいいつつ。解決したので気分よし。
反省
-vvvv
してよく見ると、「そのスクリプトがどこで実行されてるか」がわかるんですね。127.0.0.1 を書いて失敗してたとき、実際にスクリプトはリモートサーバで実行されていたんです。それなのに source の指定はローカルマシンの相対パスが書かれているからディレクトリが見つからない。
というところに気がつけば、これ特定モジュールのバグじゃなくて ansible のホスト名解決ロジックの側だろうとすぐ察せられたはずなのですが、見当違いのところをトレースしていて時間を使ってしまいました。なかなか難しいものです。