mirror of
https://github.com/juanfont/headscale.git
synced 2025-07-29 12:05:01 +00:00
integration: run headscale with delve and debug symbols (#2689)
This commit is contained in:
parent
e7fe645be5
commit
9779adc0b7
@ -13,14 +13,18 @@ RUN apt-get update \
|
|||||||
&& apt-get clean
|
&& apt-get clean
|
||||||
RUN mkdir -p /var/run/headscale
|
RUN mkdir -p /var/run/headscale
|
||||||
|
|
||||||
|
# Install delve debugger
|
||||||
|
RUN go install github.com/go-delve/delve/cmd/dlv@latest
|
||||||
|
|
||||||
COPY go.mod go.sum /go/src/headscale/
|
COPY go.mod go.sum /go/src/headscale/
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go install -a ./cmd/headscale && test -e /go/bin/headscale
|
# Build debug binary with debug symbols for delve
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o /go/bin/headscale ./cmd/headscale
|
||||||
|
|
||||||
# Need to reset the entrypoint or everything will run as a busybox script
|
# Need to reset the entrypoint or everything will run as a busybox script
|
||||||
ENTRYPOINT []
|
ENTRYPOINT []
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp 40000/tcp
|
||||||
CMD ["headscale"]
|
CMD ["/go/bin/dlv", "--listen=0.0.0.0:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/go/bin/headscale", "--"]
|
||||||
|
@ -31,6 +31,7 @@ func DefaultConfigEnv() map[string]string {
|
|||||||
"HEADSCALE_DERP_URLS": "https://controlplane.tailscale.com/derpmap/default",
|
"HEADSCALE_DERP_URLS": "https://controlplane.tailscale.com/derpmap/default",
|
||||||
"HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false",
|
"HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false",
|
||||||
"HEADSCALE_DERP_UPDATE_FREQUENCY": "1m",
|
"HEADSCALE_DERP_UPDATE_FREQUENCY": "1m",
|
||||||
|
"HEADSCALE_DEBUG_PORT": "40000",
|
||||||
|
|
||||||
// a bunch of tests (ACL/Policy) rely on predictable IP alloc,
|
// a bunch of tests (ACL/Policy) rely on predictable IP alloc,
|
||||||
// so ensure the sequential alloc is used by default.
|
// so ensure the sequential alloc is used by default.
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/ory/dockertest/v3"
|
"github.com/ory/dockertest/v3"
|
||||||
"github.com/ory/dockertest/v3/docker"
|
"github.com/ory/dockertest/v3/docker"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"tailscale.com/envknob"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/util/mak"
|
"tailscale.com/util/mak"
|
||||||
)
|
)
|
||||||
@ -66,6 +67,7 @@ type HeadscaleInContainer struct {
|
|||||||
// optional config
|
// optional config
|
||||||
port int
|
port int
|
||||||
extraPorts []string
|
extraPorts []string
|
||||||
|
debugPort int
|
||||||
caCerts [][]byte
|
caCerts [][]byte
|
||||||
hostPortBindings map[string][]string
|
hostPortBindings map[string][]string
|
||||||
aclPolicy *policyv2.Policy
|
aclPolicy *policyv2.Policy
|
||||||
@ -268,6 +270,22 @@ func WithTimezone(timezone string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithDebugPort sets the debug port for delve debugging.
|
||||||
|
func WithDebugPort(port int) Option {
|
||||||
|
return func(hsic *HeadscaleInContainer) {
|
||||||
|
hsic.debugPort = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildEntrypoint builds the container entrypoint command based on configuration.
|
||||||
|
func (hsic *HeadscaleInContainer) buildEntrypoint() []string {
|
||||||
|
debugCmd := fmt.Sprintf("/go/bin/dlv --listen=0.0.0.0:%d --headless=true --api-version=2 --accept-multiclient --allow-non-terminal-interactive=true exec /go/bin/headscale --continue -- serve", hsic.debugPort)
|
||||||
|
|
||||||
|
entrypoint := fmt.Sprintf("/bin/sleep 3 ; update-ca-certificates ; %s ; /bin/sleep 30", debugCmd)
|
||||||
|
|
||||||
|
return []string{"/bin/bash", "-c", entrypoint}
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new HeadscaleInContainer instance.
|
// New returns a new HeadscaleInContainer instance.
|
||||||
func New(
|
func New(
|
||||||
pool *dockertest.Pool,
|
pool *dockertest.Pool,
|
||||||
@ -281,9 +299,18 @@ func New(
|
|||||||
|
|
||||||
hostname := "hs-" + hash
|
hostname := "hs-" + hash
|
||||||
|
|
||||||
|
// Get debug port from environment or use default
|
||||||
|
debugPort := 40000
|
||||||
|
if envDebugPort := envknob.String("HEADSCALE_DEBUG_PORT"); envDebugPort != "" {
|
||||||
|
if port, err := strconv.Atoi(envDebugPort); err == nil {
|
||||||
|
debugPort = port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hsic := &HeadscaleInContainer{
|
hsic := &HeadscaleInContainer{
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
port: headscaleDefaultPort,
|
port: headscaleDefaultPort,
|
||||||
|
debugPort: debugPort,
|
||||||
|
|
||||||
pool: pool,
|
pool: pool,
|
||||||
networks: networks,
|
networks: networks,
|
||||||
@ -300,6 +327,7 @@ func New(
|
|||||||
log.Println("NAME: ", hsic.hostname)
|
log.Println("NAME: ", hsic.hostname)
|
||||||
|
|
||||||
portProto := fmt.Sprintf("%d/tcp", hsic.port)
|
portProto := fmt.Sprintf("%d/tcp", hsic.port)
|
||||||
|
debugPortProto := fmt.Sprintf("%d/tcp", hsic.debugPort)
|
||||||
|
|
||||||
headscaleBuildOptions := &dockertest.BuildOptions{
|
headscaleBuildOptions := &dockertest.BuildOptions{
|
||||||
Dockerfile: IntegrationTestDockerFileName,
|
Dockerfile: IntegrationTestDockerFileName,
|
||||||
@ -364,17 +392,27 @@ func New(
|
|||||||
|
|
||||||
runOptions := &dockertest.RunOptions{
|
runOptions := &dockertest.RunOptions{
|
||||||
Name: hsic.hostname,
|
Name: hsic.hostname,
|
||||||
ExposedPorts: append([]string{portProto, "9090/tcp"}, hsic.extraPorts...),
|
ExposedPorts: append([]string{portProto, debugPortProto, "9090/tcp"}, hsic.extraPorts...),
|
||||||
Networks: networks,
|
Networks: networks,
|
||||||
// Cmd: []string{"headscale", "serve"},
|
// Cmd: []string{"headscale", "serve"},
|
||||||
// TODO(kradalby): Get rid of this hack, we currently need to give us some
|
// TODO(kradalby): Get rid of this hack, we currently need to give us some
|
||||||
// to inject the headscale configuration further down.
|
// to inject the headscale configuration further down.
|
||||||
Entrypoint: []string{"/bin/bash", "-c", "/bin/sleep 3 ; update-ca-certificates ; headscale serve ; /bin/sleep 30"},
|
Entrypoint: hsic.buildEntrypoint(),
|
||||||
Env: env,
|
Env: env,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hsic.hostPortBindings) > 0 {
|
// Always bind debug port and metrics port to predictable host ports
|
||||||
|
if runOptions.PortBindings == nil {
|
||||||
runOptions.PortBindings = map[docker.Port][]docker.PortBinding{}
|
runOptions.PortBindings = map[docker.Port][]docker.PortBinding{}
|
||||||
|
}
|
||||||
|
runOptions.PortBindings[docker.Port(debugPortProto)] = []docker.PortBinding{
|
||||||
|
{HostPort: strconv.Itoa(hsic.debugPort)},
|
||||||
|
}
|
||||||
|
runOptions.PortBindings["9090/tcp"] = []docker.PortBinding{
|
||||||
|
{HostPort: "49090"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hsic.hostPortBindings) > 0 {
|
||||||
for port, hostPorts := range hsic.hostPortBindings {
|
for port, hostPorts := range hsic.hostPortBindings {
|
||||||
runOptions.PortBindings[docker.Port(port)] = []docker.PortBinding{}
|
runOptions.PortBindings[docker.Port(port)] = []docker.PortBinding{}
|
||||||
for _, hostPort := range hostPorts {
|
for _, hostPort := range hostPorts {
|
||||||
@ -410,6 +448,8 @@ func New(
|
|||||||
|
|
||||||
hsic.container = container
|
hsic.container = container
|
||||||
|
|
||||||
|
log.Printf("Debug ports for %s: delve=%s, metrics/pprof=49090\n", hsic.hostname, hsic.GetHostDebugPort())
|
||||||
|
|
||||||
// Write the CA certificates to the container
|
// Write the CA certificates to the container
|
||||||
for i, cert := range hsic.caCerts {
|
for i, cert := range hsic.caCerts {
|
||||||
err = hsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert)
|
err = hsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert)
|
||||||
@ -759,6 +799,16 @@ func (t *HeadscaleInContainer) GetPort() string {
|
|||||||
return strconv.Itoa(t.port)
|
return strconv.Itoa(t.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebugPort returns the debug port as a string.
|
||||||
|
func (t *HeadscaleInContainer) GetDebugPort() string {
|
||||||
|
return strconv.Itoa(t.debugPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHostDebugPort returns the host port mapped to the debug port.
|
||||||
|
func (t *HeadscaleInContainer) GetHostDebugPort() string {
|
||||||
|
return strconv.Itoa(t.debugPort)
|
||||||
|
}
|
||||||
|
|
||||||
// GetHealthEndpoint returns a health endpoint for the HeadscaleInContainer
|
// GetHealthEndpoint returns a health endpoint for the HeadscaleInContainer
|
||||||
// instance.
|
// instance.
|
||||||
func (t *HeadscaleInContainer) GetHealthEndpoint() string {
|
func (t *HeadscaleInContainer) GetHealthEndpoint() string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user