├── .dockerignore ├── .gitignore ├── Dockerfile ├── Dockerfile.ce ├── Dockerfile.ce-systemd ├── Dockerfile.ce-systemd-ssh ├── README.md └── entrypoint.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .git 3 | .DS_Store 4 | README.md 5 | scripts 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | Dockerfile.ce -------------------------------------------------------------------------------- /Dockerfile.ce: -------------------------------------------------------------------------------- 1 | # rebased/repackaged base image that only updates existing packages 2 | FROM mbentley/ubuntu:20.04 3 | LABEL maintainer="Matt Bentley " 4 | 5 | ARG DOCKER_VER 6 | ARG BUILDX_VER 7 | ARG DEBIAN_FRONTEND=noninteractive 8 | 9 | RUN apt-get update &&\ 10 | apt-get install -y apt-transport-https ca-certificates curl gnupg iproute2 kmod net-tools socat &&\ 11 | mkdir /etc/apt/keyrings &&\ 12 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg &&\ 13 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list &&\ 14 | apt-get update &&\ 15 | apt-get install -y docker-ce &&\ 16 | apt-get purge -y docker-ce-rootless-extras docker-scan-plugin &&\ 17 | apt-get autoremove -y &&\ 18 | rm -rf /var/lib/apt/lists/* &&\ 19 | curl -fsSL -o /tmp/docker-buildx "https://github.com/docker/buildx/releases/download/${BUILDX_VER}/buildx-${BUILDX_VER}.linux-amd64" &&\ 20 | chmod +x /tmp/docker-buildx &&\ 21 | mv /tmp/docker-buildx /usr/libexec/docker/cli-plugins/docker-buildx 22 | 23 | COPY entrypoint.sh /entrypoint.sh 24 | 25 | VOLUME ["/var/lib/docker","/var/lib/containerd"] 26 | ENTRYPOINT ["/entrypoint.sh"] 27 | CMD ["dockerd","-s","overlay2","-H","unix:///var/run/docker.sock"] 28 | -------------------------------------------------------------------------------- /Dockerfile.ce-systemd: -------------------------------------------------------------------------------- 1 | FROM mbentley/docker-in-docker:ce 2 | LABEL maintainer="Matt Bentley " 3 | 4 | ENV container=docker LC_ALL=C 5 | ARG DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update &&\ 8 | apt-get install -y --no-install-recommends systemd systemd-sysv &&\ 9 | systemctl set-default multi-user.target &&\ 10 | rm -rf /var/lib/apt/lists/* &&\ 11 | rm -f /lib/systemd/system/multi-user.target.wants/* \ 12 | /etc/systemd/system/*.wants/* \ 13 | /lib/systemd/system/local-fs.target.wants/* \ 14 | /lib/systemd/system/sockets.target.wants/*udev* \ 15 | /lib/systemd/system/sockets.target.wants/*initctl* \ 16 | /lib/systemd/system/basic.target.wants/* \ 17 | /lib/systemd/system/anaconda.target.wants/* \ 18 | /lib/systemd/system/plymouth* \ 19 | /lib/systemd/system/systemd-update-utmp* &&\ 20 | (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ "${i}" = "systemd-tmpfiles-setup.service" ] || rm -f "${i}"; done) &&\ 21 | systemctl enable docker 22 | 23 | STOPSIGNAL SIGRTMIN+3 24 | ENTRYPOINT [""] 25 | CMD ["/lib/systemd/systemd"] 26 | -------------------------------------------------------------------------------- /Dockerfile.ce-systemd-ssh: -------------------------------------------------------------------------------- 1 | FROM mbentley/docker-in-docker:ce-systemd 2 | LABEL maintainer="Matt Bentley " 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt-get update &&\ 7 | apt-get install -y --no-install-recommends openssh-server &&\ 8 | rm -rf /var/lib/apt/lists/* &&\ 9 | rm -v /etc/ssh/ssh_host_* 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mbentley/docker-in-docker 2 | 3 | ## Table of Contents 4 | 5 | * [Image Tags](#image-tags) 6 | * [Build images (optional)](#build-images-optional) 7 | * [Prerequisites](#prerequisites) 8 | * [Single engine](#single-engine) 9 | * [Swarm mode cluster](#swarm-mode-cluster) 10 | 11 | ## Image Tags 12 | 13 | For a complete list of published images, see the [list of tags on Docker Hub](https://hub.docker.com/r/mbentley/docker-in-docker/tags/). For each major release, the specific Docker Enterprise bugfix versions are also available and can be found via Docker Hub. 14 | 15 | * `ce`, `latest` ([Dockerfile.ce](./Dockerfile.ce)) 16 | * `ce-systemd` ([Dockerfile.ce-systemd](./Dockerfile.ce-systemd)) 17 | * `ce-systemd-ssh` ([Dockerfile.ce-systemd-ssh](./Dockerfile.ce-systemd-ssh)) 18 | 19 | ## Build images (optional) 20 | 21 |
Expand for more details

22 | 23 | The images are published to Docker Hub so you do not need to build them unless you want to. 24 | 25 | *Note*: the images build on each other. The `ce` tag is its own build and has no other dependencies other than `ubuntu:20.04`. The `ce-systemd` tag builds from `ce`. The `ce-systemd-ssh` tag builds from `ce-systemd`. So if you want to build `ce-systemd-ssh`, you should first build `ce`, then `ce-systemd`, and finally `ce-systemd-ssh`. This process is to re-use layers. I also recommend using `docker build buildx` as just `docker build` fails to re-use some layers that have no changed. 26 | 27 | * Docker CE (stable) 28 | 29 | ``` 30 | docker buildx build \ 31 | --build-arg DOCKER_VER="$(wget -q -O - https://api.github.com/repos/moby/moby/releases/latest | jq -r .tag_name)" \ 32 | -f Dockerfile.ce \ 33 | -t mbentley/docker-in-docker:ce \ 34 | . 35 | ``` 36 | 37 | * Docker CE (with systemd) 38 | 39 | ``` 40 | docker buildx build \ 41 | -f Dockerfile.ce-systemd \ 42 | -t mbentley/docker-in-docker:ce-systemd \ 43 | . 44 | ``` 45 | 46 | * Docker CE (with systemd + ssh) 47 | 48 | ``` 49 | docker buildx build \ 50 | -f Dockerfile.ce-systemd-ssh \ 51 | -t mbentley/docker-in-docker:ce-systemd-ssh \ 52 | . 53 | ``` 54 | 55 |

56 | 57 | ## Prerequisites 58 | 59 | * Docker for Mac installed 60 | * Must have the following ports available on your host: 61 | * `1000` - TCP connection to a single Docker engine (or whatever you specify) 62 | * `1001`, `1002`, `1003` - TCP connection to Docker engines for Swarm mode (or whatever you specify) 63 | 64 | ## Single engine 65 | 66 | 1. Start engine 67 | 68 | ``` 69 | docker run -d \ 70 | --init \ 71 | --name docker \ 72 | --hostname docker \ 73 | --restart unless-stopped \ 74 | --privileged \ 75 | -p 127.0.0.1:1000:2375 \ 76 | -v /lib/modules:/lib/modules:ro \ 77 | -v docker-root:/root \ 78 | -v docker-etc-docker:/etc/docker \ 79 | -v docker-var-lib-docker:/var/lib/docker \ 80 | -v docker-etc-cni:/etc/cni \ 81 | -v docker-opt-cni:/opt/cni \ 82 | -v docker-usr-libexec-kubernetes:/usr/libexec/kubernetes \ 83 | -v docker-var-lib-kubelet:/var/lib/kubelet \ 84 | -v docker-var-log:/var/log \ 85 | --tmpfs /run \ 86 | -e MOUNT_PROPAGATION="/" \ 87 | mbentley/docker-in-docker \ 88 | dockerd -s overlay2 -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375 89 | ``` 90 | 91 | 1. Communicate with that engine 92 | 93 | ``` 94 | docker -H tcp://localhost:1000 info 95 | ``` 96 | 97 | 1. Check version 98 | 99 | ``` 100 | docker -H tcp://localhost:1000 version 101 | ``` 102 | 103 | 1. Destroy the Engine 104 | 105 | ``` 106 | docker kill docker 107 | docker rm docker 108 | docker volume rm docker 109 | ``` 110 | 111 | ## Swarm mode cluster 112 | 113 | 1. Create 3 engines 114 | 115 | ``` 116 | for ENGINE_NUM in {1..3} 117 | do 118 | docker run -d \ 119 | --init \ 120 | --name docker${ENGINE_NUM} \ 121 | --hostname docker${ENGINE_NUM} \ 122 | --restart unless-stopped \ 123 | --privileged \ 124 | -p 127.0.0.1:100${ENGINE_NUM}:2375 \ 125 | -v /lib/modules:/lib/modules:ro \ 126 | -v docker${ENGINE_NUM}-root:/root \ 127 | -v docker${ENGINE_NUM}-var-lib-docker:/var/lib/docker \ 128 | -v docker${ENGINE_NUM}-etc-docker:/etc/docker \ 129 | -v docker${ENGINE_NUM}-etc-cni:/etc/cni \ 130 | -v docker${ENGINE_NUM}-opt-cni:/opt/cni \ 131 | -v docker${ENGINE_NUM}-usr-libexec-kubernetes:/usr/libexec/kubernetes \ 132 | -v docker${ENGINE_NUM}-var-lib-kubelet:/var/lib/kubelet \ 133 | -v docker${ENGINE_NUM}-var-log:/var/log \ 134 | --tmpfs /run \ 135 | -e MOUNT_PROPAGATION="/" \ 136 | mbentley/docker-in-docker \ 137 | dockerd -s overlay2 -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375 138 | done 139 | ``` 140 | 141 | 1. Create a new Swarm 142 | 143 | ``` 144 | docker -H tcp://localhost:1001 swarm init 145 | ``` 146 | 147 | 1. Get the worker join token and command 148 | 149 | ``` 150 | TOKEN=$(docker -H tcp://localhost:1001 swarm join-token worker -q) 151 | JOIN_COMMAND="swarm join --token ${TOKEN} $(docker container inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker1):2377" 152 | ``` 153 | 154 | 1. Join engine 2 155 | 156 | ``` 157 | docker -H tcp://localhost:1002 ${JOIN_COMMAND} 158 | ``` 159 | 160 | 1. Join engine 3 161 | 162 | ``` 163 | docker -H tcp://localhost:1003 ${JOIN_COMMAND} 164 | ``` 165 | 166 | 1. Check status 167 | 168 | ``` 169 | docker -H tcp://localhost:1001 node ls 170 | ``` 171 | 172 | 1. Destroy Swarm cluster 173 | 174 | ``` 175 | docker kill docker1 docker2 docker3 176 | docker rm docker1 docker2 docker3 177 | docker volume rm docker1 docker2 docker3 178 | ``` 179 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # set the container variable so that processes know we are in a docker container 6 | export container=docker 7 | 8 | DOCKERD_PID="$(pgrep dockerd || true)" 9 | if [ -f "/var/run/docker.pid" ] && [ -z "${DOCKERD_PID}" ] 10 | then 11 | # pid file exists and docker isn't running 12 | echo -n "INFO: Removing stale pid file (/var/run/docker.pid)..." 13 | rm /var/run/docker.pid 14 | echo "done" 15 | elif [ -n "${DOCKERD_RUNNING}" ] 16 | then 17 | # docker is running 18 | echo "ERROR: Docker is already running!" 19 | echo " Hint: This script should only be executed as the container entrypoint!" 20 | exit 1 21 | fi 22 | 23 | # set mount propagation 24 | if [ -n "${MOUNT_PROPAGATION}" ] 25 | then 26 | for MOUNT in ${MOUNT_PROPAGATION} 27 | do 28 | echo -n "INFO: Mounting ${MOUNT} as 'rshared'..." 29 | mount --make-rshared "${MOUNT}" 30 | echo "done" 31 | done 32 | fi 33 | 34 | # Mount /tmp, if needed 35 | if ! mountpoint -q /tmp 36 | then 37 | echo -n "INFO: Mounting /tmp with as tmpfs..." 38 | mount -t tmpfs none /tmp 39 | echo "done" 40 | fi 41 | 42 | # cgroup v2: enable nesting (from https://github.com/moby/moby/blob/v20.10.8/hack/dind#L28-L38) 43 | if [ -f /sys/fs/cgroup/cgroup.controllers ] 44 | then 45 | echo -n "INFO: cgroups v2 detected; enabling nesting..." 46 | # move the processes from the root group to the /init group, 47 | # otherwise writing subtree_control fails with EBUSY. 48 | # An error during moving non-existent process (i.e., "cat") is ignored. 49 | mkdir -p /sys/fs/cgroup/init 50 | xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : 51 | # enable controllers 52 | sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ 53 | > /sys/fs/cgroup/cgroup.subtree_control 54 | echo "done" 55 | fi 56 | 57 | # check to see if /usr/bin/containerd exists; if not; we are probably running an older version 58 | if [ ! -f /usr/bin/containerd ] 59 | then 60 | # /usr/bin/containerd doesn't exist; expect that it is packaged with the engine 61 | CONTAINERD_PID="$(pgrep docker-containerd || true)" 62 | if [ -f "/var/run/docker/libcontainerd/docker-containerd.pid" ] && [ -z "${CONTAINERD_PID}" ] 63 | then 64 | # pid file exists and containerd isn't running 65 | echo -n "INFO: Removing stale pid file (/var/run/docker/libcontainerd/docker-containerd.pid)..." 66 | rm /var/run/docker/libcontainerd/docker-containerd.pid 67 | echo "done" 68 | fi 69 | else 70 | # /usr/bin/containerd exists; we should start containerd because docker will start it differently than systemd would have 71 | echo "INFO: Starting containerd..." 72 | /usr/bin/containerd & 73 | 74 | # wait to make sure containerd starts 75 | while [ ! -S "/run/containerd/containerd.sock" ] 76 | do 77 | # wait until the containerd socket exists 78 | sleep .25 79 | done 80 | echo "INFO: containerd started successfully" 81 | fi 82 | 83 | echo "INFO: Executing CMD: ${*}" 84 | exec "${@}" 85 | --------------------------------------------------------------------------------