From cde5155e35aa5d56aeaec3b313be23dc99fa6386 Mon Sep 17 00:00:00 2001 From: MikelAlejoBR Date: Tue, 23 Dec 2025 09:43:06 -0500 Subject: [PATCH] feature: Makefile targets to build the operator in debug mode In order to be able to debug the operator live in the local cluster, we need the binary to be executed with Delve instead, and we need it to be built without any code optimizations or minimization so that the breakpoints work. For that purpose, new Dockerfiles are added which can build the images that way, and the corresponding Make targets make it easy to kick off the whole process with a single command. The Makefile targets also enable the "toolchain-e2e" repository to easily build the "debug" images. SANDBOX-1561 --- build/Dockerfile.debug | 53 ++++++++++++++++++++++++++++++++++ build/Dockerfile.webhook.debug | 53 ++++++++++++++++++++++++++++++++++ build/bin/entrypoint | 7 ++++- make/go.mk | 19 ++++++++++++ make/podman.mk | 12 ++++++++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 build/Dockerfile.debug create mode 100644 build/Dockerfile.webhook.debug diff --git a/build/Dockerfile.debug b/build/Dockerfile.debug new file mode 100644 index 000000000..56abab4b0 --- /dev/null +++ b/build/Dockerfile.debug @@ -0,0 +1,53 @@ +# Compile Delve in an intermediate step. +FROM registry.access.redhat.com/ubi8/ubi:latest AS delve-builder + +# The Golang version must be provided as a build arguments, which will ensure +# that Delve gets built with the same version the operator's binary gets built +# with, to avoid any discrepancies. +ARG GOLANG_VERSION + +# Install Tar to be able to extract Golang. +RUN yum install --assumeyes \ + tar \ + && yum clean all + +# Download and extract Golang. +RUN curl --location --output "${GOLANG_VERSION}.linux-amd64.tar.gz" "https://go.dev/dl/${GOLANG_VERSION}.linux-amd64.tar.gz" \ + && tar --directory /usr/local --extract --file "${GOLANG_VERSION}.linux-amd64.tar.gz" \ + && rm --force "${GOLANG_VERSION}.linux-amd64.tar.gz" + +# Put Golang in the path so that we can Delve with it. +ENV PATH=$PATH:/usr/local/go/bin + +# Build Delve and leave it in a temporary directory. +RUN GOBIN=/tmp/bin go install github.com/go-delve/delve/cmd/dlv@latest + +# Build the operator as normal. +FROM registry.access.redhat.com/ubi8/ubi-minimal:latest + +LABEL maintainer = "KubeSaw " +LABEL author = "KubeSaw " + +# Ensure that the "DEBUG_MODE" is enabled so that the binary executes with +# Delve. +ENV DEBUG_MODE=true \ + OPERATOR=/usr/local/bin/member-operator \ + USER_UID=1001 \ + USER_NAME=member-operator \ + LANG=en_US.utf8 + +# Install the operator binary in the image. +COPY build/_output/bin/member-operator ${OPERATOR} + +COPY build/bin /usr/local/bin +RUN /usr/local/bin/user_setup + +# Copy Delve to the image so that we can execute the operator with it. +COPY --from=delve-builder /tmp/bin/dlv /usr/local/bin/dlv + +ENTRYPOINT ["/usr/local/bin/entrypoint"] + +# Expose the debugger's port. +EXPOSE 50000 + +USER ${USER_UID} diff --git a/build/Dockerfile.webhook.debug b/build/Dockerfile.webhook.debug new file mode 100644 index 000000000..c7139edb9 --- /dev/null +++ b/build/Dockerfile.webhook.debug @@ -0,0 +1,53 @@ +# Compile Delve in an intermediate step. +FROM registry.access.redhat.com/ubi8/ubi:latest AS delve-builder + +# The Golang version must be provided as a build arguments, which will ensure +# that Delve gets built with the same version the operator's binary gets built +# with, to avoid any discrepancies. +ARG GOLANG_VERSION + +# Install Tar to be able to extract Golang. +RUN yum install --assumeyes \ + tar \ + && yum clean all + +# Download and extract Golang. +RUN curl --location --output "${GOLANG_VERSION}.linux-amd64.tar.gz" "https://go.dev/dl/${GOLANG_VERSION}.linux-amd64.tar.gz" \ + && tar --directory /usr/local --extract --file "${GOLANG_VERSION}.linux-amd64.tar.gz" \ + && rm --force "${GOLANG_VERSION}.linux-amd64.tar.gz" + +# Put Golang in the path so that we can Delve with it. +ENV PATH=$PATH:/usr/local/go/bin + +# Build Delve and leave it in a temporary directory. +RUN GOBIN=/tmp/bin go install github.com/go-delve/delve/cmd/dlv@latest + +# Build the operator as normal. +FROM registry.access.redhat.com/ubi8/ubi-minimal:latest + +LABEL maintainer = "KubeSaw " +LABEL author = "KubeSaw " + +# Ensure that the "DEBUG_MODE" is enabled so that the binary executes with +# Delve. +ENV DEBUG_MODE=true \ + WEBHOOK=/usr/local/bin/member-operator-webhook \ + USER_UID=1001 \ + USER_NAME=member-operator-webhook \ + LANG=en_US.utf8 + +# Install the operator binary in the image. +COPY build/_output/bin/member-operator-webhook ${WEBHOOK} + +COPY build/bin /usr/local/bin +RUN /usr/local/bin/user_setup + +# Copy Delve to the image so that we can execute the operator with it. +COPY --from=delve-builder /tmp/bin/dlv /usr/local/bin/dlv + +ENTRYPOINT ["/usr/local/bin/entrypoint"] + +# Expose the debugger's port. +EXPOSE 50000 + +USER ${USER_UID} diff --git a/build/bin/entrypoint b/build/bin/entrypoint index e23fa7172..28c06f974 100755 --- a/build/bin/entrypoint +++ b/build/bin/entrypoint @@ -9,4 +9,9 @@ if ! whoami &>/dev/null; then fi fi -exec ${OPERATOR} $@ +if [ -n "${DEBUG_MODE}" ] +then + exec /usr/local/bin/dlv --listen=:50000 --headless --continue --api-version=2 --accept-multiclient exec "${OPERATOR}" "$@" +else + exec ${OPERATOR} "$@" +fi diff --git a/make/go.mk b/make/go.mk index c905ce417..05a402476 100644 --- a/make/go.mk +++ b/make/go.mk @@ -23,6 +23,25 @@ $(OUT_DIR)/operator: -o $(OUT_DIR)/bin/member-operator-webhook \ cmd/webhook/main.go +.PHONY: build-debug +## Build the operator's image with Delve on it so that it is ready to attach a +## debugger to it. +build-debug: + @echo "building member-operator in ${GO_PACKAGE_PATH}" + $(Q)go version + $(Q)CGO_ENABLED=0 GOARCH=${goarch} GOOS=linux \ + go build ${V_FLAG} \ + -gcflags "all=-N -l" \ + -ldflags "-X ${GO_PACKAGE_PATH}/version.Commit=${GIT_COMMIT_ID} -X ${GO_PACKAGE_PATH}/version.BuildTime=${BUILD_TIME}" \ + -o $(OUT_DIR)/bin/member-operator \ + ./cmd/main.go + $(Q)CGO_ENABLED=0 GOARCH=${goarch} GOOS=linux \ + go build ${V_FLAG} \ + -gcflags "all=-N -l" \ + -ldflags "-X ${GO_PACKAGE_PATH}/version.Commit=${GIT_COMMIT_ID} -X ${GO_PACKAGE_PATH}/version.BuildTime=${BUILD_TIME}" \ + -o $(OUT_DIR)/bin/member-operator-webhook \ + cmd/webhook/main.go + .PHONY: vendor vendor: $(Q)go mod vendor diff --git a/make/podman.mk b/make/podman.mk index e637e7bc2..a6c00d7ff 100644 --- a/make/podman.mk +++ b/make/podman.mk @@ -12,12 +12,24 @@ podman-image: build $(Q)podman build --platform ${IMAGE_PLATFORM} -f build/Dockerfile -t ${IMAGE} . $(Q)podman build --platform ${IMAGE_PLATFORM} -f build/Dockerfile.webhook -t ${WEBHOOK_IMAGE} . +## Build the operator's image with Delve on it so that it is ready to attach a +## debugger to it. +podman-image-debug: build-debug + $(Q) podman build --platform ${IMAGE_PLATFORM} --build-arg GOLANG_VERSION="$$(go version | awk '{print $$3}')" --file build/Dockerfile.debug --tag ${IMAGE} . + $(Q) podman build --platform ${IMAGE_PLATFORM} --build-arg GOLANG_VERSION="$$(go version | awk '{print $$3}')" --file build/Dockerfile.webhook.debug --tag ${WEBHOOK_IMAGE} . + .PHONY: podman-push ## Push the binary image to quay.io registry podman-push: check-namespace podman-image $(Q)podman push ${IMAGE} $(Q)podman push ${WEBHOOK_IMAGE} +.PHONY: podman-push-debug +## Push the image with the debugger in it to the repository. +podman-push-debug: check-namespace podman-image-debug + $(Q)podman push ${IMAGE} + $(Q)podman push ${WEBHOOK_IMAGE} + .PHONY: check-namespace check-namespace: ifeq ($(QUAY_NAMESPACE),${GO_PACKAGE_ORG_NAME})