Overview

How to enter a Docker container

3 Comments

In previous articles [1,2,3] Lukas Pustina has given an introduction to system-level virtualization with Docker. In this article I discuss 4 options how to connect to a running Docker container and interact with it. All code examples are available on GitHub so you can try yourself.

nsenter

The nsenter tool is part of the util-linux package since version 2.23. It provides access to the namespace of another process. nsenter requires root privileges to work properly. Unfortunately, util-linux is still at version 2.20 in Ubuntu 14.04. To install the latest version (2.24) proceed as follows:

cd /tmp
curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-
cd util-linux-2.24
./configure --without-ncurses
make nsenter
cp nsenter /usr/local/bin

In order to connect to a container, you have to find out the PID of the first process in the container.

docker inspect --format "{{ .State.Pid }}" <container-id>

With that PID you can connect to the container:

nsenter --target $PID --mount --uts --ipc --net --pid

nsinit

Since version 0.9 Docker offers its own library for managing containers called libcontainer. The tool nsinit of the libcontainer allows the user direct access to the linux namespace and cgroup kernel features. Before you can install nsinit you have to install the Go runtime environment:

apt-get install git golang-go
 
mkdir -p $HOME/go-dev/bin
mkdir -p $HOME/go-dev/src
 
echo "export GOPATH=\$HOME/go-dev" >> ~/.profile
echo "PATH=\$PATH:\$GOPATH/bin" >> ~/.profile
 
source ~/.profile

In a second step, you install nsinit:

mkdir -p $GOPATH/src/github.com/dotcloud
cd $GOPATH/src/github.com/dotcloud
 
git clone https://github.com/dotcloud/docker.git
cd $GOPATH/src/github.com/dotcloud/docker
 
/usr/bin/go get -v github.com/dotcloud/docker/vendor/src/github.com/docker/libcontainer/nsinit

nsinit reads the configuration data from the container directory located in /var/lib/docker/execdriver/native/<container-id>. In order to use nsinit you have to change into that container directory. This requires root privileges because the directory /var/lib/docker is only readable for root. The container id can be determined with the docker ps command. Once you stepped into the directory you can connect to the container:

nsinit exec /bin/bash

lxc(-attach)

Up to version 0.8.1 LXC was the base for Docker to manage containers and Docker still supports it. But since version 0.9.0 Docker uses libcontainer by default, cutting the dependency to LXC. Thus, you cannot use lxc-attach by default anymore.

If you still want to use lxc-attach you have to restart the Docker daemon with the -e lxc option. With this option Docker will use LXC under the hood again. The easiest way to do so, is to create the file /etc/default/docker (if it does not exist yet) and add the following line:

DOCKER_OPTS=”-e lxc”

Now you have to restart the Docker daemon. To connect to a container you need the full container id:

docker ps --no-trunc

Now you can connect to the container. For this to work, root privileges are needed again:

lxc-attach -n <container-id> -- /bin/bash

sshd

The three previous methods all require root privileges on the host system. To avoid that, accessing containers via SSH is a good alternative.

For that you need to build a base image supporting an SSH daemon. At this point we run into the problem that we can only execute one command with the Docker keywords CMD or ENTRYPOINT. If this were the sshd process we could not run any other process. A workaround is to create a script to start all necessary other processes or to use a process management tool like supervisord. There is excellent documentation on how to use supervisord on the Docker website. Once you have started a container with a sshd process, you can connect as usual with a ssh client.

Fazit

The sshd approach is probably the easiest one and the most users are accustomed to connect to a virtual machine via ssh. In addition, you also do not need root privileges in order to connect with a container. However, there are a lot of discussions [1,2] about whether a container should manage more than one process or not. In the end, you have one additional sshd process per container which is basically not the idea of ​​process virtualization.

For the other three options, root privileges are required. Docker has used LXC to manage its containers up to version 0.8.1. For this reason, it was pretty easy to use lxc-attach. Since version 0.9.0 the Docker daemon must be started with the option -e lxc for still using LXC under the hood. But with this option set, Docker relies on LXC again which might vary across distributions or installations.

nsenter and nsinit are basically equivalent. The main difference between both tools is that nsinit will setup a new process in the container and nsenter will just enter the namespace. Jerome Petazzoni has described it very well in the Docker Blog.

Kommentare

  • Benedikt Ritter

    30. January 2015 von Benedikt Ritter

    From docker 1.3.0 on you can use process injection: docker exec -it CONTAINER_NAME /bin/bash will do the trick.

  • Shi Lei

    2. April 2015 von Shi Lei

    Now there is a simple solution.
    docker exec

  • Alexander Berresch

    7. April 2015 von Alexander Berresch

    Hi Benedikt & Shi,

    yes you’re right. Since docker version 1.3.0 you have the possibility to use:

    docker exec

    The steps described in this article were only workarounds to have the same feature for docker < v1.3.0best regards Alex

Comment

Your email address will not be published. Required fields are marked *