Added Delve debugger to the development container
| ... | ... |
@@ -148,6 +148,18 @@ RUN --mount=type=cache,sharing=locked,id=moby-cross-true-aptlib,target=/var/lib/ |
| 148 | 148 |
|
| 149 | 149 |
FROM runtime-dev-cross-${CROSS} AS runtime-dev
|
| 150 | 150 |
|
| 151 |
+FROM base AS delve |
|
| 152 |
+# DELVE_VERSION specifies the version of the Delve debugger binary |
|
| 153 |
+# from the https://github.com/go-delve/delve repository. |
|
| 154 |
+# It can be used to run Docker with a possibility of |
|
| 155 |
+# attaching debugger to it. |
|
| 156 |
+# |
|
| 157 |
+ARG DELVE_VERSION=v1.8.1 |
|
| 158 |
+RUN --mount=type=cache,target=/root/.cache/go-build \ |
|
| 159 |
+ --mount=type=cache,target=/go/pkg/mod \ |
|
| 160 |
+ GOBIN=/build/ GO111MODULE=on go install "github.com/go-delve/delve/cmd/dlv@${DELVE_VERSION}" \
|
|
| 161 |
+ && /build/dlv --help |
|
| 162 |
+ |
|
| 151 | 163 |
FROM base AS tomll |
| 152 | 164 |
# GOTOML_VERSION specifies the version of the tomll binary to build and install |
| 153 | 165 |
# from the https://github.com/pelletier/go-toml repository. This binary is used |
| ... | ... |
@@ -308,6 +320,7 @@ RUN pip3 install yamllint==1.26.1 |
| 308 | 308 |
COPY --from=dockercli /build/ /usr/local/cli |
| 309 | 309 |
COPY --from=frozen-images /build/ /docker-frozen-images |
| 310 | 310 |
COPY --from=swagger /build/ /usr/local/bin/ |
| 311 |
+COPY --from=delve /build/ /usr/local/bin/ |
|
| 311 | 312 |
COPY --from=tomll /build/ /usr/local/bin/ |
| 312 | 313 |
COPY --from=gowinres /build/ /usr/local/bin/ |
| 313 | 314 |
COPY --from=tini /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 \ |
| ... | ... |
@@ -115,8 +116,9 @@ DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),) |
| 115 | 115 |
|
| 116 | 116 |
DOCKER_IMAGE := docker-dev |
| 117 | 117 |
DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",) |
| 118 |
+DELVE_PORT_FORWARD := $(if $(DELVE_PORT),-p "$(DELVE_PORT)",) |
|
| 118 | 119 |
|
| 119 |
-DOCKER_FLAGS := $(DOCKER) run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) |
|
| 120 |
+DOCKER_FLAGS := $(DOCKER) run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) $(DELVE_PORT_FORWARD) |
|
| 120 | 121 |
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR)) |
| 121 | 122 |
export BUILD_APT_MIRROR |
| 122 | 123 |
|
| ... | ... |
@@ -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,6 @@ else |
| 128 | 128 |
mount --rbind ${realpath_etc_ssl} /etc/ssl
|
| 129 | 129 |
fi |
| 130 | 130 |
|
| 131 |
- exec dockerd $@ |
|
| 131 |
+ # shellcheck disable=SC2086 |
|
| 132 |
+ exec $dockerd "$@" |
|
| 132 | 133 |
fi |
| 10 | 11 |
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). |
| ... | ... |
@@ -8,6 +8,8 @@ if ! command -v dockerd &> /dev/null; then |
| 8 | 8 |
false |
| 9 | 9 |
fi |
| 10 | 10 |
|
| 11 |
+DOCKER_COMMAND="$(command -v dockerd)" |
|
| 12 |
+ |
|
| 11 | 13 |
DOCKER_GRAPHDRIVER=${DOCKER_GRAPHDRIVER:-vfs}
|
| 12 | 14 |
DOCKER_USERLANDPROXY=${DOCKER_USERLANDPROXY:-true}
|
| 13 | 15 |
|
| ... | ... |
@@ -23,8 +25,11 @@ fi |
| 23 | 23 |
|
| 24 | 24 |
listen_port=2375 |
| 25 | 25 |
if [ -n "$DOCKER_PORT" ]; then |
| 26 |
- IFS=':' read -r -a ports <<< "$DOCKER_PORT" |
|
| 27 |
- listen_port="${ports[-1]}"
|
|
| 26 |
+ listen_port="${DOCKER_PORT##*:}"
|
|
| 27 |
+fi |
|
| 28 |
+ |
|
| 29 |
+if [ -n "$DELVE_PORT" ]; then |
|
| 30 |
+ delve_listen_port="${DELVE_PORT##*:}"
|
|
| 28 | 31 |
fi |
| 29 | 32 |
|
| 30 | 33 |
extra_params="$DOCKERD_ARGS" |
| ... | ... |
@@ -36,7 +41,6 @@ if [ -n "$DOCKER_EXPERIMENTAL" ]; then |
| 36 | 36 |
extra_params="$extra_params --experimental" |
| 37 | 37 |
fi |
| 38 | 38 |
|
| 39 |
-dockerd="dockerd" |
|
| 40 | 39 |
socket=/var/run/docker.sock |
| 41 | 40 |
if [ -n "$DOCKER_ROOTLESS" ]; then |
| 42 | 41 |
user="unprivilegeduser" |
| ... | ... |
@@ -44,17 +48,48 @@ 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 |
|
| 51 |
-args="--debug \ |
|
| 52 |
- --host "tcp://0.0.0.0:${listen_port}" --host "unix://${socket}" \
|
|
| 53 |
- --storage-driver "${DOCKER_GRAPHDRIVER}" \
|
|
| 54 |
- --userland-proxy="${DOCKER_USERLANDPROXY}" \
|
|
| 55 |
- $storage_params \ |
|
| 56 |
- $extra_params" |
|
| 50 |
+# shellcheck disable=SC2206 |
|
| 51 |
+args=( |
|
| 52 |
+ --debug |
|
| 53 |
+ --host="tcp://0.0.0.0:${listen_port}"
|
|
| 54 |
+ --host="unix://${socket}"
|
|
| 55 |
+ --storage-driver="${DOCKER_GRAPHDRIVER}"
|
|
| 56 |
+ --userland-proxy="${DOCKER_USERLANDPROXY}"
|
|
| 57 |
+ $storage_params |
|
| 58 |
+ $extra_params |
|
| 59 |
+) |
|
| 60 |
+ |
|
| 61 |
+dockerd=("$DOCKER_COMMAND")
|
|
| 62 |
+ |
|
| 63 |
+if [ -n "$DELVE_PORT" ]; then |
|
| 64 |
+ dockerd=( |
|
| 65 |
+ dlv |
|
| 66 |
+ --listen="0.0.0.0:$delve_listen_port" |
|
| 67 |
+ --headless=true |
|
| 68 |
+ --log |
|
| 69 |
+ --api-version=2 |
|
| 70 |
+ --only-same-user=false |
|
| 71 |
+ --check-go-version=false |
|
| 72 |
+ --accept-multiclient |
|
| 73 |
+ exec "${dockerd[@]}" --
|
|
| 74 |
+ ) |
|
| 75 |
+fi |
|
| 76 |
+ |
|
| 77 |
+if [ -n "$DOCKER_ROOTLESS" ]; then |
|
| 78 |
+ dockerd=( |
|
| 79 |
+ sudo -u "$user" |
|
| 80 |
+ -E DOCKERD="${dockerd[*]}"
|
|
| 81 |
+ -E XDG_RUNTIME_DIR="/tmp/docker-${uid}"
|
|
| 82 |
+ -E XDG_CONFIG_HOME="/home/${user}/.config"
|
|
| 83 |
+ -E HOME="/home/${user}"
|
|
| 84 |
+ -- |
|
| 85 |
+ dockerd-rootless.sh |
|
| 86 |
+ ) |
|
| 87 |
+fi |
|
| 57 | 88 |
|
| 58 |
-echo "${dockerd} ${args}"
|
|
| 89 |
+set -x |
|
| 59 | 90 |
# shellcheck disable=SC2086 |
| 60 |
-exec "${dockerd}" ${args}
|
|
| 91 |
+exec "${dockerd[@]}" "${args[@]}"
|