Ansibleをコンテナで準備するのにドハマりした
■はじめに
以前のエントリの通り、macだとAnsibleの準備は簡単です。
が、諸事情によりWindowsで準備をしないとならない状況となりました。
WSL2で入れようかなとも思ったのですがalpineで比較的簡単に準備できそうなので、コンテナで準備することにしました。
が。。
いろんな要因が折り重なって解決まで丸2日かかってしまった。。
ハマりポイントを整理します。
■前提
AzureVM(ターゲットノード)
コンテナ(コントロールノード)
- Docker Desktop (Docker Engine v.19.03.12)
- alpine 3.12.0
- Ansible 2.9.9
■まずやったこと
ターゲットノードの準備
まずVMを用意します。
実はここ最近仕様が若干変わったようで、以前はなかった(と思う)構築時のSSHデフォルト適用が入るようになっています。
自然な流れで認証はSSHを選択します。
VMを作ると、そのまま認証キー(pemファイル)がローカルにダウンロードされます。
DNS名はselenoid-qa-example-01とします。
コントロールノードの準備
以下のページを参考にDockerfileを準備します。
公開鍵がローカルに払い出されたので、それを使用してアクセスすればいけるんじゃないかな?
ということで、通常の方法(Ansible内で発行した公開鍵をターゲットノードに配置する方法)をとらず、Dockerのv18.03で実装されたBuildkitを使用して認証キーをコンテナに配置して、これをAnsibleで使おうと思いました。
# syntax = docker/dockerfile:1.1-experimental FROM alpine:3.12.0 RUN set -x \ && apk add --no-cache bash \ && apk add --no-cache ansible \ && apk add --no-cache python3 \ && apk add --no-cache openssh-client \ && mkdir -p /etc/ansible \ && mkdir -p -m 700 ~/.ssh && ssh-keyscan selenoid-qa-example-01.eastus.cloudapp.azure.com >> ~/.ssh/known_hosts RUN --mount=type=secret,id=ssh,target=~/.ssh/test_key.pem RUN cd /etc/ansible RUN ansible -i inventory_node.ini selenoid-qa-example-01.eastus.cloudapp.azure.com -m ping #RUN ansible-playbook -i inventory.ini playbook_node.yml
■実行してみる
その1:VMから払い出されたpemで動かす
実はこのDockerfile、問題なくビルドされるのですが正しく動きません。
(ログも出ない)
なので実際にdocker execで潜ってpingを打つとPermission denied (publickey)になります。
どうにも公開鍵が認識されない。
selenoid-qa-example-01.eastus.cloudapp.azure.com | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added the ECDSA host key for IP address 'VMのIP' to the list of known hosts.\r\nazureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com: Permission denied (publickey).", "unreachable": true }
試しにpemをCOPYコマンドでコンテナ内でコピーし、そこからsshコマンドを実行すると普通に起動されます。
bash-5.0# ssh -i ~/.ssh/test_key.pem azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com load pubkey "/root/.ssh/test_key.pem": invalid format Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 5.3.0-1034-azure x86_64) (中略) To run a command as administrator (user "root"), use "sudo <command>". See "man sudo_root" for details. azureuser@test:~$
つまりAnsible経由ではVM作成時に発行した公開鍵は使えませんでした。
この事象が分かるまで半日ぐらい費やしてしまった。。
その2:Ansible内で公開鍵を発効して配布
さて次にやるのはAnsibleのオーソドックスな公開鍵配布方法です。
コントロールノードで発効し、ターゲットノードに配布する方法。
Dockerfileを上記サイトにあるコマンドを追加して、以下のように書き換えます。
# syntax = docker/dockerfile:1.1-experimental FROM alpine:3.12.0 RUN set -x \ && apk add --no-cache bash \ && apk add --no-cache ansible \ && apk add --no-cache python3 \ && apk add --no-cache openssh-client \ && mkdir -p /etc/ansible \ && mkdir -p -m 700 ~/.ssh \ && ssh-keyscan selenoid-qa-example-01.eastus.cloudapp.azure.com >> ~/.ssh/known_hosts COPY inventory_node.ini /etc/ansible COPY playbook_node.yml /etc/ansible COPY ansible.cfg /etc/ansible RUN ssh-keygen -q -N '' -t ed25519 -f ~/.ssh/id_ed25519 RUN ssh azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com 'cat ~/.ssh/id_ed25519.pub' | cat - >> ~/.ssh/authorized_keys RUN cd /etc/ansible RUN ansible -i inventory_node.ini selenoid-qa-example-01.eastus.cloudapp.azure.com -m ping
Buildkitで転送していた公開鍵の読み込みを削除して、内部でssh-keygenします。
で、相変わらずこれも何事もなくビルドされるので、execして確認します。
するとこれも先ほどと同様にPermission denied (publickey)になります。
ひとつずつ確認します。
まず公開鍵があるのか確認します。
bash-5.0# ls -la total 32 drwx------ 1 root root 4096 Aug 5 13:09 . drwx------ 1 root root 4096 Aug 5 13:09 .. -rw-r--r-- 1 root root 0 Aug 5 13:09 authorized_keys -rw------- 1 root root 411 Aug 5 13:09 id_ed25519 -rw-r--r-- 1 root root 102 Aug 5 13:09 id_ed25519.pub -rw-r--r-- 1 root root 944 Aug 5 13:09 known_hosts -rwx------ 1 root root 2494 Aug 5 08:29 test_key.pem
ありますね。
次、転送は?
> ssh azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com 'cat ~/.ssh/id_ed25519.pub' | cat - >> ~/.ssh/authorized_keys azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com: Permission denied (publickey).
おーこけとる。
そしてよくよく確認してみる。
あ。。そもそもターゲットノードってSSH認証しないとならないのでは?
丁度先ほどCOPYして配置したtest_key.pemが残っていたので、以下のように書き換ええ動作確認。
> ssh -i ~/.ssh/test_key.pem azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com 'cat ~/.ssh/id_ed25519.pub' | cat - >> ~/.ssh/authorized_keys load pubkey "/root/.ssh/test_key.pem": invalid format cat: /home/azureuser/.ssh/id_ed25519.pub: No such file or directory
(invalid formatは先ほどのsshsでも出てたので一旦置いておくとして)
/home/azureuser/.ssh/id_ed25519.pubが無いよ、って言われます。
これはよくよく考えてみたら当たり前です。
ターゲットノードに配布する前なので/home/azureuser/に公開鍵があるわけありません。
今一度コマンドの中身を確認しましょう。
1:ssh
2: -i ~/.ssh/test_key.pem
3: azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com
4: 'cat ~/.ssh/id_ed25519.pub'
5: |
6: cat - >> ~/.ssh/authorized_keys
1〜3行目はOKですね。普通にSSHしてます。
エラってるのは4行目。
あれ待って。
ここは文脈的には「SSH元の公開鍵の中身」ってしたいのに何でSSH先の公開鍵が出てるのかしら?
色々調べていくうちに以下のQiita記事にたどり着く。感謝。
そう、シングルクォートで囲むとコマンド結果の文字列が出てくるのだけど、同時にパスの対象がSSH先になってしまう!
試しにシングルクォートを外すと見事にSSH元パスとして評価された。
cat: /root/.ssh/id_ed25519.pub: Permission denied
つまり
- シングルクォートで囲まなければパスが正常に動作する
- シングルクォートで囲まないとコマンド結果が文字列で得られない(ので当然authrized_keysに追記できない)
と言うジレンマに陥ってしまいました。
つまり上記コマンドは使えない!と言う結論です。。。alpineのページ。。orz
で、さらに調べてたどり着いたQiita記事が以下。感謝。
おー!ワンライナーの記述あるやんけ!
と言うことで早速実行してみる。
bash-5.0# cat ~/.ssh/id_ed25519.pub | ssh -i ~/.ssh/test_key.pem azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com 'cat >> .ssh/authorized_keys' load pubkey "/root/.ssh/test_key.pem": invalid format bash-5.0#
ん、なんか行ったっぽ。
sshでVMに潜って確認してみる。(ややこしw)
> ssh -i ~/.ssh/test_key.pem azureuser@selenoid-qa-example-01.eastus.cloudapp.azure.com load pubkey "/root/.ssh/test_key.pem": invalid format Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 5.3.0-1034-azure x86_64) (中略) azureuser@test:~$ cd ~/.ssh/ azureuser@test:~/.ssh$ ls -la total 12 drwx------ 2 azureuser azureuser 4096 Aug 5 08:30 . drwxr-xr-x 5 azureuser azureuser 4096 Aug 5 13:18 .. -rw------- 1 azureuser azureuser 757 Aug 5 13:56 authorized_keys azureuser@test:~/.ssh$ less authorized_keys ssh-ed25519 *******(公開鍵の中身) root@buildkitsandbox
ちゃんと反映されていますね!
ではいよいよpingです。
ansible -i inventory_node.ini selenoid-qa-example-01.eastus.cloudapp.azure.com -m ping [WARNING]: log file at /Users/User/ansible_log/ansible.log is not writeable and we cannot create it, aborting [DEPRECATION WARNING]: Distribution Ubuntu 18.04 on host selenoid-qa-example-01.eastus.cloudapp.azure.com should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. selenoid-qa-example-01.eastus.cloudapp.azure.com | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" }
やたー!ping:pongした!
と言うわけで本日はここまで。
ではでは。