Skip to content

Proposal: build debugging in buildx (interactive sessions) #1104

Open
@tonistiigi

Description

@tonistiigi

This is a follow-up to BuildKit debugging issue moby/buildkit#1472 so we can discuss the UX and next steps for features like moby/buildkit#2813 . moby/buildkit#1472 is mostly implemented in BuildKit v0.9 with additional signaling patches in v0.10 so unless we missed something no more (breaking) BuildKit changes should be needed.

All of this work does not need to end up in buildx repository, and some may be moved out later. I don't want opinionated dev features in buildctl that should be vendor-agnostic test tool, and I also don't want to maintain two similar, but different debugging stacks. Aside of that, code reuse is encouraged.

BuildKit issue concentrated on internal building blocks for this feature and you should read it first. In here, I'm proposing steps for incremental PRs to end up with a user-friendly debugging feature.

All flag names up to later discussion. Naming is hard.

PRs may be combined where it makes sense for review, but all the described steps should be quite independent.

PR1

Add possibility to interactively run a process using the NewContainer API after the build has completed.

docker buildx build --invoke bash .
docker buildx build --invoke entrypoint=/usr/bin/cat,args=/etc/passwd,env=FOO=bar . # optional longform (not a requirement)

The build will run with the progressbar until completion. Progressbar will finish and container will be launched. Container redirects all stdio and signals. TTY is enabled if user enabled TTY for main process.

PR2

Add "monitor mode" to the interactive process. When running an interactive process, the user can switch between to process io and monitor process io. Similar to QEMU monitor mode. In monitor mode they can issue additional commands.

In the very first PR only supported command may be "exit".

(buildx) exit

PR3

Add "rollback" command to monitor mode. With this command the user can make modifications in the interactive container and when they issue "rollback" command they are brought back to the initial state.

Add "reload" command to monitor mode. This will run the build again(now with possibly updated source) and invoke the shell again.

PR4

Refactor build command to invoke builds in a background process. This is important as we don't want the lifecycle of "debugging session" to be locked into a single process. A socket should be created under ~/.buildx and even if the current process (unexpectedly) dies its state can be accessed again via the socket.

PR5

Add list and attach commands to the monitor mode. List would show all the current active sessions (via the socket described in the previous section). Attach would make that session active in current process. If the session is already active in another process these processes would detach and go to the monitor mode.

PR6

Add exec command to execute new processes in the same debug container. All processes are attachable as described in the previous section.

PR7

docker buildx build --invoke=debug-shell should go directly to monitor mode where processes can be created with exec. We can also have docker buildx debug-shell to start monitor mode without a specific container context.

PR8

Add docker buildx build --invoke=on-error. In this mode, if build ends with an error debug shell will be opened from the error location. The error returned by buildkit is typed and contains the references to the state of the error and state in the beginning of the failed step. Monitor commands allow to switch in-between of these states. Error also includes source map that can be shown to the user.

Next:

In the next steps we can write more specific proposals for:

Breakpoint debugger

There are two ways to approach this. As the builder is lazy we can call Solve that will return a result without actually evaluating it. This result can be converted to DefinitionOp which contains the source locations. Now this DefinitionOp can be mutated to build up the the breakpoint and then evaluated and run interactively. I think this is similar to wrapper in buildg without requiring buildkit update or proxy. The problem with this one is the cases when frontend does multiple Solve calls (maybe in parallel). This would start to conflict with the debugger logic. Therefore I think a better approach could be to define this as frontend capability and send breakpoint info with build opts to the frontend. If frontend allows debugging it would stop on the breakpoint and return the result that the debugger will then show.

Monitor mode

Add more functions to monitor mode. Eg. commands to inspect file layouts, transfer files. Keep shell history between invocations.

Buildx bake

Enable interactive sessions in buildx bake. Eg. docker buildx bake dev could build all the images part of the project, run them, and put the user into a dev container. Inside the dev container they can switch between active processes etc.

@ktock @crazy-max

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions