diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 2b46258e..93ef41f1 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -5,6 +5,7 @@ - [Prerequisites](#prerequisites) - [Getting Started](#getting-started) + - [🐛 Debugging](#-debugging) ## Prerequisites @@ -27,3 +28,41 @@ All other remaining tools (e.g. `kustomize`) are getting installed automatically The `make tilt-up` command will give you the URL to the local tilt environment. 1. Time to start developing. 🎉 + + +### 🐛 Debugging + +To improve the local development process, we add [delve](https://github.com/go-delve/delve) into `garm-operator` container image. +This allows us to debug the `garm-operator` running in the local `kind` cluster. + +The following steps are required to start debugging the `garm-operator`: + +1. set the `mode` variable from `local` to `debug` in the `Tiltfile` + + This will start the `garm-operator` container with the `command` and `args` specified in the [`config/overlays/debug/manager_patch.yaml`](config/overlays/debug/manager_patch.yaml) file. (Ensure that the correct GARM credentials are set.) + + The `garm-operator-controller-manager` pod should log then print the following log message which indicates that you are able to attach a debugger to the `garm-operator`: + + ``` + 2023-12-08T15:39:21Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted) + API server listening at: [::]:2345 + ``` + +1. IDE configuration + 1. VSCode + 1. Create a `launch.json` file in the `.vscode` directory with the following content: + ```json + { + "version": "0.2.0", + "configurations": [ + { + "name": "garm-operator - attach", + "type": "go", + "request": "attach", + "mode": "remote", + "port": 2345 + } + ] + } + ``` +1. Happy debugging 🐛 diff --git a/Dockerfile b/Dockerfile index 6e9cf9b7..f8b184ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,18 +18,23 @@ COPY api/ api/ COPY internal/controller/ internal/controller/ COPY pkg/ pkg/ +# install delve(dlv) for debugging +RUN go install github.com/go-delve/delve/cmd/dlv@latest + # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -o manager cmd/main.go +RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -gcflags "-N -l" -o manager cmd/main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/static:nonroot +FROM busybox:stable WORKDIR / COPY --from=builder /workspace/manager . +COPY --from=builder /go/bin/dlv . + USER 65532:65532 ENTRYPOINT ["/manager"] diff --git a/Tiltfile b/Tiltfile index fc72dbd8..e294a75b 100644 --- a/Tiltfile +++ b/Tiltfile @@ -13,7 +13,15 @@ deploy_cert_manager( version='v1.12.0' # the version of cert-manager to deploy ) -templated_yaml = kustomize('config/overlays/local') +# mode could be either 'local' or 'debug' +# when set to 'debug', delve will be used within the container to start +# the manager binary and the dlv debug port will be exposed +# +# for more details, please read the DEVELOPMENT.md +mode = 'local' + +# kustomize overlays +templated_yaml = kustomize('config/overlays/' + mode) k8s_yaml(templated_yaml) # for not having uncategorized resources in the tilt ui @@ -39,6 +47,11 @@ k8s_resource( 'garm-operator-validating-webhook-configuration:validatingwebhookconfiguration', ], labels=["operator"], + port_forwards=[2345], # dlv debug port +) + +docker_build('localhost:5000/controller', '.', + ignore=['.github', 'config', 'docs', 'hack', '*.md'] ) -docker_build('localhost:5000/controller', '.') +# TODO: add a list of ignore files \ No newline at end of file diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 03f12398..9a0d7b65 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -44,44 +44,44 @@ spec: securityContext: runAsNonRoot: true containers: - - command: - - /manager - args: - - --garm-server=$GARM_SERVER_URL - - --garm-username=$GARM_SERVER_USERNAME - - --garm-password=$GARM_SERVER_PASSWORD - - --operator-watch-namespace=$OPERATOR_WATCH_NAMESPACE - image: controller:latest - name: manager - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - # TODO(user): Configure the resources accordingly based on the project requirements. - # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 10m - memory: 64Mi - volumeMounts: - - name: serviceaccount-volume - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + - command: + - /manager + args: + - --garm-server=$GARM_SERVER_URL + - --garm-username=$GARM_SERVER_USERNAME + - --garm-password=$GARM_SERVER_PASSWORD + - --operator-watch-namespace=$OPERATOR_WATCH_NAMESPACE + image: controller:latest + name: manager + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + volumeMounts: + - name: serviceaccount-volume + mountPath: /var/run/secrets/kubernetes.io/serviceaccount volumes: # use a custom token with specified expiration time - this implementation behaves like the default token mechanism # see: https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#bound-service-account-token-volume diff --git a/config/overlays/debug/kustomization.yaml b/config/overlays/debug/kustomization.yaml new file mode 100644 index 00000000..da28a33b --- /dev/null +++ b/config/overlays/debug/kustomization.yaml @@ -0,0 +1,11 @@ +resources: + - ../../default + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: controller + newName: localhost:5000/controller + +patches: + - path: manager_patch.yaml diff --git a/config/overlays/debug/manager_patch.yaml b/config/overlays/debug/manager_patch.yaml new file mode 100644 index 00000000..916268f2 --- /dev/null +++ b/config/overlays/debug/manager_patch.yaml @@ -0,0 +1,37 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: garm-operator-controller-manager + namespace: garm-operator-system +spec: + template: + spec: + containers: + - name: manager + command: + [ + "/dlv", + "--listen=:2345", + "--headless=true", + "--api-version=2", + "--accept-multiclient", + "exec", + "/manager", + "--wd", + "/tmp", + "--", + ] + args: + - --garm-server=http://garm-server.garm-server.svc:9997 + - --garm-username=admin + - --garm-password=LmrBG1KcBOsDfNKq4cQTGpc0hJ0kejkk + - --operator-watch-namespace=garm-operator-system + ports: + - containerPort: 2345 + name: delve + protocol: TCP + resources: + limits: + memory: 1Gi + requests: + memory: 1Gi diff --git a/config/overlays/local/manager_patch.yaml b/config/overlays/local/manager_patch.yaml index 3a9d1f0a..837927aa 100644 --- a/config/overlays/local/manager_patch.yaml +++ b/config/overlays/local/manager_patch.yaml @@ -13,4 +13,3 @@ spec: - --garm-username=admin - --garm-password=LmrBG1KcBOsDfNKq4cQTGpc0hJ0kejkk - --operator-watch-namespace=garm-operator-system -