0
点赞
收藏
分享

微信扫一扫

测试和调试 容器化Node应用


Testing and Debugging a Containerized Node application

Introduction

Containers in general and Docker in specific have changed the way how we think about running and deploying software quite a bit. Running an application in a container instead of directly on your computer or server has a lot of advantages. But what about testing and debugging? Are we still able to run tests and debug an application as easy and straight forward when we run it inside a container as we do when we run it directly on our host? In this post I want to give a step by step introduction on how to configure your application and how to adjust your development workflow to achieve exactly that. The source code accompanying this post can be found here.

Creating a sample application

I have chosen to build a simple node JS application that I’ll use to demonstrate testing and debugging when running in a container. The principles show here can be easily adapted to other types of applications, e.g. Python, Go or .NET Core.

Initialize the application

Create a new folder for the project. In the terminal navigate to this folder and run the command

npm initserver.js and when asked for the test command then enter jasmine-node spec. This will generate our package.json

This sample application will use express JS and thus we install this library using

npm install express --saveserver.js

primes.js which contains the logic to determine whether or not a given number is a prime. Thus let’s add such a file primes.js

isPrime which is used on line 11 in the server.js

Adding a Dockerfile

Dockerfile

jasmine-node which we need to run our tests and how we expose not only port 3000 but also port 5858. The latter will be used to attach the debugger. Also note how we first copy only the package.json into the image and run npm install and only after this copy the remainder of the application folder into the image. This helps us to optimize the build of the Docker image. When building an image Docker will only rebuild the layers of the image that have changed. And it is much less likely that we change the content of the package.json

Running the application in a container

Now let’s first build the Docker image of our application. Execute this command in the terminal

docker build -t my-app .

(Don’t forget the point at the end of the command!) And now we can run a container from this image

docker run -d --name my-app -p 3000:3000 my-appdocker ps  If for some reason the container is not running we can use the docker logs myApp

Adding tests

jasmine-nodenpm install -g jasmine-nodespec to your application. Then add a file called primes-spec.js

I am not going to discuss the syntax of a Jasmine test here. Please consult the excellent documentation here if you are not familiar with Jasmine. Once we have defined a test we can now execute the following command in our terminal

npm testjasmine-node spec as we have defined in our project.json  We can of course also add some integration or API tests to the application. For this we need to add the requestmodule to our application. Use this command to add the modulenpm install request --saveserver-spec.js to the spec

npm testdocker-compose. Let’s a add a file docker-compose.test.yml

entrypoint as defined in the Dockerfile with the value npm test. Now on in the terminal enter the following commanddocker-compose -f docker-compose.test.yml up --buildentrypoint. If all works well then we should see an output like this in the terminal

 And as expected, the logs tell us that after building the image a container is run and all tests are executed. In this specific case all tests were successful and thus the exit code is 0 (zero). If some test would fail the exit code would be 1. This is important to know when we execute the tests as part of Continuous Integration (CI). Now we can tear down everything by using

docker-compose -f docker-compose.test.yml down

With this we have shown that to run tests against a node application we do not need to do this on our host but can execute them directly in a Docker container. The advantage of it is that we do not need to install any specific software other than a decent editor to edit our project file on our host (e.g. laptop). We can run our application in a Docker container and test it manually or using automated tests. This is huge when we think about it. Everything application specific is in the container. Our host remains clean. That also means that you can now work on different projects with potentially conflicting frameworks or versions of the same framework. Since you’re always only installing the necessary libraries and frameworks in the container and each container is totally opaque there are no more conflicts!

Debugging the application

Running automated tests against our application is one thing but sometimes we still need to debug our application. We want to be able to step through our code line by line and inspect the value of variables, etc. Can we do that if our application runs in a container? The answer is a bold YES. In the following I am showing how we can achieve this for our node application. I am using Visual Studio Code (which just got released in version 1.0 and runs on Windows, Mac and Linux) as my editor. The technique I am showing here has first been published by Alex Zeitler here. I have tweaked it a bit to fit with my needs. First we need to know on which IP address our Docker host runs. Use the following command to find out

docker-machine ip defaultdefault. In my case the IP address is 192.168.99.100 which is default when you are using Docker Toolbox. Next we add another docker-compose file which we’ll be using for debugging. Add a file called docker-compose.debug.yml

docker-compose file for testing we are using the Dockerfile to build the image, we open port 3000 and(!) port 5858 and map them to the same ports on the host. Finally we override the entrypoint with node --debug=5858 server.js. That is we start node in debug mode listening on port 5858. We can start a debug session by using this commanddocker-compose -f docker-compose.debug.yml up --build -d.vscode to our project. Inside this folder we add a file launch.json.

 The content of this file should be like this

Attach. We specifically need to make sure that the entry address is set to the correct IP address of our Docker host (192.168.99.100 in my case). Also double check that the port corresponds to the one node is listening at. Once we have added the launch configuration we can click on the debug symbol in VS Code. Make sure that the Attach configuration is selected and then hit the run

server.js file. Open a browser and navigate to 192.168.99.100:3000

 In the debug window of VS Code we can now see all kinds of interesting information like the content of variables in scope and the call stack. We can also define watches. With other words: we have a full debugging experience similar to what we’re used if we debug directly on our host instead in a container.

Summary

In this post I have shown how we can run automated tests against a node JS application running in a Docker container as well as how we can debug an application running in a container. We can achieve the same results even though the application is now not running natively on our development system but encapsulated in a container. The benefit of all this is that we don’t need to pollute our host (laptop) with libraries and frameworks to support testing and debugging. Everything is encapsulated in the containers and we only need a nice code editor on our host. What I have shown here can also be applied to other type of applications. In a next post I will do this for a ASP.NET Core application.



举报

相关推荐

0 条评论