diff --git a/template/Tiltfile b/template/Tiltfile index 98f0a07..cd18f4f 100644 --- a/template/Tiltfile +++ b/template/Tiltfile @@ -9,6 +9,11 @@ print( load("ext://syncback", "syncback") +# Check for --debugpy argument +config.define_bool("debugpy", False, "Enable debugpy debugging support") +cfg = config.parse() +enable_debugpy = cfg.get("debugpy", False) + docker_build( "backend", context="backend", @@ -29,9 +34,11 @@ docker_build( ) {% endif %} -k8s_yaml( - kustomize("./k8s/local/") -) +# Load kubernetes configuration +if enable_debugpy: + k8s_yaml(local('./k8s/local/enable-debugpy.sh')) +else: + k8s_yaml(kustomize("./k8s/local/")) syncback( "backend-sync", @@ -55,6 +62,8 @@ syncback( {% if copier__create_nextjs_frontend %} k8s_resource(workload='frontend', port_forwards=3000) {% endif %} +if enable_debugpy: + k8s_resource(workload='backend', port_forwards=5678) k8s_resource(workload='backend', port_forwards=8000) k8s_resource(workload='mailhog', port_forwards=8025) k8s_resource(workload='postgres', port_forwards=5432) diff --git a/template/backend/{{copier__project_slug}}/utils/debugger.py b/template/backend/{{copier__project_slug}}/utils/debugger.py index 957bc41..54671b2 100644 --- a/template/backend/{{copier__project_slug}}/utils/debugger.py +++ b/template/backend/{{copier__project_slug}}/utils/debugger.py @@ -8,9 +8,10 @@ def pycharm_debugger(): logger.info("Pycharm pydevd connecting...") import pydevd_pycharm host_ip = os.getenv("DOCKER_GATEWAY_IP") + debug_port = int(os.getenv("DEBUGGER_PORT", default=6400)) try: pydevd_pycharm.settrace( - host_ip, port=6400, stdoutToServer=True, stderrToServer=True, suspend=False + host_ip, port=debug_port, stdoutToServer=True, stderrToServer=True, suspend=False ) except ConnectionRefusedError: msg = "Debugger connection failed. Check IDE debugger is running and try again. Continuing without debugger." @@ -18,4 +19,7 @@ def pycharm_debugger(): def vscode_debugger(): - raise NotImplementedError("VSCode debugger not implemented") + logger.info("Debugpy connecting...") + import debugpy + debug_port = int(os.getenv("DEBUGGER_PORT", default=5678)) + debugpy.listen(("0.0.0.0", debug_port)) # nosec B104 diff --git a/template/docs/debug.md b/template/docs/debug.md index 96ea6e7..8e0b8eb 100644 --- a/template/docs/debug.md +++ b/template/docs/debug.md @@ -1,9 +1,32 @@ # :bug: How to debug the application -The steps below describe how to set up interactive debugging with PyCharm. +The steps below describe how to set up interactive debugging. Scaf supports -## PyCharm Debugging Setup -Update `k8s/base/app.configmap.yaml` with `data` field `PYTHONBREAKPOINT: "utils.pycharm_debugger"` +* PyCharm +* VS Code + +## Starting Tilt with Debugging Support + +To enable debugging, start Tilt with the `--debugpy` flag: + +```bash +tilt up -- --debugpy +``` + +This will: +* Add the debug port (5678) to the backend service +* Modify the Django container to use debugpy +* Enable port forwarding for the debug port + +Without the `--debugpy` flag, Tilt will run normally without debugging support. + +## PyCharm Debugging + +### Setup + +Update `k8s/base/app.configmap.yaml` with: +* `data` field `PYTHONBREAKPOINT: "utils.pycharm_debugger"` +* `data` field `DEBUGGER_PORT: "6400"` In PyCharm: @@ -19,11 +42,59 @@ In PyCharm: ![debug__debug_configuration.png](images/debug__debug_configuration.png) -## Debugging in development +### Debugging in development Before the code you want to debug, add the following: ```python breakpoint() ``` -You must then set break points in your IDE and call the code as usual to hit them. +You must then set break points in PyCharm, and call the code as usual to hit them. + +## VS Code Debugging + +### Setup + +Make sure you have started Tilt with the `--debugpy` flag as described above. + +In VS Code: + +1. Go to 'Run & Debug` tab +2. Click on 'create a launch.json file' +3. Choose 'Python Debugger' +4. Choose 'Remote Attach' +5. Set the host to `0.0.0.0` +6. Set the port to `5678` +7. VS Code will create a `.vscode/launch.json` with your configuration. +8. You'll need to update the `pathMappings` slightly. See the example below. +9. Make any desired further changes, then save. The file should something look like: + +```json +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Remote Attach", + "type": "debugpy", + "request": "attach", + "connect": { + "host": "0.0.0.0", + "port": 5678 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder}/backend", + "remoteRoot": "/app/src" + } + ] + } + ] +} +``` + +### Debugging in development + +You can set break points in VS Code as normal, and call the code as usual to hit them. diff --git a/template/k8s/base/app.configmap.yaml b/template/k8s/base/app.configmap.yaml index 685be10..ac7f1db 100644 --- a/template/k8s/base/app.configmap.yaml +++ b/template/k8s/base/app.configmap.yaml @@ -22,7 +22,8 @@ data: # Also probably need to add cython to local.in in that case. PYDEVD_USE_CYTHON: "NO" PYDEVD_USE_FRAME_EVAL: "NO" - PYTHONBREAKPOINT: "" # "utils.pycharm_debugger" for pycharm + PYTHONBREAKPOINT: "" # "utils.pycharm_debugger" for pycharm, "utils.vscode_debugger" for VS Code + DEBUGGER_PORT: "" # "6400" for pycharm, "5678" for VS Code {%- if copier__mail_service == 'Mailgun' %} MAILGUN_DOMAIN: "{{ copier__domain_name }}" MAILGUN_API_URL: "https://api.mailgun.net/v3"{%- endif %} diff --git a/template/k8s/base/django.yaml b/template/k8s/base/django.yaml index f445f95..41af67b 100644 --- a/template/k8s/base/django.yaml +++ b/template/k8s/base/django.yaml @@ -11,6 +11,7 @@ spec: ports: - port: 8000 targetPort: http-server + name: wsgi --- apiVersion: apps/v1 kind: Deployment diff --git a/template/k8s/local/enable-debugpy.sh b/template/k8s/local/enable-debugpy.sh new file mode 100755 index 0000000..bfea41e --- /dev/null +++ b/template/k8s/local/enable-debugpy.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Generate base YAML and patch with debugpy support +kubectl kustomize ./k8s/local/ | yq --yaml-output ' + if (.kind == "Service" and .metadata.name == "backend") then + .spec.ports += [{ + "port": 5678, + "targetPort": 5678, + "name": "debug" + }] + elif (.kind == "Deployment" and .metadata.name == "backend") then + .spec.template.spec.containers[0].command = [ + "python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "manage.py", "runserver", "0.0.0.0:8000" + ] | + .spec.template.spec.containers[0].ports += [{ + "name": "debug", + "containerPort": 5678 + }] + else + . + end +'