Skip to content

Commit 773a413

Browse files
committed
Support interactive debugging of Dockerfile
Signed-off-by: Kohei Tokunaga <[email protected]>
1 parent 70bcdd0 commit 773a413

File tree

7 files changed

+231
-1
lines changed

7 files changed

+231
-1
lines changed

Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ ARG CONTAINERD_FUSE_OVERLAYFS_VERSION=v1.0.4
4040
ARG IPFS_VERSION=v0.12.2
4141
# Extra deps: Init
4242
ARG TINI_VERSION=v0.19.0
43+
# Extra deps: Debug
44+
ARG BUILDG_VERSION=v0.0.3
4345

4446
# Test deps
4547
ARG GO_VERSION=1.18
@@ -203,6 +205,13 @@ RUN fname="tini-static-${TARGETARCH:-amd64}" && \
203205
grep "${fname}" "/SHA256SUMS.d/tini-${TINI_VERSION}" | sha256sum -c && \
204206
cp -a "${fname}" /out/bin/tini && chmod +x /out/bin/tini && \
205207
echo "- Tini: ${TINI_VERSION}" >> /out/share/doc/nerdctl-full/README.md
208+
ARG BUILDG_VERSION
209+
RUN fname="buildg-${BUILDG_VERSION}-${TARGETOS:-linux}-${TARGETARCH:-amd64}.tar.gz" && \
210+
curl -o "${fname}" -fSL "https://github.com/ktock/buildg/releases/download/${BUILDG_VERSION}/${fname}" && \
211+
grep "${fname}" "/SHA256SUMS.d/buildg-${BUILDG_VERSION}" | sha256sum -c && \
212+
tar xzf "${fname}" -C /out/bin && \
213+
rm -f "${fname}" && \
214+
echo "- buildg: ${BUILDG_VERSION}" >> /out/share/doc/nerdctl-full/README.md
206215

207216
RUN echo "" >> /out/share/doc/nerdctl-full/README.md && \
208217
echo "## License" >> /out/share/doc/nerdctl-full/README.md && \
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
3181c6e98cdd913fd24117288dfac5cea3a50232db7775a99a45f379f9a5e9e6 buildg-v0.0.3-linux-amd64.tar.gz
2+
650fbcfa761c353a8dd45f0f4506d2bc462f18cbafb9694e0f537d36ce1bddde buildg-v0.0.3-linux-arm64.tar.gz

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ It does not necessarily mean that the corresponding features are missing in cont
310310
- [:nerd_face: nerdctl apparmor unload](#nerd_face-nerdctl-apparmor-unload)
311311
- [Builder management](#builder-management)
312312
- [:whale: nerdctl builder prune](#whale-nerdctl-builder-prune)
313+
- [:nerd_face: nerdctl builder debug](#nerd_face-nerdctl-builder-debug)
313314
- [System](#system)
314315
- [:whale: nerdctl events](#whale-nerdctl-events)
315316
- [:whale: nerdctl info](#whale-nerdctl-info)
@@ -1207,6 +1208,21 @@ Usage: `nerdctl builder prune`
12071208
Flags:
12081209
- :nerd_face: `--buildkit-host=<BUILDKIT_HOST>`: BuildKit address
12091210

1211+
### :nerd_face: nerdctl builder debug
1212+
Interactive debugging of Dockerfile using [buildg](https://github.com/ktock/buildg).
1213+
Please refer to [`./docs/builder-debug.md`](./docs/builder-debug.md) for details.
1214+
This is an [experimental](./docs/experimental.md) feature.
1215+
1216+
:warning: This command currently doesn't use the host's `buildkitd` daemon but uses the patched version of BuildKit provided by buildg. This should be fixed in the future.
1217+
1218+
Usage: `nerdctl builder debug PATH`
1219+
1220+
Flags:
1221+
- :nerd_face: `-f`, `--file`: Name of the Dockerfile
1222+
- :nerd_face: `--image`: Image to use for debugging stage
1223+
- :nerd_face: `--target`: Set the target build stage to build
1224+
- :nerd_face: `--build-arg`: Set build-time variables
1225+
12101226
Unimplemented `docker builder prune` flags: `--all`, `--filter`, `--force`, `--keep-storage`
12111227

12121228
## System
@@ -1510,6 +1526,7 @@ Experimental features:
15101526
- [`./docs/experimental.md`](./docs/experimental.md): Experimental features
15111527
- [`./docs/freebsd.md`](./docs/freebsd.md): Running FreeBSD jails
15121528
- [`./docs/ipfs.md`](./docs/ipfs.md): Distributing images on IPFS
1529+
- [`./docs/builder-debug.md`](./docs/builder-debug.md): Interactive debugging of Dockerfile
15131530

15141531
Implementation details:
15151532
- [`./docs/dir.md`](./docs/dir.md): Directory layout (`/var/lib/nerdctl`)

cmd/nerdctl/builder.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package main
1818

1919
import (
20+
"fmt"
2021
"os"
2122
"os/exec"
2223

@@ -37,6 +38,7 @@ func newBuilderCommand() *cobra.Command {
3738
}
3839
builderCommand.AddCommand(
3940
newBuilderPruneCommand(),
41+
newBuilderDebugCommand(),
4042
)
4143
return builderCommand
4244
}
@@ -73,3 +75,74 @@ func builderPruneAction(cmd *cobra.Command, args []string) error {
7375
buildctlCmd.Stdout = cmd.OutOrStdout()
7476
return buildctlCmd.Run()
7577
}
78+
79+
func newBuilderDebugCommand() *cobra.Command {
80+
shortHelp := `Debug Dockerfile`
81+
var buildDebugCommand = &cobra.Command{
82+
Use: "debug",
83+
Short: shortHelp,
84+
RunE: builderDebugAction,
85+
SilenceUsage: true,
86+
SilenceErrors: true,
87+
}
88+
buildDebugCommand.Flags().StringP("file", "f", "", "Name of the Dockerfile")
89+
buildDebugCommand.Flags().String("target", "", "Set the target build stage to build")
90+
buildDebugCommand.Flags().StringArray("build-arg", nil, "Set build-time variables")
91+
buildDebugCommand.Flags().String("image", "", "Image to use for debugging stage")
92+
return buildDebugCommand
93+
}
94+
95+
func builderDebugAction(cmd *cobra.Command, args []string) error {
96+
if len(args) < 1 {
97+
return fmt.Errorf("context needs to be specified")
98+
}
99+
100+
buildgBinary, err := exec.LookPath("buildg")
101+
if err != nil {
102+
return err
103+
}
104+
buildgArgs := []string{"debug"}
105+
debugLog, err := cmd.Flags().GetBool("debug")
106+
if err != nil {
107+
return err
108+
} else if debugLog {
109+
buildgArgs = append([]string{"--debug"}, buildgArgs...)
110+
}
111+
112+
if file, err := cmd.Flags().GetString("file"); err != nil {
113+
return err
114+
} else if file != "" {
115+
buildgArgs = append(buildgArgs, "--file="+file)
116+
}
117+
118+
if target, err := cmd.Flags().GetString("target"); err != nil {
119+
return err
120+
} else if target != "" {
121+
buildgArgs = append(buildgArgs, "--target="+target)
122+
}
123+
124+
if buildArgsValue, err := cmd.Flags().GetStringArray("build-arg"); err != nil {
125+
return err
126+
} else if len(buildArgsValue) > 0 {
127+
for _, v := range buildArgsValue {
128+
buildgArgs = append(buildgArgs, "--build-arg="+v)
129+
}
130+
}
131+
132+
if imageValue, err := cmd.Flags().GetString("image"); err != nil {
133+
return err
134+
} else if imageValue != "" {
135+
buildgArgs = append(buildgArgs, "--image="+imageValue)
136+
}
137+
138+
buildgCmd := exec.Command(buildgBinary, append(buildgArgs, args[0])...)
139+
buildgCmd.Env = os.Environ()
140+
buildgCmd.Stdin = cmd.InOrStdin()
141+
buildgCmd.Stdout = cmd.OutOrStdout()
142+
buildgCmd.Stderr = cmd.ErrOrStderr()
143+
if err := buildgCmd.Start(); err != nil {
144+
return err
145+
}
146+
147+
return buildgCmd.Wait()
148+
}

cmd/nerdctl/builder_linux_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"fmt"
21+
"os"
22+
"testing"
23+
24+
"github.com/containerd/nerdctl/pkg/testutil"
25+
"gotest.tools/v3/assert"
26+
)
27+
28+
func TestBuilderDebug(t *testing.T) {
29+
testutil.DockerIncompatible(t)
30+
base := testutil.NewBase(t)
31+
32+
dockerfile := fmt.Sprintf(`FROM %s
33+
CMD ["echo", "nerdctl-builder-debug-test-string"]
34+
`, testutil.CommonImage)
35+
36+
buildCtx, err := createBuildContext(dockerfile)
37+
assert.NilError(t, err)
38+
defer os.RemoveAll(buildCtx)
39+
40+
base.Cmd("builder", "debug", buildCtx).AssertOK()
41+
}

docs/builder-debug.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Interactive debugging of Dockerfile (Experimental)
2+
3+
nerdctl supports interactive debugging of Dockerfile as `nerdctl builder debug`.
4+
5+
```
6+
$ nerdctl builder debug /path/to/context
7+
```
8+
9+
This feature leverages [buildg](https://github.com/ktock/buildg), interactive debugger of Dockerfile.
10+
For command reference, please refer to the [Command reference doc in buildg repo](https://github.com/ktock/buildg#command-reference).
11+
12+
:warning: This command currently doesn't use the host's `buildkitd` daemon but uses the patched version of BuildKit provided by buildg. This should be fixed to use the host's `buildkitd` in the future.
13+
14+
## Example
15+
16+
Example Dockerfile:
17+
18+
```Dockerfile
19+
FROM busybox AS build1
20+
RUN echo a > /a
21+
RUN echo b > /b
22+
RUN echo c > /c
23+
```
24+
25+
Example debugging:
26+
27+
```console
28+
$ nerdctl builder debug --image=ubuntu:22.04 /tmp/ctx/
29+
WARN[2022-05-10T12:49:43Z] using host network as the default
30+
#1 [internal] load .dockerignore
31+
#1 transferring context: 2B done
32+
#1 DONE 0.1s
33+
34+
#2 [internal] load build definition from Dockerfile
35+
#2 transferring dockerfile: 108B done
36+
#2 DONE 0.1s
37+
38+
#3 [internal] load metadata for docker.io/library/busybox:latest
39+
#3 DONE 3.0s
40+
41+
#4 [1/4] FROM docker.io/library/busybox@sha256:d2b53584f580310186df7a2055ce3ff83cc0df6caacf1e3489bff8cf5d0af5d8
42+
#4 resolve docker.io/library/busybox@sha256:d2b53584f580310186df7a2055ce3ff83cc0df6caacf1e3489bff8cf5d0af5d8 0.0s done
43+
#4 sha256:50e8d59317eb665383b2ef4d9434aeaa394dcd6f54b96bb7810fdde583e9c2d1 0B / 772.81kB 0.2s
44+
Filename: "Dockerfile"
45+
1| FROM busybox AS build1
46+
=> 2| RUN echo a > /a
47+
3| RUN echo b > /b
48+
4| RUN echo c > /c
49+
>>> break 3
50+
>>> breakpoints
51+
[0]: line: Dockerfile:3
52+
[on-fail]: breaks on fail
53+
>>> continue
54+
#4 sha256:50e8d59317eb665383b2ef4d9434aeaa394dcd6f54b96bb7810fdde583e9c2d1 772.81kB / 772.81kB 0.3s done
55+
#4 extracting sha256:50e8d59317eb665383b2ef4d9434aeaa394dcd6f54b96bb7810fdde583e9c2d1 0.0s done
56+
#4 DONE 0.4s
57+
58+
#5 [2/4] RUN echo a > /a
59+
#5 DONE 15.1s
60+
Breakpoint: line: Dockerfile:3: reached
61+
Filename: "Dockerfile"
62+
1| FROM busybox AS build1
63+
2| RUN echo a > /a
64+
*=> 3| RUN echo b > /b
65+
4| RUN echo c > /c
66+
>>> exec --image sh
67+
# cat /etc/os-release
68+
PRETTY_NAME="Ubuntu 22.04 LTS"
69+
NAME="Ubuntu"
70+
VERSION_ID="22.04"
71+
VERSION="22.04 LTS (Jammy Jellyfish)"
72+
VERSION_CODENAME=jammy
73+
ID=ubuntu
74+
ID_LIKE=debian
75+
HOME_URL="https://www.ubuntu.com/"
76+
SUPPORT_URL="https://help.ubuntu.com/"
77+
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
78+
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
79+
UBUNTU_CODENAME=jammy
80+
# ls /debugroot/
81+
a b bin dev etc home proc root tmp usr var
82+
# cat /debugroot/a /debugroot/b
83+
a
84+
b
85+
#
86+
>>> quit
87+
```

docs/experimental.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ The following features are experimental and subject to change:
88
eStargz itself is out of experimental.
99
- [Image Distribution on IPFS](./ipfs.md)
1010
- [Image Sign and Verify (cosign)](./cosign.md)
11-
- [Rootless container networking acceleration with bypass4netns](./rootless.md#bypass4netns)
11+
- [Rootless container networking acceleration with bypass4netns](./rootless.md#bypass4netns)
12+
- [Interactive debugging of Dockerfile](./builder-debug.md)

0 commit comments

Comments
 (0)