はじめに
起動させたコンテナの中に入るには ssh を使うのではなく nsenter を使うのがオフィシャルに推奨されていた。
2014年10月17日追記: Docker1.3 からは $ docker exec
というコマンドが追加された。これは nsenter を replcace するものなので、今後はこれを利用する。
ssh を使わない方が良いという話は Docker の公式ブログ WHY YOU DON'T NEED TO RUN SSHD IN YOUR DOCKER CONTAINERS に詳しく書かれている。(Qiita に翻訳もある 【翻訳】Docker コンテナー内で SSHd を実行する必要がない理由 - helical618)
CoreOS で docke exec を使ってコンテナの中に入る。
hello コンテナを起動したあと、
core@core-01 ~ $ docker run -d --name hello busybox /bin/sh -c "while true; do echo Hello World; sl
eep 1; done"
ad6aa31ae8194515e3ffb2e1632849f4cd79fed6af61c36ec6d1d144e86e13f9
exec
を使ってコンテナの中に入る。
core@core-01 ~ $ docker exec -it hello /bin/sh
/ # ls
bin etc lib linuxrc mnt proc run sys usr
dev home lib64 media opt root sbin tmp var
/ # exit
より正確な説明としては、exec
はコンテナにログインするためだけにあるのではなく、起動中のコンテナに 別のプロセスを注入する コマンドである。
CoreOS で nsenter を使ってコンテナの中に入る
Ubuntu や CentOS だと nsenter は公式リポジトリの README に書かれた方法でインストールする必要があるが、最新の CoreOS にはデフォルトで nsenter が入っている(素晴らしい)。
参考: nsinit (or nsenter) should be installed and available #18
# dd-agent という名前のコンテナが起動している
core@core-01 ~ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
60990982b230 datadog/docker-dd-agent:latest /usr/local/bin/run-d 8 minutes ago Up 8 minutes 8125/udp dd-agent
# dd-agent の PID を取得
core@core-01 ~ $ PID=$(docker inspect --format {{.State.Pid}} dd-agent)
# nsenter でコンテナの中に入る
core@core-01 ~ $ sudo nsenter --target $PID --mount --uts --ipc --net --pid
root@dd-agent:/#
CoreOS で docker-enter を使ってコンテナの中に入る
docker-enter は nsenter をラップしたシェルスクリプトで、コンテナ ID やコンテナ名を元にコンテナの中に入れるコマンドとして使う。
$ docker-enter <コンテナ ID>
# または
$ docker-enter <コンテナ名>
nsenter の README に書かれた方法でインストールした場合、デフォルトでは /usr/local/bin/docker-enter
に置かれるが、CoreOS では docker-enter
までは入ってないみたい。 CoreOS の /usr
以下は Read Only で、Cloud-Config を使っても書き込めなかった。 yungsang さんが作られている yungsang/coreos - Vagran Cloud を使えば docker-enter
入りの CoreOS が利用可能である。今のところ Cloud-Config + Docker Image のみだけでいけたらめっちゃシンプルでいいなと思っているので Cloud-Config を使って何とか出来ないかと考え core ユーザの PATH
を調べてみると
core@core-01 ~ $ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin:/usr/x86_64-cros-linux-gnu/gcc-bin/4.6.3
/opt/bin
がある。調べるとここは書き込み可能。ということで /opt/bin/docker-enter
に置く事にした。 /opt/bin
はデフォルトで存在しないのでディレクトリを作成しないといけないかと思ったが、 write_files
でファイルを存在しないディレクトリに置こうとした場合は、root 権限でディレクトリも作ってくれた。
#cloud-init
# 一部抜粋
write_files:
- path: /opt/bin/docker-enter
permissions: 0755
content: |
#!/bin/sh
#
# Original Source:
# https://github.com/jpetazzo/nsenter/blob/master/docker-enter
#
if [ -e $(dirname "$0")/nsenter ]; then
# with boot2docker, nsenter is not in the PATH but it is in the same folder
NSENTER=$(dirname "$0")/nsenter
else
NSENTER=nsenter
fi
if [ -z "$1" ]; then
echo "Usage: docker-enter CONTAINER [COMMAND [ARG]...]"
echo ""
echo "Enters the Docker CONTAINER and executes the specified COMMAND."
echo "If COMMAND is not specified, runs an interactive shell in CONTAINER."
else
PID=$(docker inspect --format "{{.State.Pid}}" "$1")
if [ -z "$PID" ]; then
exit 1
fi
shift
OPTS="--target $PID --mount --uts --ipc --net --pid --"
if [ -z "$1" ]; then
# No command given.
# Use su to clear all host environment variables except for TERM,
# initialize the environment variables HOME, SHELL, USER, LOGNAME, PATH,
# and start a login shell.
"$NSENTER" $OPTS su - root
else
# Use env to clear all host environment variables.
"$NSENTER" $OPTS env --ignore-environment -- "$@"
fi
fi
メモと感想
/opt/bin
をこんな感じで使って良いのか
/etc
が書き込み出来るのは知っていたが、/etc
にコマンドを置くのはアレだと思っていたら、/opt
が writable で場所的にも悪くはないと思って使っているけどどうなんだろう。
-> 2014/09/07 追記 @yungsang さんからコメント頂きました!
- linux のお作法的にも問題ない(例えば Chef や Sensu のインストーラとかも
/opt/chef
や/opt/sensu
とかに置くしね、自分も ubuntu のとき/opt/app
にアプリケーション置いてる) - CoreOS チームも
/opt
以下に Kubernetes 置いてる - 参考 - Running Kubernetes Example on CoreOS, Part 1 - CoreOS Blog
nsenter について(または ssh でログインしないことについて)
コンテナの中で sshd を立てておくというのはコンテナ内に複数プロセス動かすことになる。
これはコミュニティの中で意見が割れている:
- コンテナの中は 1 プロセスのみ動かす派
- コンテナの中で複数プロセス動かす派
にかかわるのかもしれない。この話は Docker Misconceptions([翻訳] Dockerについてよくある勘違い)でよく検討されている。コンテナの中を 1 プロセスにすると、プロセスのログを stdout にしておくことで $ docker logs
でログの取得・閲覧が済むので、コンテナの中にログインしてどうこうする、ということも減ったり、コンテナの扱い方としてもシンプルになる気がしている。ただ Sensu とか色んなコンポーネントが必要になるものについては複数プロセスにした方が良い気がしている。適材適所なのかなぁ。
Docker on Ubuntu の時は Chef を使って docker-enter を入れている
Chef から docker を扱う bflad/chef-docker の docker_container
resource を使って esenter を入れている。
コマンドラインから esenter をインストールする場合は
$ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
とする。それを docker_container
resource を使って行うため以下のように書いてインストールしている。
# your_recipe.rb
#
# Install docker-enter to /usr/local/bin/docker-enter
# https://github.com/jpetazzo/nsenter
#
docker_container "nsenter" do
image "jpetazzo/nsenter"
detach false
remove_automatically true
volume "/usr/local/bin:/target"
not_if { ::File.exists?("/usr/local/bin/docker-enter") }
action :run
end