-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
247 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
server/.env* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
## `docker` Flavor | ||
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. | ||
|
||
## Basics | ||
This [Dockerfile](./server/Dockerfile) uses | ||
[multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) | ||
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` wervice uses | ||
the `release` Dockerfile stage, and the `test` service uses the `test` Dockerfile stage. | ||
|
||
### `docker-compose.yml` Services | ||
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. | ||
|
||
#### `web_base` | ||
All configuration for running the webserver locally, minus the `volumes` block. | ||
|
||
#### `web` | ||
`web_base`, plus the `volumes` block required for hotreloading to function locally. | ||
|
||
#### `test_base` | ||
All configuration for running the tests, minus the `volumes` block. | ||
|
||
#### `test` | ||
`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. | ||
|
||
### Commands | ||
|
||
#### `npm run build:test` | ||
Rebuilds the `test` service used for running tests, and will re-install npm | ||
dependencies when they change. | ||
|
||
#### `npm run build:web` | ||
Rebuilds the `web` service used locally, and will re-install npm dependencies when | ||
they change. | ||
|
||
#### `npm run docker:lint` | ||
Runs the `npm run lint` command in the `test` service. | ||
|
||
#### `npm run docker:start` | ||
Starts the `web` service in daemon mode, making it available at `localhost:3000`. | ||
|
||
#### `npm run docker:test` | ||
Runs the `npm test` command in the `test` service. | ||
|
||
#### `npm run docker:test:ci` | ||
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. | ||
|
||
### `.env` | ||
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](https://docs.docker.com/compose/compose-file/#env_file). | ||
|
||
### Stages | ||
There are currently four stages in the Dockerfile that are used. | ||
|
||
#### `base` | ||
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. | ||
|
||
#### `dependencies` | ||
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`. | ||
|
||
#### `test` | ||
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. | ||
|
||
#### `development` | ||
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. | ||
|
||
#### `release` | ||
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. | ||
|
||
## Local Development | ||
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 | ||
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. | ||
|
||
### Secret Management (`.env`) | ||
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. | ||
|
||
## Changing the Port | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
version: '3.4' | ||
services: | ||
web_base: &web_base | ||
build: | ||
context: . | ||
dockerfile: server/Dockerfile | ||
target: development | ||
command: [ | ||
"./node_modules/.bin/nodemon", | ||
"--watch", | ||
"lib", | ||
"--watch", | ||
"server", | ||
"server/index.js" | ||
] | ||
environment: | ||
- NODE_ENV=development | ||
ports: | ||
- 3000:3000 | ||
web: | ||
# hack for docker-compose v3 dropping `extends` support | ||
<< : *web_base | ||
# allows for hot-reloading of server | ||
volumes: | ||
- ./lib:/app/lib | ||
- ./server:/app/server | ||
- ./test:/app/test | ||
- ./package.json:/app/package.json | ||
test_base: &test_base | ||
build: | ||
context: . | ||
dockerfile: server/Dockerfile | ||
target: test | ||
test: | ||
# hack for docker-compose v3 dropping `extends` support | ||
<< : *test_base | ||
# allows for hot-reloading of server | ||
volumes: | ||
- ./lib:/app/lib | ||
- ./server:/app/server | ||
- ./test:/app/test | ||
- ./package.json:/app/package.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# create base image with all packages, proper entrypoint, and directories created | ||
FROM node:14-alpine AS base | ||
|
||
# install any packages we need from apt here | ||
RUN apk add --update dumb-init | ||
|
||
# set entrypoint to `dumb-init` as it handles being pid 1 and forwarding signals | ||
# so that you dont need to bake that logic into your node app | ||
ENTRYPOINT ["dumb-init", "--"] | ||
|
||
# all of our code will live in `/app` | ||
WORKDIR /app | ||
|
||
# using the base image, create an image containing all of our files | ||
# and dependencies installed, devDeps and test directory included | ||
FROM base AS dependencies | ||
|
||
COPY package*.json ./ | ||
RUN npm set progress=false \ | ||
&& npm config set depth 0 \ | ||
&& npm i | ||
|
||
COPY .eslintrc.json . | ||
COPY ./server ./server | ||
COPY ./test ./test | ||
COPY ./lib ./lib | ||
|
||
# if you have any build scripts to run, like for the `templated-site` flavor | ||
# uncomment and possibly modify the following RUN command: | ||
# RUN npm run build | ||
# keeping all of the bash commands you can within a single RUN is generally important, | ||
# but for this case it's likely that we want to use the cache from the prune which will | ||
# change infrequently. | ||
|
||
# test running image using all of the files and devDeps | ||
FROM dependencies AS test | ||
ENV NODE_ENV=test | ||
# use `sh -c` so we can chain test commands using `&&` | ||
CMD ["npm", "test"] | ||
|
||
# dev ready image, contains devDeps for test running and debugging | ||
FROM dependencies AS development | ||
|
||
# expose port 3000 from in the container to the outside world | ||
# this is the default port defined in server/manifest.js, and | ||
# will need to be updated if you change the default port | ||
EXPOSE 3000 | ||
CMD ["npm", "start"] | ||
|
||
# release ready image, devDeps are pruned and tests removed for size control | ||
FROM development AS release | ||
|
||
ENV NODE_ENV=production | ||
|
||
# prune non-prod dependencies, remove test files | ||
RUN npm prune --production \ | ||
&& rm -rf ./test | ||
|
||
# `node` user is created in base node image | ||
# we want to use this non-root user for running the server in case of attack | ||
# https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user | ||
USER node |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters