LoginSignup
71
76

More than 5 years have passed since last update.

CoreOS で起動中のコンテナの中に入る

Last updated at Posted at 2014-09-07

はじめに

起動させたコンテナの中に入るには 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 置いてる

nsenter について(または ssh でログインしないことについて)

コンテナの中で sshd を立てておくというのはコンテナ内に複数プロセス動かすことになる。

これはコミュニティの中で意見が割れている:

  • コンテナの中は 1 プロセスのみ動かす派
  • コンテナの中で複数プロセス動かす派

にかかわるのかもしれない。この話は Docker Misconceptions[翻訳] Dockerについてよくある勘違い)でよく検討されている。コンテナの中を 1 プロセスにすると、プロセスのログを stdout にしておくことで $ docker logs でログの取得・閲覧が済むので、コンテナの中にログインしてどうこうする、ということも減ったり、コンテナの扱い方としてもシンプルになる気がしている。ただ Sensu とか色んなコンポーネントが必要になるものについては複数プロセスにした方が良い気がしている。適材適所なのかなぁ。

Docker on Ubuntu の時は Chef を使って docker-enter を入れている

Chef から docker を扱う bflad/chef-dockerdocker_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

REF

71
76
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
76