Skip to content

Commit d8e6bbf

Browse files
committed
Add ephemeral debugging guide (nginx#1202)
Problem: No documentation on how to debug NGF in Kubernetes Solution: Add a developer guide with step-by-step instructions on how to inject an ephemeral dlv debug container into NGF while it's running in a cluster. Includes makefile targets to make the process easier and a dockerfile for the dlv debug image.
1 parent 8f3549b commit d8e6bbf

File tree

5 files changed

+211
-5
lines changed

5 files changed

+211
-5
lines changed

Makefile

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ NGINX_CONF_DIR = internal/mode/static/nginx/conf
88
NJS_DIR = internal/mode/static/nginx/modules/src
99
NGINX_DOCKER_BUILD_PLUS_ARGS = --secret id=nginx-repo.crt,src=nginx-repo.crt --secret id=nginx-repo.key,src=nginx-repo.key
1010
BUILD_AGENT=local
11+
GW_API_VERSION = 1.0.0
12+
INSTALL_WEBHOOK = false
1113

1214
# go build flags - should not be overridden by the user
1315
GO_LINKER_FlAGS_VARS = -X main.version=${VERSION} -X main.commit=${GIT_COMMIT} -X main.date=${DATE}
@@ -147,13 +149,59 @@ njs-unit-test: ## Run unit tests for the njs httpmatches module
147149
lint-helm: ## Run the helm chart linter
148150
helm lint $(CHART_DIR)
149151

152+
.PHONY: load-images
153+
load-images: ## Load NGF and NGINX images on configured kind cluster.
154+
kind load docker-image $(PREFIX):$(TAG) $(NGINX_PREFIX):$(TAG)
155+
156+
.PHONY: load-images-with-plus
157+
load-images-with-plus: ## Load NGF and NGINX Plus images on configured kind cluster.
158+
kind load docker-image $(PREFIX):$(TAG) $(NGINX_PLUS_PREFIX):$(TAG)
159+
160+
.PHONY: install-ngf-local-build
161+
install-ngf-local-build: build-images load-images helm-install-local ## Install NGF from local build on configured kind cluster.
162+
163+
.PHONY: install-ngf-local-build-with-plus
164+
install-ngf-local-build-with-plus: build-images-with-plus load-images-with-plus helm-install-local-with-plus ## Install NGF with NGINX Plus from local build on configured kind cluster.
165+
166+
.PHONY: helm-install-local
167+
helm-install-local: ## Helm install NGF on configured kind cluster with local images. To build, load, and install with helm run make install-ngf-local-build.
168+
./conformance/scripts/install-gateway.sh $(GW_API_VERSION) $(INSTALL_WEBHOOK)
169+
helm install dev ./deploy/helm-chart --create-namespace --wait --set service.type=NodePort --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginxGateway.image.pullPolicy=Never --set nginx.image.repository=$(NGINX_PREFIX) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=Never -n nginx-gateway
170+
171+
.PHONY: helm-install-local-with-plus
172+
helm-install-local-with-plus: ## Helm install NGF with NGINX Plus on configured kind cluster with local images. To build, load, and install with helm run make install-ngf-local-build-with-plus.
173+
./conformance/scripts/install-gateway.sh $(GW_API_VERSION) $(INSTALL_WEBHOOK)
174+
helm install dev ./deploy/helm-chart --create-namespace --wait --set service.type=NodePort --set nginxGateway.image.repository=$(PREFIX) --set nginxGateway.image.tag=$(TAG) --set nginxGateway.image.pullPolicy=Never --set nginx.image.repository=$(NGINX_PLUS_PREFIX) --set nginx.image.tag=$(TAG) --set nginx.image.pullPolicy=Never --set nginx.plus=true -n nginx-gateway
175+
176+
# Debug Targets
150177
.PHONY: debug-build
151178
debug-build: GO_LINKER_FLAGS=$(GO_LINKER_FlAGS_VARS)
152179
debug-build: ADDITIONAL_GO_BUILD_FLAGS=-gcflags "all=-N -l"
153180
debug-build: build ## Build binary with debug info, symbols, and no optimizations
154181

155-
.PHONY: build-ngf-debug-image
156-
build-ngf-debug-image: debug-build build-ngf-image ## Build NGF image with debug binary
182+
.PHONY: debug-build-dlv-image
183+
debug-build-dlv-image: check-for-docker ## Build the dlv debugger image.
184+
docker build --platform linux/$(GOARCH) -f debug/Dockerfile -t dlv-debug:edge .
185+
186+
.PHONY: debug-build-images
187+
debug-build-images: debug-build build-ngf-image build-nginx-image debug-build-dlv-image ## Build all images used in debugging.
188+
189+
.PHONY: debug-build-images-with-plus
190+
debug-build-images-with-plus: debug-build build-ngf-image build-nginx-plus-image debug-build-dlv-image ## Build all images with NGINX plus used in debugging.
191+
192+
.PHONY: debug-load-images
193+
debug-load-images: load-images ## Load all images used in debugging to kind cluster.
194+
kind load docker-image dlv-debug:edge
195+
196+
.PHONY: debug-load-images-with-plus
197+
debug-load-images-with-plus: load-images-with-plus ## Load all images with NGINX Plus used in debugging to kind cluster.
198+
kind load docker-image dlv-debug:edge
199+
200+
.PHONY: debug-install-local-build
201+
debug-install-local-build: debug-build-images debug-load-images helm-install-local ## Install NGF from local build using debug NGF binary on configured kind cluster.
202+
203+
.PHONY: debug-install-local-build-with-plus
204+
debug-install-local-build-with-plus: debug-build-images-with-plus debug-load-images-with-plus helm-install-local-with-plus ## Install NGF with NGINX Plus from local build using debug NGF binary on configured kind cluster.
157205

158206
.PHONY: dev-all
159207
dev-all: deps fmt njs-fmt vet lint unit-test njs-unit-test ## Run all the development checks

conformance/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ build-images: ## Build NGF and nginx images
4444

4545
.PHONY: load-images
4646
load-images: ## Load NGF and NGINX images on configured kind cluster
47-
kind load docker-image $(PREFIX):$(TAG) $(NGINX_PREFIX):$(TAG)
47+
cd .. && make PREFIX=$(PREFIX) TAG=$(TAG) load-images
4848

4949
.PHONY: prepare-ngf-dependencies
5050
prepare-ngf-dependencies: update-ngf-manifest ## Install NGF dependencies on configured kind cluster

debug/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# syntax=docker/dockerfile:1.5
2+
# This Dockerfile builds an image with the dlv debugger. See the debugging guide in the developer docs for details
3+
# on how to use it.
4+
FROM golang:1.21-alpine AS builder
5+
6+
RUN go install github.com/go-delve/delve/cmd/dlv@latest
7+
8+
FROM alpine:latest
9+
10+
COPY --from=builder /go/bin/dlv /usr/bin/
11+
12+
CMD ["sh"]

docs/developer/debugging.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Debugging
2+
3+
## Debugging NGF Remotely in Kubernetes
4+
5+
This section will walk you through how to attach an ephemeral [dlv](https://github.com/go-delve/delve) debugger
6+
container to NGF while it's running in Kubernetes. This will allow you to remotely debug NGF running in Kubernetes
7+
using your IDE.
8+
9+
- Create a `kind` cluster:
10+
11+
```console
12+
make create-kind-cluster
13+
```
14+
15+
- Set GOARCH environment variable:
16+
17+
The [Makefile](/Makefile) uses the GOARCH variable to build the binary and container images. The default value of GOARCH is `amd64`.
18+
19+
If you are deploying NGINX Gateway Fabric on a kind cluster, and the architecture of your machine is not `amd64`, you will want to set the GOARCH variable to the architecture of your local machine. You can find the value of GOARCH by running `go env`. Export the GOARCH variable in your `~/.zshrc` or `~/.bashrc`.
20+
21+
```console
22+
echo "export GOARCH=< Your architecture (e.g. arm64 or amd64) >" >> ~/.bashrc
23+
source ~/.bashrc
24+
```
25+
26+
or for zsh:
27+
28+
```console
29+
echo "export GOARCH=< Your architecture (e.g. arm64 or amd64) >" >> ~/.zshrc
30+
source ~/.zshrc
31+
```
32+
33+
- Build debug images and install NGF on your kind cluster:
34+
35+
- **For NGINX OSS:**
36+
37+
```console
38+
make GOARCH=$GOARCH debug-install-local-build
39+
```
40+
41+
- **For NGINX Plus:**
42+
43+
```console
44+
make GOARCH=$GOARCH debug-install-local-build-with-plus
45+
```
46+
47+
> Note: The default value of GOARCH in the [Makefile](/Makefile) is `amd64`. If you try and debug an amd64 container on an ARM machine you will see the following error in the dlv container logs: `could not attach to pid <pid>: function not implemented`.
48+
> This is a known issue and the only workaround is to create an arm64 image by specifying `GOARCH=arm64` the above commands.
49+
> For more information, see this [issue](https://github.com/docker/for-mac/issues/5191)
50+
51+
- Start kubectl proxy in the background:
52+
53+
```console
54+
kubectl proxy &
55+
```
56+
57+
- Save the NGF Pod name:
58+
59+
```console
60+
POD_NAME=<NGF Pod>
61+
```
62+
63+
- Run the following curl command to create an ephemeral debug container:
64+
65+
```console
66+
curl --location --request PATCH 127.0.0.1:8001/api/v1/namespaces/nginx-gateway/pods/$POD_NAME/ephemeralcontainers \
67+
--header 'Content-Type: application/strategic-merge-patch+json' \
68+
--data '{
69+
"spec":
70+
{
71+
"ephemeralContainers":
72+
[
73+
{
74+
"name": "dlv",
75+
"command": [
76+
"/bin/sh",
77+
"-c",
78+
"PID=$(pgrep -f /usr/bin/gateway) && dlv attach $PID --headless --listen 127.0.0.1:40000 --api-version=2 --accept-multiclient --only-same-user=false"
79+
],
80+
"image": "dlv-debug:edge",
81+
"imagePullPolicy": "Never",
82+
"targetContainerName": "nginx-gateway",
83+
"stdin": true,
84+
"tty": true,
85+
"securityContext": {
86+
"capabilities": {
87+
"add": [
88+
"SYS_PTRACE"
89+
]
90+
},
91+
"runAsNonRoot":false
92+
}
93+
}
94+
]
95+
}
96+
}'
97+
```
98+
99+
- Verify that the dlv API server is running:
100+
101+
```console
102+
kubectl logs -n nginx-gateway $POD_NAME -c dlv
103+
```
104+
105+
you should see the following log:
106+
107+
```text
108+
API server listening at: 127.0.0.1:40000
109+
```
110+
111+
- Kill the kubectl proxy process:
112+
113+
```console
114+
kill <kubectl proxy PID>
115+
```
116+
117+
- Port-forward the dlv API server port on the NGF Pod:
118+
119+
```console
120+
kubectl port-forward -n nginx-gateway $POD_NAME 40000
121+
```
122+
123+
- Connect to the remote dlv API server through your IDE:
124+
- [jetbrains instructions](https://www.jetbrains.com/help/go/attach-to-running-go-processes-with-debugger.html)
125+
- [vscode instructions](https://github.com/golang/vscode-go/blob/master/docs/debugging.md)
126+
127+
- Debug!

docs/developer/quickstart.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Follow these steps to set up your development environment.
1111
1. Install:
1212
- [Go](https://golang.org/doc/install) v1.21.0+
1313
- [Docker](https://docs.docker.com/get-docker/) v18.09+
14+
- [Kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)
1415
- [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
1516
- [Helm](https://helm.sh/docs/intro/quickstart/#install-helm)
1617
- [git](https://git-scm.com/)
@@ -50,12 +51,30 @@ Follow these steps to set up your development environment.
5051

5152
## Build the Binary and Images
5253

54+
### Setting GOARCH
55+
56+
The [Makefile](/Makefile) uses the GOARCH variable to build the binary and container images. The default value of GOARCH is `amd64`.
57+
58+
If you are deploying NGINX Gateway Fabric on a kind cluster, and the architecture of your machine is not `amd64`, you will want to set the GOARCH variable to the architecture of your local machine. You can find the value of GOARCH by running `go env`. Export the GOARCH variable in your `~/.zshrc` or `~/.bashrc`.
59+
60+
```shell
61+
echo "export GOARCH=< Your architecture (e.g. arm64 or amd64) >" >> ~/.bashrc
62+
source ~/.bashrc
63+
```
64+
65+
or for zsh:
66+
67+
```shell
68+
echo "export GOARCH=< Your architecture (e.g. arm64 or amd64) >" >> ~/.zshrc
69+
source ~/.zshrc
70+
```
71+
5372
### Build the Binary
5473

5574
To build the binary, run the make build command from the project's root directory:
5675
5776
```makefile
58-
make build
77+
make GOARCH=$GOARCH build
5978
```
6079
6180
This command will build the binary and output it to the `/build/.out` directory.
@@ -65,7 +84,7 @@ This command will build the binary and output it to the `/build/.out` directory.
6584
To build the NGINX Gateway Fabric and NGINX container images from source run the following make command:
6685
6786
```makefile
68-
make TAG=$(whoami) build-images
87+
make GOARCH=$GOARCH TAG=$(whoami) build-images
6988
```
7089
7190
This will build the docker images `nginx-gateway-fabric:<your-user>` and `nginx-gateway-fabric/nginx:<your-user>`.

0 commit comments

Comments
 (0)