RHEL/CentOS 6で Docker に nsinit/nsenter する

  • 33
    Like
  • 1
    Comment
More than 1 year has passed since last update.

RHEL/CentOS 6 上で Docker に nsinit/nsenter を使って attach する方法のメモです。

CoreOS ですと、すでに Qiita に投稿されている方がいらっしゃいます。

結論から言いますと、 util-linux に入っている nsenter を使う方がよいです。 nsinit のほうはちょっと苦労します。

util-linux に入っている nsenter を使う

Attaching to a container with Docker 0.9 and libcontainer
書いてある方法でいけます。
ただし、 gettext を 0.18.3 以上にしないとビルドできないため、 gettext もソースからビルドします。

途中、ルーチンとエイリアス定義をしていますが、好みに応じて変更してください。

  1. gettext インストール
    1. curl -LO http://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.1.tar.xz
    2. tar xf gettext-0.19.1.tar.xz
    3. cd gettext-0.19.1
    4. ./configure --prefix=/opt/gettext-0.19.1
    5. make -j4 && sudo make install
  2. util-linux インストール
    1. curl -LO https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.2.tar.xz
    2. tar xf util-linux-2.24.2.tar.xz
    3. cd util-linux-2.24.2
    4. CFLAGS=-I/opt/gettext-0.19.1/include LDFLAGS=-L/opt/gettext-0.19.1/lib ./configure --prefix=/opt/util-linux-2.24.2
    5. make -j4 && sudo make install
  3. nsenter するためのシェルスクリプトのルーチンを ~/.bashrc などに定義する

    docker_nsenter() {
        declare container_id=$1
        if [ -z "$container_id" ]; then
            echo "Usage: docker_container <container_id>" >&2
            return 1
        fi
        /opt/util-linux-2.24.2/bin/nsenter --mount --uts --ipc --net --pid --target $(docker inspect --format '{{.State.Pid}}' $container_id)
    }
    alias docker-nsenter='docker_nsenter'
    
  4. source ~/.bashrc でルーチン読み込み

  5. docker-nsenter でプロセスに attach する

    • docker ps でコンテナID確認

      # docker ps
      CONTAINER ID        IMAGE                COMMAND                CREATED             STATUS              PORTS                   NAMES
      dc1681d20f84        ssh-gateway:latest   /bin/sh -c /sbin/ini   8 days ago          Up 6 days           0.0.0.0:49153->22/tcp   suspicious_pasteur
      
    • docker-nsenter <container_id> で attach

      # docker-nsenter dc16
      [root@dc1681d20f84 /]#
      

docker/libcontainer に入っている nsinit を使う

こちらは CentOS の場合、現状それなりに苦労します(最初諦めた)。
nsinit を使うためには、 Go が必要です。

go get をしたあと、 Docker 1.0 では動かないため(HEAD の Docker が必要)、タグに巻き戻して パッチ をあてています。

お作法などがありそうな気がしていますが、 Go に未熟で分かっていないので、もっと良い方法がありましたら教えて下さい。

  1. Go 環境をインストール
    • yum install golang
  2. パッケージを入れるためのディレクトリ(GOPATH) を作成
    1. mkdir /var/lib/go
    2. echo 'export GOPATH=/var/lib/go' >> ~/.bashrc; source ~/.bashrc
  3. nsinit をインストール(要パッチ)
    • Docker v1.0 の場合
      1. go get -d github.com/docker/libcontainer/nsinit
      2. cd $GOPATH/src/github.com/docker/libcontainer
      3. git checkout -b v1.0.1+patch v1.0.1
      4. git fetch origin refs/pull/58/head
      5. git cherry-pick FETCH_HEAD
      6. go install github.com/docker/libcontainer/nsinit
    • Docker v1.1 の場合
      1. go get -d github.com/docker/libcontainer/nsinit
      2. cd $GOPATH/src/github.com/docker/libcontainer
      3. git checkout -b v1.1.0+patch v1.1.0
      4. git fetch origin refs/pull/58/head
      5. git cherry-pick FETCH_HEAD
      6. go install github.com/docker/libcontainer/nsinit/main
        • v1.1.0 ではコマンド構成が代わり、 github.com/docker/libcontainer/nsinit /main としないとインストールできません
      7. mv $GOPATH/bin/main $GOPATH/bin/nsinit
  4. nsinit するためのシェルスクリプトのルーチンを ~/.bashrc などに定義する

    docker_nsinit() {
        declare container_id=$1
        if [ -z "$container_id" ]; then
            echo "Usage: docker_nsinit <container_id> <command> [[args]...]" >&2
            return 1
        fi
    
        shift
    
        declare full_container_id=$(docker inspect --format '{{.Id}}' $container_id)
        (cd /var/lib/docker/execdriver/native/$full_container_id && $GOPATH/bin/nsinit $*)
    }
    alias docker-nsinit='docker_nsinit'
    
  5. source ~/.bashrc でルーチン読み込み

  6. docker-nsinit でプロセスに attach する

    • docker ps でコンテナID確認

      # docker ps
      CONTAINER ID        IMAGE                COMMAND                CREATED             STATUS              PORTS                   NAMES
      dc1681d20f84        ssh-gateway:latest   /bin/sh -c /sbin/ini   8 days ago          Up 6 days           0.0.0.0:49153->22/tcp   suspicious_pasteur
      
    • docker-nsinit <container_id> exec -- bash で attach

      # docker-nsinit dc16 exec -- bash
      [root@dc1681d20f84 /]#
      

なお、 nsinit に関しては、以下のエラーメッセージが表示されるというはまりを経験しました。

  • nsenter: Failed to open ns file "/proc/1408/ns/pid" for ns "pid" with error: "No such file or directory" と怒られる
    • Issue#42 で報告したあと、パッチ を作っていただいた方がいらっしゃいます。
    • こちらのパッチを v1.0.1 (Docker v1.1.0 の場合は v1.1.0)にマージすることで解決します
  • 2014/06/29 23:22:06 failed to exec: bridge is not specified と怒られる

    • Docker v1.0 において、パッチを最新の master にマージすると発生します
    • Victor Marmol によれば、

      Yes, there have been a few changes to libcontainer that have not yet been integrated into Docker. If you're using libcontainer alongside Docker you must build with the version tagged for that Docker release. In this case, we've changed the checkpoint to include the network information.

    とのことで、Docker 1.0 を使う場合は v1.0.1 タグにマージしないといけません。