This flavor of the pal boilerplate is designed to get someone up and running
using Docker with scalable best practices. Certain features require the deployment
flavor of the pal boilerplate to be installed as well in order to function.
This Dockerfile uses multi-stage builds to create different Docker images depending on the environment the images will be running in, while ensuring best practices are followed to keep image size low and create a security sandbox if you are running a server.
We are using Docker Compose to define web
and test
services. The web
service uses
the release
Dockerfile stage, and the test
service uses the test
Dockerfile stage.
The docker-compose.yml
file defines four services. The reason for the *_base
services
is that certain CI providers like CircleCI do not support voluming in files, and you will
get strange file system errors if you try to run with a volumes
block.
All configuration for running the webserver locally, minus the volumes
block.
web_base
, plus the volumes
block required for hotreloading to function locally.
All configuration for running the tests, minus the volumes
block.
test_base
, plus the volumes
block required to allow re-running tests in
watch
mode or by hand, but without requiring a full image rebuild.
Rebuilds the test
service used for running tests, and will re-install npm
dependencies when they change.
Rebuilds the web
service used locally, and will re-install npm dependencies when
they change.
Runs the npm run lint
command in the test
service.
Starts the web
service in daemon mode, making it available at localhost:3000
.
Runs the npm test
command in the test
service.
Starts the test_base
service, which triggers both a lint
and test
npm script
run. The process will exit with the same code the internal process exits with,
making this the ideal command to use when integrating with CI.
This flavor no longer uses .env
files, as it is safer to start the container declaring
the environment variables in either the docker-compose.yml
file or via the docker
cli.
If you need to add any environment variables, you can do so in the docker-compose.yml
files as shown, or add them to .env
and load them in as shown
here.
There are currently four stages in the Dockerfile that are used.
Contains all package installs, files system modifications, and entrypoint declaration. Any commands that will not change across the other stages or are required for multiple other stages to execute properly should be put in this stage.
The dependencies
stage is used to install npm dependencies, copy all of your source
files, and then optionally run any build commands that need to be executed. The desired
outcome of this stage is an image that contains all dependencies, all source files, and
all built assets (if necessary).
In order to run build scripts, you will need to locate this stage in the Dockerfile
and uncomment the RUN npm run build
command that is in there, possibly changing the
command if you are using multiple build scripts in your package.json
.
The test
stage is used for running your test suite. It changes the user to node
to mimic the production environment, and then runs npm lint && npm test
which should
run your full test suite. The container will exit with the same code as your test
runner, which means that in CI you can run npm run docker:test:ci
as your test step to
automatically build your test image and then run your tests inside of it.
The development
stage is meant to run your server locally with dev deps installed. The
docker-compose.yml
file can be used to tweak the environment variables used for
this stage when running locally, and the logic for building this stage should not
make any assumptions about what environment the output will be used in.
The release
stage is meant to run your server in a production-like setup without dev deps.
The docker-compose.yml
file can be used to tweak the environment variables used for
this stage when running locally, and the logic for building this stage should not
make any assumptions about what environment the output will be used in.
If you are using the development
flavor alongside this docker
flavor, you can simply
run npm run docker:start
to build the release stage of the Dockerfile, and then start
it as a daemon
in Docker. You can then visit localhost:3000
to hit your server.
By default, the server is started using nodemon
when you start it using
docker-compose
, which means every time you save a file the server will be restarted
automatically with your fresh changes.
Running tests locally is extremely easy. Simply run npm run docker:test
, and linting
and testing will be run. If you modify the package*.json
files, you will need to run
npm run build:test
to trigger a reinstall of your dependencies.
This removes the option to have a .env
files for secrets locally, because those environment
variables can now just be set in the docker-compose.yml
file environment
section. If
you have true secrets that you need locally and cannot check into Git, you can re-create
the server/.env
file, and then add a key in the *_base
services in docker-compose.yml
that is simply env_file: server/.env
at the same level in the yaml as the environment
key.
Currently the build process assumes that the port default of 3000
in
server/manifest.js
is being used. server/Dockerfile
has an EXPOSE
command that
references this port, and docker-compose.yml
also contains a mapping of port 3000
in the container to port 3000
on the host machine.