Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/features/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ docker run -p 40000:40000 <img>
```

This sets up your app to be waiting to run the command you've specified. All that's needed now is to connect your debugger client to the running container!

By default, the application will not start until a debugger has connected and issued the `continue` command. This is required in order to be able to set breakpoints for code that is executed during start-up. If you want the application to start running without waiting for a debugger, use the `--debug-continue` parameter:

```plaintext
ko build . --debug --debug-continue
```
1 change: 1 addition & 0 deletions docs/reference/ko_apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ko apply -f FILENAME [flags]
--bare Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).
-B, --base-import-paths Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).
--debug Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.
--debug-continue Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.
--disable-optimizations Disable optimizations when building Go code. Useful when you want to interactively debug the created container.
-f, --filename strings Filename, directory, or URL to files to use to create the resource
-h, --help help for apply
Expand Down
1 change: 1 addition & 0 deletions docs/reference/ko_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ko build IMPORTPATH... [flags]
--bare Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).
-B, --base-import-paths Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).
--debug Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.
--debug-continue Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.
--disable-optimizations Disable optimizations when building Go code. Useful when you want to interactively debug the created container.
-h, --help help for build
--image-annotation strings Which annotations (key=value[,key=value]) to add to the OCI manifest.
Expand Down
1 change: 1 addition & 0 deletions docs/reference/ko_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ko create -f FILENAME [flags]
--bare Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).
-B, --base-import-paths Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).
--debug Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.
--debug-continue Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.
--disable-optimizations Disable optimizations when building Go code. Useful when you want to interactively debug the created container.
-f, --filename strings Filename, directory, or URL to files to use to create the resource
-h, --help help for create
Expand Down
1 change: 1 addition & 0 deletions docs/reference/ko_resolve.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ko resolve -f FILENAME [flags]
--bare Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).
-B, --base-import-paths Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).
--debug Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.
--debug-continue Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.
--disable-optimizations Disable optimizations when building Go code. Useful when you want to interactively debug the created container.
-f, --filename strings Filename, directory, or URL to files to use to create the resource
-h, --help help for resolve
Expand Down
1 change: 1 addition & 0 deletions docs/reference/ko_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ko run IMPORTPATH [flags]
--bare Whether to just use KO_DOCKER_REPO without additional context (may not work properly with --tags).
-B, --base-import-paths Whether to use the base path without MD5 hash after KO_DOCKER_REPO (may not work properly with --tags).
--debug Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.
--debug-continue Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.
--disable-optimizations Disable optimizations when building Go code. Useful when you want to interactively debug the created container.
-h, --help help for run
--image-annotation strings Which annotations (key=value[,key=value]) to add to the OCI manifest.
Expand Down
4 changes: 4 additions & 0 deletions pkg/build/gobuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ type gobuild struct {
annotations map[string]string
user string
debug bool
debugContinue bool
semaphore *semaphore.Weighted

cache *layerCache
Expand Down Expand Up @@ -134,6 +135,7 @@ type gobuildOpener struct {
dir string
jobs int
debug bool
debugContinue bool
}

func (gbo *gobuildOpener) Open() (Interface, error) {
Expand Down Expand Up @@ -169,6 +171,7 @@ func (gbo *gobuildOpener) Open() (Interface, error) {
annotations: gbo.annotations,
dir: gbo.dir,
debug: gbo.debug,
debugContinue: gbo.debugContinue,
platformMatcher: matcher,
cache: &layerCache{
buildToDiff: map[string]buildIDToDiffID{},
Expand Down Expand Up @@ -1129,6 +1132,7 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
"--log",
"--accept-multiclient",
"--api-version=2",
fmt.Sprintf("--continue=%t", g.debugContinue),
"--",
}

Expand Down
118 changes: 77 additions & 41 deletions pkg/build/gobuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1498,52 +1498,88 @@ func TestDebugger(t *testing.T) {
}
importpath := "github.com/google/ko"

ng, err := NewGo(
context.Background(),
"",
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
WithPlatforms("linux/amd64"),
WithDebugger(),
)
if err != nil {
t.Fatalf("NewGo() = %v", err)
tests := []struct {
desc string
opts []Option
wantEntrypoint []string
}{
{
desc: "debugger enabled",
opts: []Option{
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
WithPlatforms("linux/amd64"),
WithDebugger(),
},
wantEntrypoint: []string{
"/ko-app/dlv",
"exec",
"--listen=:40000",
"--headless",
"--log",
"--accept-multiclient",
"--api-version=2",
"--continue=false",
"--",
"/ko-app/ko",
},
},
{
desc: "debugger enabled with continue",
opts: []Option{
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
WithPlatforms("linux/amd64"),
WithDebugger(),
WithDebuggerContinue(),
},
wantEntrypoint: []string{
"/ko-app/dlv",
"exec",
"--listen=:40000",
"--headless",
"--log",
"--accept-multiclient",
"--api-version=2",
"--continue=true",
"--",
"/ko-app/ko",
},
},
}

result, err := ng.Build(context.Background(), StrictScheme+importpath)
if err != nil {
t.Fatalf("Build() = %v", err)
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
ng, err := NewGo(context.Background(), "", tc.opts...)
if err != nil {
t.Fatalf("NewGo() = %v", err)
}

img, ok := result.(v1.Image)
if !ok {
t.Fatalf("Build() not an Image: %T", result)
}
result, err := ng.Build(context.Background(), StrictScheme+importpath)
if err != nil {
t.Fatalf("Build() = %v", err)
}

// Check that the entrypoint of the image is not overwritten
cfg, err := img.ConfigFile()
if err != nil {
t.Errorf("ConfigFile() = %v", err)
}
gotEntrypoint := cfg.Config.Entrypoint
wantEntrypoint := []string{
"/ko-app/dlv",
"exec",
"--listen=:40000",
"--headless",
"--log",
"--accept-multiclient",
"--api-version=2",
"--",
"/ko-app/ko",
}
img, ok := result.(v1.Image)
if !ok {
t.Fatalf("Build() not an Image: %T", result)
}

if got, want := len(gotEntrypoint), len(wantEntrypoint); got != want {
t.Fatalf("len(entrypoint) = %v, want %v", got, want)
}
// Check that the entrypoint of the image is not overwritten
cfg, err := img.ConfigFile()
if err != nil {
t.Errorf("ConfigFile() = %v", err)
}
gotEntrypoint := cfg.Config.Entrypoint
wantEntrypoint := tc.wantEntrypoint

for i := range wantEntrypoint {
if got, want := gotEntrypoint[i], wantEntrypoint[i]; got != want {
t.Errorf("entrypoint[%d] = %v, want %v", i, got, want)
}
if got, want := len(gotEntrypoint), len(wantEntrypoint); got != want {
t.Fatalf("len(entrypoint) = %v, want %v", got, want)
}

for i := range wantEntrypoint {
if got, want := gotEntrypoint[i], wantEntrypoint[i]; got != want {
t.Errorf("entrypoint[%d] = %v, want %v", i, got, want)
}
}
})
}
}
7 changes: 7 additions & 0 deletions pkg/build/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,10 @@ func WithDebugger() Option {
return nil
}
}

func WithDebuggerContinue() Option {
return func(gbo *gobuildOpener) error {
gbo.debugContinue = true
return nil
}
}
3 changes: 3 additions & 0 deletions pkg/commands/options/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type BuildOptions struct {
Annotations []string
User string
Debug bool
DebugContinue bool
// UserAgent enables overriding the default value of the `User-Agent` HTTP
// request header used when retrieving the base image.
UserAgent string
Expand Down Expand Up @@ -103,6 +104,8 @@ func AddBuildOptions(cmd *cobra.Command, bo *BuildOptions) {
"The default user the image should be run as.")
cmd.Flags().BoolVar(&bo.Debug, "debug", bo.Debug,
"Include Delve debugger into image and wrap around ko-app. This debugger will listen to port 40000.")
cmd.Flags().BoolVar(&bo.DebugContinue, "debug-continue", bo.DebugContinue,
"Continue the debugged process on start. Useful when you don't want to require a debugger to attach for the application to start.")
bo.Trimpath = true
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/commands/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func gobuildOptions(bo *options.BuildOptions) ([]build.Option, error) {
if bo.Debug {
opts = append(opts, build.WithDebugger())
opts = append(opts, build.WithDisabledOptimizations()) // also needed for Delve

if bo.DebugContinue {
opts = append(opts, build.WithDebuggerContinue())
}
}
switch bo.SBOM {
case "none":
Expand Down