You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2023/06/26 18:09:14 UTC

[camel-k] 01/01: Ref #4513: Allow to remote debug the Operator

This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch 4513/remote-debug-operator
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit a49eb87e37dd57dbf416288956356f0674987bfc
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Mon Jun 26 20:08:49 2023 +0200

    Ref #4513: Allow to remote debug the Operator
---
 .gitignore                                         |  4 +
 build/Dockerfile                                   | 10 ++-
 .../ROOT/pages/contributing/remote-debugging.adoc  | 90 ++++++++++++++++++++++
 pkg/cmd/install.go                                 | 13 ++++
 pkg/install/operator.go                            | 23 ++++++
 script/Makefile                                    | 23 ++++--
 6 files changed, 156 insertions(+), 7 deletions(-)

diff --git a/.gitignore b/.gitignore
index 42d3fa167..50fa869a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -176,3 +176,7 @@ config/**/*.gen.json
 # Fabric8 CRDs
 java/target
 pkg/resources/resources.go
+
+MAC OS files
+.DS_Store
+
diff --git a/build/Dockerfile b/build/Dockerfile
index 4694eb062..0b5c9b06f 100644
--- a/build/Dockerfile
+++ b/build/Dockerfile
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM eclipse-temurin:17-jdk
+FROM eclipse-temurin:17-jdk as base
 
 ARG MAVEN_DEFAULT_VERSION="3.8.6"
 ARG MAVEN_HOME="/usr/share/maven"
@@ -56,3 +56,11 @@ RUN mkdir -p /etc/maven/m2 \
 USER 1000
 
 ADD build/_output/bin/kamel /usr/local/bin/kamel
+
+FROM golang:1.19 as go
+
+RUN go install github.com/go-delve/delve/cmd/dlv@latest
+
+FROM base as debug
+
+COPY --from=go /go/bin/dlv /usr/local/bin/dlv
diff --git a/docs/modules/ROOT/pages/contributing/remote-debugging.adoc b/docs/modules/ROOT/pages/contributing/remote-debugging.adoc
new file mode 100644
index 000000000..92b3a3858
--- /dev/null
+++ b/docs/modules/ROOT/pages/contributing/remote-debugging.adoc
@@ -0,0 +1,90 @@
+[[debugging]]
+= Debugging Camel-K
+
+In this article, we describe the steps needed to be able to remote debug the Camel-K operator directly from the K8s cluster.
+By doing so you are sure that the operator is executed in the same context as your target environment which is not the case
+if the operator is launched on the local machine.
+
+[[publish-image]]
+== Publish the image
+
+The first thing to do is to build a specific docker image of the Camel-K operator for the debug mode, indeed the `kamel` program
+will then be built without compiler optimizations, and inlining but also the docker image will launch the operator through
+https://github.com/go-delve/delve[`delve`] to be able to remote debug the operator.
+
+[source,shell]
+----
+DEBUG_MODE=true make images
+----
+
+Once done, a tag of type `docker.io/apache/camel-k:2.0.0-SNAPSHOT-debug` is pushed into your local docker image registry.
+
+In case you are using Minikube, before executing the previous command make sure to set up properly the environment
+variables of your terminal by executing the command `eval $(minikube -p minikube docker-env)`, in that case the image is
+directly pushed into the registry of Minikube.
+
+For other cluster like for example `kind` where the registry is accessible from the host `localhost:5001`, simply tag the
+image to match with the new host and port with the next command:
+
+[source,shell]
+----
+docker tag docker.io/apache/camel-k:2.0.0-SNAPSHOT-debug localhost:5001/apache/camel-k:2.0.0-SNAPSHOT-debug
+----
+
+Then push the image to the target registry with next command:
+[source,shell]
+----
+docker push localhost:5001/apache/camel-k:2.0.0-SNAPSHOT-debug
+----
+
+To ensure that the image has been pushed with success, launch the following command
+[source,shell]
+----
+curl http://localhost:5001/v2/_catalog
+{"repositories":["apache/camel-k"]}
+----
+
+[[install-operator]]
+== Install the operator
+
+Since the docker image is ready to be used, we can now install the operator with the debugging flags to make sure that
+the operator will be launched properly with the debug port open on the corresponding pod.
+
+First, let's create a namespace in which the operator will be installed, here the namespace is `test`.
+[source,shell]
+----
+kubectl create ns test
+namespace/test created
+----
+
+Then install the operator with the image that we built before
+[source,shell]
+----
+./kamel install --olm=false --operator-image apache/camel-k:2.0.0-SNAPSHOT-debug --debugging -n test
+----
+It will install the operator using `apache/camel-k:2.0.0-SNAPSHOT-debug` as docker image in debug mode.
+
+[[port-forward]]
+== Open the port on the pod
+
+The operator is now waiting for a remote connection, but to make it possible, we need to make the debugging port of the
+pod accessible from outside the cluster thanks to the following `port-forward` command:
+
+[source,shell]
+----
+kubectl port-forward -n test $(kubectl get po -l app=camel-k -oname -n test) 4040:4040
+Forwarding from 127.0.0.1:4040 -> 4040
+Forwarding from [::1]:4040 -> 4040
+----
+This command port forwards the port `4040` of the pod to the local port `4040` which makes it accessible from localhost.
+Where `4040` is the default port of delve set on the pod, but it can be changed when installing the operator with the flag
+`--debugging-port=4040`
+
+[[configure-ide]]
+== Configure your IDE
+
+At this stage, you simply need to configure your favorite IDE to remote debug the operator using `localhost` as host and
+`4040` as port:
+
+* https://www.jetbrains.com/help/go/attach-to-running-go-processes-with-debugger.html#step-3-create-the-remote-run-debug-configuration-on-the-client-computer[Configure IDEA]
+* https://go.googlesource.com/vscode-go/+/HEAD/docs/debugging.md#remote-debugging[Configure VSCode]
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 738d9a092..7c95ba1c2 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -140,6 +140,11 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
 	cmd.Flags().Bool("monitoring", false, "To enable or disable the operator monitoring")
 	cmd.Flags().Int("monitoring-port", 8080, "The port of the metrics endpoint")
 
+	// debugging
+	cmd.Flags().Bool("debugging", false, "To enable or disable the operator debugging")
+	cmd.Flags().Int("debugging-port", 4040, "The port of the debugger")
+	cmd.Flags().String("debugging-path", "/usr/local/bin/kamel", "The path to the kamel executable file")
+
 	// Operator settings
 	cmd.Flags().StringArray("toleration", nil, "Add a Toleration to the operator Pod")
 	cmd.Flags().StringArray("node-selector", nil, "Add a NodeSelector to the operator Pod")
@@ -196,6 +201,9 @@ type installCmdOptions struct {
 	MaxRunningBuilds            int32    `mapstructure:"max-running-pipelines"`
 	Monitoring                  bool     `mapstructure:"monitoring"`
 	MonitoringPort              int32    `mapstructure:"monitoring-port"`
+	Debugging                   bool     `mapstructure:"debugging"`
+	DebuggingPort               int32    `mapstructure:"debugging-port"`
+	DebuggingPath               string   `mapstructure:"debugging-path"`
 	TraitProfile                string   `mapstructure:"trait-profile"`
 	Tolerations                 []string `mapstructure:"tolerations"`
 	NodeSelectors               []string `mapstructure:"node-selectors"`
@@ -427,6 +435,11 @@ func (o *installCmdOptions) setupOperator(
 			Enabled: o.Monitoring,
 			Port:    o.MonitoringPort,
 		},
+		Debugging: install.OperatorDebuggingConfiguration{
+			Enabled: o.Debugging,
+			Port:    o.DebuggingPort,
+			Path:    o.DebuggingPath,
+		},
 		Tolerations:           o.Tolerations,
 		NodeSelectors:         o.NodeSelectors,
 		ResourcesRequirements: o.ResourcesRequirements,
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index c76666a33..89d09fb69 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -57,6 +57,7 @@ type OperatorConfiguration struct {
 	ClusterType           string
 	Health                OperatorHealthConfiguration
 	Monitoring            OperatorMonitoringConfiguration
+	Debugging             OperatorDebuggingConfiguration
 	Tolerations           []string
 	NodeSelectors         []string
 	ResourcesRequirements []string
@@ -68,6 +69,12 @@ type OperatorHealthConfiguration struct {
 	Port int32
 }
 
+type OperatorDebuggingConfiguration struct {
+	Enabled bool
+	Port    int32
+	Path    string
+}
+
 type OperatorMonitoringConfiguration struct {
 	Enabled bool
 	Port    int32
@@ -210,6 +217,22 @@ func OperatorOrCollect(ctx context.Context, cmd *cobra.Command, c client.Client,
 				FSGroup: &ugfid,
 			}
 		}
+		if cfg.Debugging.Enabled {
+			if d, ok := o.(*appsv1.Deployment); ok {
+				if d.Labels["camel.apache.org/component"] == "operator" {
+					d.Spec.Template.Spec.Containers[0].Command = []string{"dlv",
+						fmt.Sprintf("--listen=:%d", cfg.Debugging.Port), "--headless=true", "--api-version=2",
+						"exec", cfg.Debugging.Path, "--", "operator", "--leader-election=false"}
+					d.Spec.Template.Spec.Containers[0].Ports = append(d.Spec.Template.Spec.Containers[0].Ports, corev1.ContainerPort{
+						Name:          "delve",
+						ContainerPort: cfg.Debugging.Port,
+					})
+					// In debug mode, the Liveness probe must be removed otherwise K8s will consider the pod as dead
+					// while debugging
+					d.Spec.Template.Spec.Containers[0].LivenessProbe = nil
+				}
+			}
+		}
 
 		if cfg.Global {
 			if d, ok := o.(*appsv1.Deployment); ok {
diff --git a/script/Makefile b/script/Makefile
index 2f41df8dc..6b6c5841d 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -54,7 +54,7 @@ RELEASE_GIT_REMOTE := origin
 GIT_COMMIT := $(shell if [ -d .git ]; then git rev-list -1 HEAD; else echo "$(CUSTOM_VERSION)"; fi)
 LINT_GOGC := 10
 LINT_DEADLINE := 10m
-
+DEBUG_MODE ?= false
 
 # olm bundle vars
 MANAGER := config/manager
@@ -121,6 +121,10 @@ endif
 
 GOFLAGS = -ldflags "$(GOLDFLAGS)" -trimpath
 
+ifeq ($(DEBUG_MODE),true)
+GOFLAGS += -gcflags="all=-N -l"
+endif
+
 define LICENSE_HEADER
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
@@ -432,6 +436,17 @@ else
 endif
 	cp build/_output/bin/kamel-$(IMAGE_ARCH) build/_output/bin/kamel
 
+DOCKER_TAG := $(CUSTOM_IMAGE):$(CUSTOM_VERSION)
+ifneq ($(IMAGE_ARCH), amd64)
+	DOCKER_TAG := $(DOCKER_TAG)-$(IMAGE_ARCH)
+endif
+
+ifeq ($(DEBUG_MODE),true)
+	TARGET_STAGE := debug
+	DOCKER_TAG := $(DOCKER_TAG)-debug
+else
+	TARGET_STAGE := base
+endif
 
 images: build kamel-overlay maven-overlay bundle-kamelets
 ifneq (,$(findstring SNAPSHOT,$(RUNTIME_VERSION)))
@@ -439,11 +454,7 @@ ifneq (,$(findstring SNAPSHOT,$(RUNTIME_VERSION)))
 endif
 	@echo "####### Building Camel K operator arch $(IMAGE_ARCH) container image..."
 	mkdir -p build/_maven_output
-ifeq ($(IMAGE_ARCH), amd64)
-	docker build --platform=linux/$(IMAGE_ARCH) -t $(CUSTOM_IMAGE):$(CUSTOM_VERSION) -f build/Dockerfile .
-else
-	docker build --platform=linux/$(IMAGE_ARCH) -t $(CUSTOM_IMAGE):$(CUSTOM_VERSION)-$(IMAGE_ARCH) -f build/Dockerfile .
-endif
+	docker build --target $(TARGET_STAGE) --platform=linux/$(IMAGE_ARCH) -t $(DOCKER_TAG) -f build/Dockerfile .
 
 # Mainly used for internal CI purposes
 image-push: