Signed-off-by: Konrad Ponichtera <konpon96@gmail.com>
| ... | ... |
@@ -149,6 +149,18 @@ RUN --mount=type=cache,sharing=locked,id=moby-cross-true-aptlib,target=/var/lib/ |
| 149 | 149 |
|
| 150 | 150 |
FROM runtime-dev-cross-${CROSS} AS runtime-dev
|
| 151 | 151 |
|
| 152 |
+FROM base AS delve |
|
| 153 |
+# DELVE_VERSION specifies the version of the Delve debugger binary |
|
| 154 |
+# from the https://github.com/go-delve/delve repository. |
|
| 155 |
+# It can be used to run Docker with a possibility of |
|
| 156 |
+# attaching debugger to it. |
|
| 157 |
+# |
|
| 158 |
+ARG DELVE_VERSION=v1.8.1 |
|
| 159 |
+RUN --mount=type=cache,target=/root/.cache/go-build \ |
|
| 160 |
+ --mount=type=cache,target=/go/pkg/mod \ |
|
| 161 |
+ GOBIN=/build/ GO111MODULE=on go install "github.com/go-delve/delve/cmd/dlv@${DELVE_VERSION}" \
|
|
| 162 |
+ && /build/dlv --help |
|
| 163 |
+ |
|
| 152 | 164 |
FROM base AS tomll |
| 153 | 165 |
# GOTOML_VERSION specifies the version of the tomll binary to build and install |
| 154 | 166 |
# from the https://github.com/pelletier/go-toml repository. This binary is used |
| ... | ... |
@@ -301,6 +313,7 @@ RUN pip3 install yamllint==1.26.1 |
| 301 | 301 |
COPY --from=dockercli /build/ /usr/local/cli |
| 302 | 302 |
COPY --from=frozen-images /build/ /docker-frozen-images |
| 303 | 303 |
COPY --from=swagger /build/ /usr/local/bin/ |
| 304 |
+COPY --from=delve /build/ /usr/local/bin/ |
|
| 304 | 305 |
COPY --from=tomll /build/ /usr/local/bin/ |
| 305 | 306 |
COPY --from=tini /build/ /usr/local/bin/ |
| 306 | 307 |
COPY --from=registry /build/ /usr/local/bin/ |
| ... | ... |
@@ -68,6 +68,7 @@ DOCKER_ENVS := \ |
| 68 | 68 |
-e DOCKER_TEST_HOST \ |
| 69 | 69 |
-e DOCKER_USERLANDPROXY \ |
| 70 | 70 |
-e DOCKERD_ARGS \ |
| 71 |
+ -e DELVE_PORT \ |
|
| 71 | 72 |
-e TEST_FORCE_VALIDATE \ |
| 72 | 73 |
-e TEST_INTEGRATION_DIR \ |
| 73 | 74 |
-e TEST_SKIP_INTEGRATION \ |
| ... | ... |
@@ -114,8 +115,9 @@ DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),) |
| 114 | 114 |
|
| 115 | 115 |
DOCKER_IMAGE := docker-dev |
| 116 | 116 |
DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",) |
| 117 |
+DELVE_PORT_FORWARD := $(if $(DELVE_PORT),-p "$(DELVE_PORT)",) |
|
| 117 | 118 |
|
| 118 |
-DOCKER_FLAGS := $(DOCKER) run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) |
|
| 119 |
+DOCKER_FLAGS := $(DOCKER) run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) $(DELVE_PORT_FORWARD) |
|
| 119 | 120 |
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR)) |
| 120 | 121 |
export BUILD_APT_MIRROR |
| 121 | 122 |
|
| ... | ... |
@@ -77,6 +77,8 @@ if [ -z "$mtu" ]; then |
| 77 | 77 |
mtu=1500 |
| 78 | 78 |
fi |
| 79 | 79 |
|
| 80 |
+dockerd="${DOCKERD:-dockerd}"
|
|
| 81 |
+ |
|
| 80 | 82 |
if [ -z "$_DOCKERD_ROOTLESS_CHILD" ]; then |
| 81 | 83 |
_DOCKERD_ROOTLESS_CHILD=1 |
| 82 | 84 |
export _DOCKERD_ROOTLESS_CHILD |
| ... | ... |
@@ -128,5 +130,7 @@ else |
| 128 | 128 |
mount --rbind ${realpath_etc_ssl} /etc/ssl
|
| 129 | 129 |
fi |
| 130 | 130 |
|
| 131 |
- exec dockerd $@ |
|
| 131 |
+ # shellcheck disable=SC2068 |
|
| 132 |
+ # shellcheck disable=SC2086 |
|
| 133 |
+ exec $dockerd $@ |
|
| 132 | 134 |
fi |
| 9 | 10 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,66 @@ |
| 0 |
+### Debugging the daemon |
|
| 1 |
+ |
|
| 2 |
+The Docker daemon inside the development container can be debugged with [Delve](https://github.com/go-delve/delve). |
|
| 3 |
+ |
|
| 4 |
+Delve debugger listens on a port, which has to be exposed outside the development container. |
|
| 5 |
+Also, in order to be able to debug the daemon, it has to be compiled with the debugging symbols. |
|
| 6 |
+This can be done by launching the development container with the following command: |
|
| 7 |
+ |
|
| 8 |
+```bash |
|
| 9 |
+$ make BIND_DIR=. DOCKER_DEBUG=1 DELVE_PORT=127.0.0.1:2345:2345 shell |
|
| 10 |
+``` |
|
| 11 |
+ |
|
| 12 |
+The `DOCKER_DEBUG` variable disables build optimizations, allowing to debug the binary, |
|
| 13 |
+while `DELVE_PORT` publishes the specified port for use with the debugger. |
|
| 14 |
+ |
|
| 15 |
+The `DELVE_PORT` variable accepts the port in the same format as Docker CLI's `--publish` (`-p`) option. |
|
| 16 |
+This means that the port can be published in multiple ways: |
|
| 17 |
+ |
|
| 18 |
+1. `DELVE_PORT=127.0.0.1:2345:2345` - exposes debugger on port `2345` for local development only (recommended) |
|
| 19 |
+2. `DELVE_PORT=2345:2345` - exposes debugger on port `2345` without binding to specific IP |
|
| 20 |
+3. `DELVE_PORT=2345` - same as above |
|
| 21 |
+ |
|
| 22 |
+**IMPORTANT:** Publishing the port without binding it to localhost (127.0.0.1) might expose the debugger |
|
| 23 |
+outside the developer's machine and is not recommended. |
|
| 24 |
+ |
|
| 25 |
+## Running Docker daemon with debugger attached |
|
| 26 |
+ |
|
| 27 |
+1. Run development container with build optimizations disabled and Delve enabled: |
|
| 28 |
+ ```bash |
|
| 29 |
+ $ make BIND_DIR=. DOCKER_DEBUG=1 DELVE_PORT=127.0.0.1:2345:2345 shell |
|
| 30 |
+ ``` |
|
| 31 |
+2. Inside the development container: |
|
| 32 |
+ 1. Build the Docker daemon: |
|
| 33 |
+ ```bash |
|
| 34 |
+ $ ./hack/make.sh binary |
|
| 35 |
+ ``` |
|
| 36 |
+ 2. Install the newly-built daemon: |
|
| 37 |
+ ```bash |
|
| 38 |
+ $ make install |
|
| 39 |
+ ``` |
|
| 40 |
+ 3. Run the daemon through the `make.sh` script: |
|
| 41 |
+ ```bash |
|
| 42 |
+ $ ./hack/make.sh run |
|
| 43 |
+ ``` |
|
| 44 |
+ The execution will stop and wait for the IDE or Delve CLI to attach |
|
| 45 |
+ to the port, specified with the `DELVE_PORT` variable. |
|
| 46 |
+ Once the IDE or Delve CLI is attached, the execution will continue. |
|
| 47 |
+ |
|
| 48 |
+## Debugging from IDE (on example of GoLand 2021.3) |
|
| 49 |
+ |
|
| 50 |
+1. Open the project in GoLand |
|
| 51 |
+2. Click *Add Configuration* on the taskbar |
|
| 52 |
+  |
|
| 53 |
+3. Create the *Go Remote* configuration. |
|
| 54 |
+ No changes are necessary, unless a different port is to be used. |
|
| 55 |
+  |
|
| 56 |
+4. Run the Docker binary in the development container, as described in the previous section. |
|
| 57 |
+ Make sure that the port in the `DELVE_PORT` variable corresponds to one, used in the *Go Remote* configuration. |
|
| 58 |
+5. Run the *Go Remote* configuration. |
|
| 59 |
+ The Docker daemon will continue execution inside the container and debugger will stop it on the breakpoints. |
|
| 60 |
+  |
|
| 61 |
+ |
|
| 62 |
+## Where to go next |
|
| 63 |
+ |
|
| 64 |
+Congratulations, you have experienced how to use Delve to debug the Docker daemon |
|
| 65 |
+and how to configure an IDE to make use of it. |
|
| 0 | 66 |
\ No newline at end of file |
| ... | ... |
@@ -250,3 +250,4 @@ jobs can be triggered and re-ran by the Moby maintainers |
| 250 | 250 |
|
| 251 | 251 |
Congratulations, you have successfully completed the basics you need to |
| 252 | 252 |
understand the Moby test framework. |
| 253 |
+In the next section you'll [learn how to debug Docker daemon, running inside the development container](debug.md). |
| ... | ... |
@@ -27,6 +27,11 @@ if [ -n "$DOCKER_PORT" ]; then |
| 27 | 27 |
listen_port="${ports[-1]}"
|
| 28 | 28 |
fi |
| 29 | 29 |
|
| 30 |
+if [ -n "$DELVE_PORT" ]; then |
|
| 31 |
+ IFS=':' read -r -a ports <<< "$DELVE_PORT" |
|
| 32 |
+ delve_listen_port="${ports[-1]}"
|
|
| 33 |
+fi |
|
| 34 |
+ |
|
| 30 | 35 |
extra_params="$DOCKERD_ARGS" |
| 31 | 36 |
if [ "$DOCKER_REMAP_ROOT" ]; then |
| 32 | 37 |
extra_params="$extra_params --userns-remap $DOCKER_REMAP_ROOT" |
| ... | ... |
@@ -36,7 +41,7 @@ if [ -n "$DOCKER_EXPERIMENTAL" ]; then |
| 36 | 36 |
extra_params="$extra_params --experimental" |
| 37 | 37 |
fi |
| 38 | 38 |
|
| 39 |
-dockerd="dockerd" |
|
| 39 |
+dockerd="$(command -v dockerd)" |
|
| 40 | 40 |
socket=/var/run/docker.sock |
| 41 | 41 |
if [ -n "$DOCKER_ROOTLESS" ]; then |
| 42 | 42 |
user="unprivilegeduser" |
| ... | ... |
@@ -44,7 +49,6 @@ if [ -n "$DOCKER_ROOTLESS" ]; then |
| 44 | 44 |
# shellcheck disable=SC2174 |
| 45 | 45 |
mkdir -p -m 700 "/tmp/docker-${uid}"
|
| 46 | 46 |
chown $user "/tmp/docker-${uid}"
|
| 47 |
- dockerd="sudo -u $user -E XDG_RUNTIME_DIR=/tmp/docker-${uid} -E HOME=/home/${user} -- dockerd-rootless.sh"
|
|
| 48 | 47 |
socket=/tmp/docker-${uid}/docker.sock
|
| 49 | 48 |
fi |
| 50 | 49 |
|
| ... | ... |
@@ -55,6 +59,29 @@ args="--debug \ |
| 55 | 55 |
$storage_params \ |
| 56 | 56 |
$extra_params" |
| 57 | 57 |
|
| 58 |
+if [ -n "$DELVE_PORT" ]; then |
|
| 59 |
+ dockerd="dlv --listen=0.0.0.0:$delve_listen_port \ |
|
| 60 |
+ --headless=true \ |
|
| 61 |
+ --log \ |
|
| 62 |
+ --api-version=2 \ |
|
| 63 |
+ --only-same-user=false \ |
|
| 64 |
+ --check-go-version=false \ |
|
| 65 |
+ --accept-multiclient \ |
|
| 66 |
+ exec ${dockerd} --"
|
|
| 67 |
+fi |
|
| 68 |
+ |
|
| 58 | 69 |
echo "${dockerd} ${args}"
|
| 59 |
-# shellcheck disable=SC2086 |
|
| 60 |
-exec "${dockerd}" ${args}
|
|
| 70 |
+ |
|
| 71 |
+if [ -n "$DOCKER_ROOTLESS" ]; then |
|
| 72 |
+ # shellcheck disable=SC2068 |
|
| 73 |
+ # shellcheck disable=SC2086 |
|
| 74 |
+ exec sudo -u $user \ |
|
| 75 |
+ -E DOCKERD="$dockerd" \ |
|
| 76 |
+ -E XDG_RUNTIME_DIR=/tmp/docker-${uid} \
|
|
| 77 |
+ -E XDG_CONFIG_HOME=/home/${user}/.config \
|
|
| 78 |
+ -E HOME=/home/${user} \
|
|
| 79 |
+ -- /go/src/github.com/docker/docker/contrib/dockerd-rootless.sh ${args}
|
|
| 80 |
+else |
|
| 81 |
+ # shellcheck disable=SC2086 |
|
| 82 |
+ exec ${dockerd} ${args}
|
|
| 83 |
+fi |