Exercise: containerising a Node.js webserver
- Create a simple Node.js web server
- Create
index.js
to expose a web server on port 3030// content of index.js const http = require('http'); const port = 3030; const requestHandler = (request, response) => { console.log(request.url); response.end('Hello Node.js Server!'); }; const server = http.createServer(requestHandler); server.listen(port, (err) => { if (err) { return console.log('something bad happened', err); } console.log(`server is listening on ${port}`); });
- Test locally
- Install
package.json
usingnpm install
- Start using
npm start
curl localhost:3030
or open in local browser- Terminate local service after testing
- Install
- Create
- Write a
Dockerfile
to:- Use a Node.js base image
- Copy package.json over to image and
npm install
at build time - Run
npm start
at container start time EXPOSE
port 3030 from the container
- Instantiate this image and connect to your container
- Verify that you can connect to the web service from within the container
- Use
docker container ls
to show exposed ports for running containers - Verify that you can connect to the web service from outside the container
- e.g. on host machine
- Capture all your commands in scripts (good IAC practice)
- Run your container as a non-root user, e.g. user
1000
- Modify your container to run all processes as user
1000
- Set appropriate file permissions to enable access to your non-root user
- Modify your container to run all processes as user
The solution to the ‘containerising’ exercise is available as part of our open-source Devops-Workstream.
Exercise: augment existing Dockerfile
- Create a
Dockerfile
that augments the existing NGINX Dockerfile- Use the
FROM
keyword to reference the latest nginx
- Use the
- Install an additional package such as procps (for
ps
commands)- using the package manager built into your chosen distribution
- Copy a local nginx.conf file into your container
- You might base your configuration on a simplified version of this Nginx Example Configuration
- Alternatively see solution for sample config
- You might base your configuration on a simplified version of this Nginx Example Configuration
- Copy a local website into your container
- A single
index.html
file will suffice, but you can enrich it if you’d like
- A single
- Run NGINX as a non-root user, e.g. user
1000
- Hint: you’ll need to direct NGINX to use /tmp subfolder for all writable outputs
The solution to the ‘augment’ exercise is available as part of our open-source Devops-Workstream.
Exercise: environment variables
- Build on the ‘containerising’ exercise to pass in a
PORT
environment variable- Extend the Node.js code to look for the
PORT
environment variable- Add to package.json
... "main": "src/index.js", "dependencies": { "dotenv": "^8.2.0", "nodemon": "^2.0.1" }, ...
- Add to package.json
- Modify the
index.js
to accept an environment variable, but fall back to a default if absent... const http = require('http'); const env = require('process').env; require('dotenv').config(); const port = env.PORT || 8080; ...
- Extend the Node.js code to look for the
- Initially don’t set a environment value for port
- Test to see if it’s exposed on 8080, both in the container and to the host
- Set a value for the environment variable in
Dockerfile
- Connect into the machine and
echo $PORT
to see environment value - Retest access on 8080 and your new value, both in the container and to the host
- Hint: use
docker container ls
to see what your container exposes by default
- Hint: use
- Connect into the machine and
- Set a value for
PORT
in thedocker run
command that you use to instantiate your container- Retest access again
The solution to the ‘environment variables’ exercise is available as part of our open-source Devops-Workstream.
Exercise: volumes
- Build on the ‘augment’ exercise to share volumes into your container
- Instead of using
COPY
to make a duplicate of yournginx.conf
- mount the file as a volume
- Instead of using
- Try modifying your config then restarting your container
- Hint: you can use
docker logs <container_name>
to see start-up logs from NGINX
- Hint: you can use
- Repeat this process for the local website you made previously
- Instead of using
COPY
to make a duplicate of your local website- mount the directory as a volume
- Instead of using
- Modify your local website and restart your container
The solution to the ‘volumes’ exercise is available as part of our open-source Devops-Workstream.
Exercise: docker-compose
- Write a
docker-compose.yml
file to bring up an ELK stack, using container images:- Elasticsearch
docker.elastic.co/elasticsearch/elasticsearch:7.10.0
- Logstash
docker.elastic.co/logstash/logstash:7.10.0
- Kibana
docker.elastic.co/kibana/kibana:7.10.0
- Elasticsearch
- Bring your stack up using
docker-compose up
- You might choose to run that in a separate process (using
&
) to avoid blocking your command prompt
- You might choose to run that in a separate process (using
- Pass an environment variable to Elasticsearch:
discovery.type=single-node
- Expose port
9200
for Elasticsearch and5601
for Kibana- Test internal (in-container) and external (on-guest) access to both services
- Ensure that Elasticsearch spins-up before Logstash and Kibana using the
depends_on
relationship
The solution to the ‘docker-compose’ exercise is available as part of our open-source Devops-Workstream.
Leave a comment