37

I am attempting to create a container that can access the host docker remote API via the docker socket file (host machine - /var/run/docker.sock).

The answer here suggests proxying requests to the socket. How would I go about doing this?

3 Answers 3

43

If one intends to use Docker from within a container, they should clearly understand security implications.

Accessing Docker from within the container is simple:

  1. Use the docker official image or install Docker inside the container. Or you may download archive with docker client binary as described here
  2. Expose Docker unix socket from host to container

That's why

docker run -v /var/run/docker.sock:/var/run/docker.sock \
       -ti docker

should do the trick.

Alternatively, you may expose into container and use Docker REST API

UPD: Former version of this answer (based on previous version of jpetazzo post ) advised to bind-mount the docker binary from the host to the container. This is not reliable anymore, because the Docker Engine is no longer distributed as (almost) static libraries.

Considerations:

  1. All host containers will be accessible to container, so it can stop them, delete, run any commands as any user inside top-level Docker containers.
  2. All created containers are created in a top-level Docker.
  3. Of course, you should understand that if container has access to host's Docker daemon, it has a privileged access to entire host system. Depending on container and system (AppArmor) configuration, it may be less or more dangerous
  4. Other warnings here dont-expose-the-docker-socket

Other approaches like exposing /var/lib/docker to container are likely to cause data corruption. See do-not-use-docker-in-docker-for-ci for more details.

Note for users of official Jenkins CI container

In this container (and probably in many other) jenkins process runs as a non-root user. That's why it has no permission to interact with docker socket. So quick & dirty solution is running

docker exec -u root ${NAME} /bin/chmod -v a+s $(which docker)

after starting container. That allows all users in container to run docker binary with root permissions. Better approach would be to allow running docker binary via passwordless sudo, but official Jenkins CI image seems to lack the sudo subsystem.

Sign up to request clarification or add additional context in comments.

2 Comments

Also, there is a great advanced article: jpetazzo.github.io/2016/04/03/one-container-to-rule-them-all
Mounting the docker binary is discouraged: Former versions of this post advised to bind-mount the docker binary from the host to the container. This is not reliable anymore, because the Docker Engine is no longer distributed as (almost) static libraries.
34

I figured it out. You can simply pass the the socket file through the volume argument

docker run -v /var/run/docker.sock:/container/path/docker.sock

As @zarathustra points out, this may not be the greatest idea however. See: https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/

6 Comments

You should never do this, see lvh.io/posts/…
@Zarathustra agreed and thanks. The question however, was not whether or not it should be done. I will update the answer here with warning.
this is how Portainer does it
So what's the alternative?
@DesmondMorris it seems that the link is dead. Do you have an updated version?
|
11

I stumbled across this page while trying to make docker socket calls work from a container that is running as the nobody user.

In my case I was getting access denied errors when my-service would try to make calls to the docker socket to list available containers.

I ended up using docker-socket-proxy to proxy the docker socket to my-service. This is a different approach to accessing the docker socket within a container so I though I would share it.

I made my-service able to receive the docker host it should talk to, docker-socker-proxy in this case, via the DOCKER_HOST environment variable.

Note that docker-socket-proxy will need to run as the root user to be able to proxy the docker socket to my-service.

Example docker-compose.yml:

version: "3.1"

services:
  my-service:
    image: my-service
    environment:
      - DOCKER_HOST=tcp://docker-socket-proxy:2375
    networks:
      - my-network
  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy
    environment:
      - SERVICES=1
      - TASKS=1
      - NETWORKS=1
      - NODES=1
    volumes:
     - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - my-network
    deploy:
      placement:
        constraints: [node.role == manager]

networks:
  my-network:
    driver: overlay

Note that the above compose file is swarm ready (docker stack deploy my-service) but it should work in compose mode as well (docker-compose up -d). The nice thing about this approach is that my-service does not need to run on a swarm manager anymore.

1 Comment

Would you mind explaining why your network is called my-network but your services refer to it as my-service_my-network?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.