ssh
やdocker exec
、kubectl exec
で、シェルを起動せずに直接コマンドを実行できるが、ssh
などを実行するローカルの標準出力をリモートホストやコンテナの標準入力として処理する方法について。
SSHの場合
前提。
ローカルのhostnameはcloud-dev
で、リモートはrhel8
となっている。
[zaki@cloud-dev ~]$ hostname cloud-dev [zaki@cloud-dev ~]$ ssh 192.168.0.27 hostname rhel8
ローカルのhostname
コマンド実行結果をリモートにパイプし、リモートではそれを標準入力(-
)から受けてファイルへリダイレクト。(コマンドにあまり意味はない)
[zaki@cloud-dev ~]$ hostname | ssh 192.168.0.27 sh -c 'cat - > /tmp/hostname.txt'
結果、リモートでは/tmp/hostname.txt
が生成され、ローカルのhostname
の結果が保存される。
ローカルにはこのファイルは無い。
[zaki@cloud-dev ~]$ ssh 192.168.0.27 cat /tmp/hostname.txt cloud-dev [zaki@cloud-dev ~]$ ls /tmp/hostname.txt ls: /tmp/hostname.txt にアクセスできません: そのようなファイルやディレクトリはありません
Dockerのコンテナの場合
前提。
debian
イメージでデプロイしたコンテナIDa24d81dbfee2
のコンテナが動作している。
コンテナでhostname
を実行するとコンテナIDと同じになっている。
[zaki@cloud-dev ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a24d81dbfee2 debian "tail -f /dev/null" 2 seconds ago Up 1 second relaxed_heisenberg [zaki@cloud-dev ~]$ docker exec -i a24d hostname a24d81dbfee2
前述SSHの例と同様に、ローカルのhostname
の実行結果をパイプでdocer exec
で実行中コンテナの標準入力としてファイルへリダイレクト。
ポイントは-i
を付与すること。これが無いと標準入力を引き継げずに入力がなくなり、空ファイルが生成される。
また、-i
とセットで使うことの多い-t
は、付与するとthe input device is not a TTY
とエラーになるので使用しない。
[zaki@cloud-dev ~]$ hostname | docker exec -i a24d sh -c 'cat - > /tmp/hostname.txt'
結果、コンテナ内の/tmp/hostname.txt
にローカルのコマンド実行結果が保存される。
[zaki@cloud-dev ~]$ docker exec a24d cat /tmp/hostname.txt cloud-dev [zaki@cloud-dev ~]$ ls /tmp/hostname.txt ls: /tmp/hostname.txt にアクセスできません: そのようなファイルやディレクトリはありません
KubernetesのPodの場合
前提。
HTTPサーバーのPodであるsample-http
が動作している。
Pod名はsample-http-6c94f59975-w89gd
でPod内コンテナのホスト名も同じ名称になっている。
[zaki@cloud-dev ~]$ kubectl get pod NAME READY STATUS RESTARTS AGE sample-http-6c94f59975-w89gd 1/1 Running 0 7d12h [zaki@cloud-dev ~]$ kubectl exec sample-http-6c94f59975-w89gd -- hostname sample-http-6c94f59975-w89gd
SSHとDockerの例同様、ローカルのhostname
の実行結果をPodへパイプし、Pod内でファイルへリダイレクトしてみる。
ポイントはDocker同様に-i
を付与すること。これが無いと標準入力を引き継げずに入力がなくなり、空ファイルが生成される。
また、やはりdocker exec
と同様に-t
を併用すると Unable to use a TTY - input is not a terminal or the right kind of file
というエラーになるので使用しない。
[zaki@cloud-dev ~]$ hostname | kubectl exec -i sample-http-6c94f59975-w89gd -- sh -c 'cat - > /tmp/hostname.txt' [zaki@cloud-dev ~]$ kubectl exec sample-http-6c94f59975-w89gd -- cat /tmp/hostname.txt cloud-dev [zaki@cloud-dev ~]$ ls /tmp/hostname.txt ls: /tmp/hostname.txt にアクセスできません: そのようなファイルやディレクトリはありません
使いどころ
個人的によく使うパターンは、ローカルにあるtar.gzのアーカイブファイルを、「リモートに転送してリモート上で展開せず」に、「tar.gzの中身を標準出力で転送してリモートで展開する」ことで、リモート上にtar.gzのアーカイブファイルそのものの転送と展開後の削除を省略したりする。
同じように、(この文脈だと紛らわしいけど)ローカルのコンテナイメージをdocker save
の結果をファイルではなく標準出力でssh
にパイプし、リモートでdocker load
することでイメージのtarファイル作成・転送・展開を一気にできる。
コンテナの場合も、例えばDBの初期構築用SQLファイルをローカルから一気にコンテナ内のコマンドに流したりできる。
SSHは昔から(横着したいときに特に)よく使ってたんだけど、そういえばDockerやKubernetesで同じことできるんだっけ?と思って試してみたらちゃんとできた。