In this post, we will continue our previous nodejs weather application and introduce Docker for NodeJS application using VSCode. We will build our application and host it in docker by adding a Dockerfile. We will modify our code to take the APIKEY from an environment variable.
Create Dockerfile
Let’s launch our editor VSCode again with our solution and add the .dockerignore file first, since there are things that we do not want in our Docker image, kind of like gitignore.
node_modules
npm-debug.log
.vscode
Next add a Dockerfile with vscode so that we can build our image, we will use the carbon-alpine image which is v8 of nodejs, the reason we choose alpine is because its small and has minimal size and is secure.
#base image to use
FROM node:carbon-alpine
#the app directory
WORKDIR /usr/src/app
#copy package.json and package-lock.json
COPY package*.json ./
#build the code for production, and install app dependencies
RUN npm install --only=production
#bundle source code inside the Docker image
COPY . .
#Bind port to 3000
EXPOSE 3000
#RUN the application
CMD ["npm", "start"]
Above we will create a working directory and copy our package*.json then we run npm to install our packages. We also expose the default port 3000 and we run our application with npm start.
Modify our source code
Before we build our image, we need to modify our app.js such that the APIKEY is no longer in the source code. Let’s make it so that it takes it from an environment variable. In doing so we will need to pass our APIKEY in our environment when we start to run our docker image, more on this later.
let apiKey = process.env.APIKEY;
app.set('apiKey', apiKey);
Build our NodeJS Image
Now that we modified app.js we can now go back to our docker file and build our image. Hit Ctrl+` in your vscode to launch terminal.
$docker build -t /myweatherapp .
Once finished building you can see your docker image by this command
$docker images
taswar/myweatherapp latest d6abb08fcf9f 7 seconds ago 76.1MB
Run the image
Since we modified app.js we now need to inject the APIKEY into our docker image, we can do so with this command in vscode terminal using powershell. You need to use the proper APIKEY that you have got from openweather. We are also exposing the inside port 3000 to our local machine port of 8080
$docker run -p 8080:3000 -e APIKEY=1234 -d taswar/myweatherapp
Now we should be able to view our application on http://localhost:8080
Security Issue
So you may think that now that we pass our APIKEY through the environment we are all good, but there is still a security issue here. If someone hacks into your machine that runs docker they are still able to see your secrets. Say What???
Lets try to inspect our docker container by using the following commands, first lets find out the container id that docker is running under
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1fe8eb2d995 taswar/myweatherapp "npm start" 35 minutes ago Up 35 minutes 0.0.0.0:8080->3000/tcp romantic_jennings
Now we can inspect the container by using this command, we don’t have to type the entire id, the first 3 characters would do the trick.
$ docker inspect e1f
If we look at the config section of the inspect we will see our APIKEY is in plain text
"Config": {
"Hostname": "e1fe8eb2d995",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3000/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"APIKEY=1234", //
Now you may say someone needs to have root access to view this information but maybe there is a better way we can mitigate this by maybe using a Token. This is where a secret key management comes in to help in storing your secrets. In the next blog post we will go over what Vault is and how it helps us in storing secrets and exposing a token for our docker container to consume without us exposing the APIKEY.
The source code of this can be found at https://github.com/taswar/nodejs-weather-app