docker-lambda icon indicating copy to clipboard operation
docker-lambda copied to clipboard

Debugging documentation

Open richarddd opened this issue 4 years ago • 11 comments

First of all: Thanks for your amazing work on this project!

I understand it is possible to attach a remote debugger to process running in the docker container.

However I'm missing documentation on how to do so?

I'm specifically search for info on how to attach a debugger on node, java and python lambdas when they are running in the container.

Thanks 🙂

richarddd avatar Jan 08 '20 08:01 richarddd

I was having the same issue and I had to customise the running image to solve it. First I tried using docker kill --signal SIGUSR1 <container_id>, as explained here, but that didn't work. If anyone knows how to channel SIGUSR1 into the lambda's node process, please let us know!

That would make debugging a way more elegant solution than the workarounds I am posting below:

zvictor avatar Mar 29 '20 09:03 zvictor

Workaround 1: start node with --inspect using a custom image

FROM lambci/lambda:nodejs12.x

USER root
RUN sed -i "s/bin\/node/bin\/node --inspect=0.0.0.0:9229/g" /var/runtime/bootstrap
# undo the USER change that was needed above:
USER sbx_user1051

The RUN command above will change the script that launches your application and will append the --inspect option to have the debugger running at port 9229 of the container. Do not forget to expose the port 9229!

zvictor avatar Mar 29 '20 09:03 zvictor

Workaround 2: replace /var/runtime/bootstrap using a volume

The idea here is to avoid building a custom image.

  1. Add the --inspect instruction to a copy of the /var/runtime/bootstrap file.
  2. Add a volume to your running container that replaces the original /var/runtime/bootstrap by yours (from step 1).
  3. expose the debugging port

For unknown reasons, this solution didn't work that well to me. I managed to get one lambda working well, but a second lambda doesn't start the debugger 🤷‍♀️

zvictor avatar Mar 29 '20 09:03 zvictor

I got it working using node by simply setting NODE_OPTIONS and setting the debug port. Then expose that port from my dockerfile :)

BUT, that only solves the "node" debugging, I have no idea how to solve java, c#, python etc .:/

richarddd avatar Mar 31 '20 06:03 richarddd

does it work with just NODE_OPTIONS? 🤔 I feel so dumb right now... 😆

zvictor avatar Mar 31 '20 15:03 zvictor

If anyone finds this useful setting this env inside the container will allow you to debug Java (checked with jdk11)

JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=127.0.0.1:8000

Remember to expose the port too.

jakub-bochenski avatar Aug 05 '20 12:08 jakub-bochenski

does it work with just NODE_OPTIONS? 🤔 I feel so dumb right now... 😆

Clearly, I don't know entirely what to do here. I have tried to set the NODE_OPTIONS environment variable in my docker-compose file but yet the port still remains closed:

  lambda:
    image: lambci/lambda:nodejs12.x
    environment: 
      DOCKER_LAMBDA_WATCH: 1
      DOCKER_LAMBDA_STAY_OPEN: 1
      DOCKER_LAMBDA_DEBUG: 1
      LAMBDA_TASK_ROOT: /var/task/.webpack/service
      NODE_OPTIONS: --inspect=0.0.0.0:9229/g
    command: src/handlers/template.handler
    ports: 
      - "9101:9001"
      - "9229:9229"
    volumes:
      - build_artifacts:/var/task:ro
$ docker-compose -p devcontainer up lambda
Recreating devcontainer_lambda_1 ... done
Attaching to devcontainer_lambda_1
lambda_1      | Lambda API listening on port 9001...

$ telnet 192.168.56.99 9229
Trying 192.168.56.99...
telnet: Unable to connect to remote host: Connection refused

benze avatar Nov 09 '20 20:11 benze

Just remove this /g you added. it should be NODE_OPTIONS: --inspect=0.0.0.0:9229

zvictor avatar Nov 09 '20 21:11 zvictor

@zvictor I made the change, but clearly I must be doing something else wrong. After restarting the container, I noticed I first need to send it a request to get it to launch node and listen to the port properly. Once I do that, I am able to attach the debugger.

My launch.json is configured as:

    "configurations": [
        {
            "address": "192.168.56.99",
            "localRoot": "${workspaceFolder}",
            "name": "Attach to Remote",
            "port": 9229,
            "remoteRoot": "/var/task/.webpack/service",
            "request": "attach",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "type": "pwa-node"
        }
    ]

where /var/task/.webpack/service is the path I have mounted in LAMBDA_TASK_ROOT and the root to the webpacked node application. It is not, however, the root for the handler itself. The handler is in /var/task/.webpack/service/src/handlers/template.js

When I launch the debugger, it seems to attach. Docker logs show:

lambda_1      | Debugger attached.

And yet, no breakpoints or variables or stack trace are shown in VSC.

Any suggestions?

benze avatar Nov 10 '20 02:11 benze

This is what I have in my launch.json:

      {
        "type": "node",
        "request": "attach",
        "name": "my lambda",
        "port": 9229,
        "localRoot": "${workspaceFolder}",
        "remoteRoot": "/var/task",
        "protocol": "inspector",
        "restart": true,
        "skipFiles": [
          "<node_internals>/**",
          "/var/runtime/**",
          "**/node_modules/**"
        ]
      },

and also consider giving a try to ms-vscode.js-debug-nightly. It works better for me.

It looks like you are using webpack and pwa specifics and that might be complicating things to you. I don't know how you setup such things so I can't help you further. I suggest you try first debugging a basic lambda "hello world" and then go for your "full" project.

zvictor avatar Nov 10 '20 07:11 zvictor

Thanks! Indeed, I took a step back and worked through the process more carefully. In the end, the sourcemaps generated by webpack were causing me the most pain. Using the following webpack config helped me out:

module.exports = {
...
    devtool: 'inline-source-map',
    output: {
        libraryTarget: 'commonjs',
        path: path.resolve(__dirname, 'build/.webpack'),
        filename: '[name].js',
        devtoolModuleFilenameTemplate: 'file:///[absolute-resource-path]'  // map to source with absolute file path not webpack:// protocol
    },
...

benze avatar Nov 10 '20 14:11 benze