Implement Docker isolation for multiple users Implement Docker isolation for multiple users docker docker

Implement Docker isolation for multiple users


You can use Docker in Docker (docker:dind image) to run multiple instances of Docker daemon on the same host, and have each tester use a different DOCKER_HOST to run their Compose stack. Each app instance will be deployed on a separate Docker daemon and isolated without requiring any change in docker-compose.yml.

Docker in Docker can be used to run a Docker daemon from another Docker daemon. (Docker daemon is the process actually managing your container when using docker). See Docker architecture and DinD original blogpost for details.


Example: run 2 Docker daemons exposing the app port

Let's Consider 2 testers with this docker-compose.yml:

version: 3services:  app:    image: my/app:latest    ports:      - 8080:80
  1. Run 2 instances of Docker Daemon exposing Daemon port and any port that will be exposed by Docker Compose (see below why)
# Run docker dind and map port 23751 on localhost# Expose Daemon 8080 on 8081 (port that will be used by Tester1)# privileged is required to run dind (see dind-rootless exists but is experimental) # DOCKER_TLS_CERTDIR="" is to deploy an unsecure Daemon# it's easier to use but should only be used for testing/dev purposesdocker run -d \  -p 23751:2375 \  -p 8081:8080 \  --privileged \  --name dockerd-tester1 \  -e DOCKER_TLS_CERTDIR=""   docker:dind# Second Daemon using port 23752docker run -d \  -p 23752:2375 \  -p 8082:8080 \  --privileged \  --name dockerd-tester2 \  -e DOCKER_TLS_CERTDIR=""   docker:dind
  1. Each tester can run their own stack on their Docker daemon by setting DOCKER_HOST env var:
# Tester 1 shell# use dockerd-tester1 daemon on port 23751export DOCKER_HOST=tcp://localhost:23751# run our stackdocker-compose up -d

Same for Tester 2 on dockerd-tester2 port:

# Tester 2 shellexport DOCKER_HOST=tcp://localhost:23752docker-compose up -d
  1. Interacting with Tester 1 and 2's stacks

Need the ability to build and run tests using our docker-compose files and need the ability to run the actual project on different ports

The exposed ports for each testers will be exposed on the Docker daemon host and reachable via http://$DOCKER_HOST:$APP_PORT instead of localhost:$APP_PORT (that's why we also exposed app port on each Daemon).

Considering our docker-compose.yml, testers will be able to access application such as:

# Tester 1# port 8081 is linked to port 8080 of Docker daemon running our app container# itself redirect on port 8080# in short: 8081 -> 8080 -> 80curl localhost:8081# Tester 2# 8082 -> 8080 -> 80curl localhost:8082

Our deployment will look like this

enter image description here


Alternative without exposing ports, using Docker daemon IP directly

Similar to the first example, you can also interact with the deployed app by using Docker daemon IP directly:

# Run daemon without exposing portsdocker run -d \  --privileged \  --name dockerd-tester1 \  -e DOCKER_TLS_CERTDIR=""   docker:dind# Retrieve daemon IPdocker inspect --format '{{ .NetworkSettings.IPAddress }}' dockerd-tester1# output like 172.17.0.2# use it!export DOCKER_HOST=172.17.0.2docker-compose up -d# our app port are exposed on Daemoncurl 172.17.0.2:8080

We contacted directly our Daemon via its IP instead of exposing its port on localhost.


You can even define your Docker daemons with static IPs in a docker-compose.yml such as:

version: "3"services:  dockerd-tester1:    image: docker:dind    privileged: true    environment:      DOCKER_TLS_CERTDIR: ""    networks:      dind-net:        # static IP to set as DOCKER_HOST        ipv4_address: 10.5.0.6  # same for dockerd-tester2  # ...networks:  dind-net:    driver: bridge    ipam:     config:       - subnet: 10.5.0.0/16

And then

export DOCKER_HOST=10.5.0.6# ...

Notes:

  • This may have some performance impact depending on the machine on which Daemons are deployed
  • You can use dind-rootless instead of dind to avoid using --privileged flags
  • It's better to avoid DOCKER_TLS_CERTDIR: "" for security reasons, see TLS instruction on docker image for detailed usage of TLS


The OP has already an CI/CD-system running. The question is: How can testers wrote new testcases on a own enviroment which is not running on the local maschine.

I suggest that you setup a k8s (kubernetes) instance on your new "high-end"-server. The installation of minikube is very easy and enough when you has only one server (aka node).

With k8s you can control your docker-containers (or with the correct verb "orchestrate").
You can do one of these things next:

  1. Wrote a script for the test-laptops, so they can start new environments. You can use the $USER-variable for the correct naming. Be aware that the testers may have access to k8s now.
  2. My favorite: Don't create enviroments for users, create them for merge requets. They are not bound to users and can be created by your version-control-system (e.g. gitlab). The testers can open an MR, your server setup a new enviroment and the tester is ready to go. And your testers have no access to k8s.
  3. Not recommended, but possible: Create enviroments manually for each tester.