mirror of
https://github.com/docker/awesome-compose.git
synced 2025-04-29 07:38:02 +02:00
add react-express-mysql application sample
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
This commit is contained in:
parent
0d06c37791
commit
43f21f2d8d
46 changed files with 4786 additions and 0 deletions
36
samples/react-express-mysql/backend/Dockerfile
Executable file
36
samples/react-express-mysql/backend/Dockerfile
Executable file
|
@ -0,0 +1,36 @@
|
|||
# if you're doing anything beyond your local machine, please pin this to a specific version at https://hub.docker.com/_/node/
|
||||
FROM node:10
|
||||
|
||||
RUN mkdir -p /opt/app
|
||||
|
||||
# set our node environment, either development or production
|
||||
# defaults to production, compose overrides this to development on build and run
|
||||
ARG NODE_ENV=production
|
||||
ENV NODE_ENV $NODE_ENV
|
||||
|
||||
# default to port 80 for node, and 9229 and 9230 (tests) for debug
|
||||
ARG PORT=80
|
||||
ENV PORT $PORT
|
||||
EXPOSE $PORT 9229 9230
|
||||
|
||||
# you'll likely want the latest npm, reguardless of node version, for speed and fixes
|
||||
RUN npm i npm@latest -g
|
||||
|
||||
# install dependencies first, in a different location for easier app bind mounting for local development
|
||||
WORKDIR /opt
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm install && npm cache clean --force
|
||||
ENV PATH /opt/node_modules/.bin:$PATH
|
||||
|
||||
# check every 30s to ensure this service returns HTTP 200
|
||||
HEALTHCHECK --interval=30s CMD node healthcheck.js
|
||||
|
||||
# copy in our source code last, as it changes the most
|
||||
WORKDIR /opt/app
|
||||
COPY . /opt/app
|
||||
|
||||
# if you want to use npm start instead, then use `docker run --init in production`
|
||||
# so that signals are passed properly. Note the code in index.js is needed to catch Docker signals
|
||||
# using node here is still more graceful stopping then npm with --init afaik
|
||||
# I still can't come up with a good production way to run with npm and graceful shutdown
|
||||
CMD [ "node", "index.js" ]
|
21
samples/react-express-mysql/backend/LICENSE
Executable file
21
samples/react-express-mysql/backend/LICENSE
Executable file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2015-2017 Bret Fisher
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
86
samples/react-express-mysql/backend/README.md
Executable file
86
samples/react-express-mysql/backend/README.md
Executable file
|
@ -0,0 +1,86 @@
|
|||
## Node + Docker Hello World, for Showing Good Defaults for Using Node.js in Docker
|
||||
|
||||
> This tries to be a "good defaults" example of using Node.js in Docker for local development and shipping to production with all the bells, whistles, and best practices. Issues/PR welcome.
|
||||
|
||||
### Local Development Features
|
||||
|
||||
- **Dev as close to prod as you can**. docker-compose builds a local development image that is just like production image except for the below dev-only features needed in image. Goal is to have dev env be as close to test and prod as possible while still giving all the nice tools to make you a happy dev.
|
||||
- **Prevent needing node/npm on host**. Installs `node_modules` outside app root in container so local development won't run into a problem of bind-mounting over it with local source code. This means it will run `npm install` once on container build and you don't need to run npm on host or on each docker run. It will re-run on build if you change `package.json`.
|
||||
- **One line startup**. Uses `docker-compose up` for single-line build and run of local development server.
|
||||
- **Edit locally while code runs in container**. docker-compose uses proper bind-mounts of host source code into container so you can edit locally while running code in Linux container.
|
||||
- **Use nodemon in container**. docker-compose uses nodemon for development for auto-restarting node in container when you change files on host.
|
||||
- **Enable debug from host to container**. opens the inspect port 9229 for using host-based debugging like chrome tools or VS Code. Nodemon enables `--inspect` by default in docker-compose.
|
||||
- **Provides VSCode debug configs and tasks for tests**. for Visual Studio Code fans, `.vscode` directory has the goods, thanks to @JPLemelin.
|
||||
- **Small image and quick re-builds**. `COPY` in `package.json` and run `npm install` **before** `COPY` in your source code. This saves big on build time and keep container lean.
|
||||
- **Bind-mount package.json**. This allows adding packages in realtime without rebuilding images. e.g. `dce node npm install --save <package name>`
|
||||
|
||||
|
||||
### Production-minded Features
|
||||
|
||||
- **Use Docker build-in healthchecks**. uses Dockerfile `HEALTHCHECK` with `/healthz` route to help Docker know if your container is running properly (example always returns 200, but you get the idea).
|
||||
- **Proper NODE_ENV use**. Defaults to `NODE_ENV=production` in Dockerfile and overrides to `development` in docker-compose for local dev.
|
||||
- **Don't add dev dependencies into production image**. Proper `NODE_ENV` use means dev dependencies won't be installed in container by default. Using docker-compose will build with them by default.
|
||||
- **Enables proper SIGTERM/SIGINT for graceful exit**. Defaults to `node index.js` rather then npm for allowing graceful shutdown of node. npm doesn't pass SIGTERM/SIGINT properly (you can't ctrl-c when running `docker run` in foreground). To get `node index.js` to graceful exit, extra signal-catching code is needed. The `Dockerfile` and `index.js` document the options and links to known issues.
|
||||
- **Use docker-stack.yml example for Docker Swarm deployments**.
|
||||
|
||||
|
||||
### Assumptions
|
||||
|
||||
- You have Docker and Docker-Compose installed (Docker for Mac, Docker for Windows, get.docker.com and manual Compose installed for Linux).
|
||||
- You want to use Docker for local development (i.e. never need to install node/npm on host) and have dev and prod Docker images be as close as possible.
|
||||
- You don't want to loose fidelity in your dev workflow. You want a easy environment setup, using local editors, node debug/inspect, local code repo, while node server runs in a container.
|
||||
- You use `docker-compose` for local development only (docker-compose was never intended to be a production deployment tool anyway).
|
||||
- The `docker-compose.yml` is not meant for `docker stack deploy` in Docker Swarm, it's meant for happy local development. Use `docker-stack.yml` for Swarm.
|
||||
|
||||
|
||||
### Getting Started
|
||||
|
||||
If this was your Node.js app, to start local development you would:
|
||||
|
||||
- Running `docker-compose up` is all you need. It will:
|
||||
- Build custom local image enabled for development (nodemon, `NODE_ENV=development`).
|
||||
- Start container from that image with ports 80 and 9229 open (on localhost).
|
||||
- Starts with `nodemon` to restart node on file change in host pwd.
|
||||
- Mounts the pwd to the app dir in container.
|
||||
- If you need other services like databases, just add to compose file and they'll be added to the custom Docker network for this app on `up`.
|
||||
- Compose should detect if you need to rebuild due to changed package.json or Dockerfile, but `docker-compose build` works for manually building.
|
||||
- Be sure to use `docker-compose down` to cleanup after your done dev'ing.
|
||||
|
||||
If you wanted to add a package while docker-compose was running your app:
|
||||
- `docker-compose exec node npm install --save <package name>`
|
||||
- This installs it inside the running container.
|
||||
- Nodemon will detect the change and restart.
|
||||
- `--save` will add it to the package.json for next `docker-compose build`
|
||||
|
||||
To execute the unit-tests, you would:
|
||||
- Execute `docker-compose exec node npm test`, It will:
|
||||
- Run a process `npm test` in the container node.
|
||||
- You can use the *vscode* to debug unit-tests with config `Docker Test (Attach 9230 --inspect)`, It will:
|
||||
- Start a debugging process in the container and wait-for-debugger, this is done by *vscode tasks*
|
||||
- It will also kill previous debugging process if existing.
|
||||
|
||||
### Other Resources
|
||||
|
||||
- https://blog.hasura.io/an-exhaustive-guide-to-writing-dockerfiles-for-node-js-web-apps-bbee6bd2f3c4
|
||||
|
||||
MIT License,
|
||||
|
||||
Copyright (c) 2015-2018 Bret Fisher
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
21
samples/react-express-mysql/backend/healthcheck.js
vendored
Executable file
21
samples/react-express-mysql/backend/healthcheck.js
vendored
Executable file
|
@ -0,0 +1,21 @@
|
|||
var http = require("http");
|
||||
|
||||
var options = {
|
||||
timeout: 2000,
|
||||
host: 'localhost',
|
||||
port: process.env.PORT || 8080,
|
||||
path: '/healthz' // must be the same as HEALTHCHECK in Dockerfile
|
||||
};
|
||||
|
||||
var request = http.request(options, (res) => {
|
||||
console.info('STATUS: ' + res.statusCode);
|
||||
process.exitCode = (res.statusCode === 200) ? 0 : 1;
|
||||
process.exit();
|
||||
});
|
||||
|
||||
request.on('error', function(err) {
|
||||
console.error('ERROR', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
request.end();
|
78
samples/react-express-mysql/backend/index.js
vendored
Executable file
78
samples/react-express-mysql/backend/index.js
vendored
Executable file
|
@ -0,0 +1,78 @@
|
|||
// simple node web server that displays hello world
|
||||
// optimized for Docker image
|
||||
|
||||
var express = require('express');
|
||||
// this example uses express web framework so we know what longer build times
|
||||
// do and how Dockerfile layer ordering matters. If you mess up Dockerfile ordering
|
||||
// you'll see long build times on every code change + build. If done correctly,
|
||||
// code changes should be only a few seconds to build locally due to build cache.
|
||||
|
||||
var morgan = require('morgan');
|
||||
// morgan provides easy logging for express, and by default it logs to stdout
|
||||
// which is a best practice in Docker. Friends don't let friends code their apps to
|
||||
// do app logging to files in containers.
|
||||
|
||||
// Constants
|
||||
const PORT = process.env.PORT || 8080;
|
||||
// if you're not using docker-compose for local development, this will default to 8080
|
||||
// to prevent non-root permission problems with 80. Dockerfile is set to make this 80
|
||||
// because containers don't have that issue :)
|
||||
|
||||
// Appi
|
||||
var app = express();
|
||||
|
||||
app.use(morgan('common'));
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('Hello Docker World\n');
|
||||
});
|
||||
|
||||
app.get('/healthz', function (req, res) {
|
||||
// do app logic here to determine if app is truly healthy
|
||||
// you should return 200 if healthy, and anything else will fail
|
||||
// if you want, you should be able to restrict this to localhost (include ipv4 and ipv6)
|
||||
res.send('I am happy and healthy\n');
|
||||
});
|
||||
|
||||
var server = app.listen(PORT, function () {
|
||||
console.log('Webserver is ready');
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// need this in docker container to properly exit since node doesn't handle SIGINT/SIGTERM
|
||||
// this also won't work on using npm start since:
|
||||
// https://github.com/npm/npm/issues/4603
|
||||
// https://github.com/npm/npm/pull/10868
|
||||
// https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
|
||||
// if you want to use npm then start with `docker run --init` to help, but I still don't think it's
|
||||
// a graceful shutdown of node process
|
||||
//
|
||||
|
||||
// quit on ctrl-c when running docker in terminal
|
||||
process.on('SIGINT', function onSigint () {
|
||||
console.info('Got SIGINT (aka ctrl-c in docker). Graceful shutdown ', new Date().toISOString());
|
||||
shutdown();
|
||||
});
|
||||
|
||||
// quit properly on docker stop
|
||||
process.on('SIGTERM', function onSigterm () {
|
||||
console.info('Got SIGTERM (docker container stop). Graceful shutdown ', new Date().toISOString());
|
||||
shutdown();
|
||||
})
|
||||
|
||||
// shut down server
|
||||
function shutdown() {
|
||||
server.close(function onServerClosed (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
process.exit();
|
||||
})
|
||||
}
|
||||
//
|
||||
// need above in docker container to properly exit
|
||||
//
|
||||
|
||||
module.exports = app;
|
3305
samples/react-express-mysql/backend/package-lock.json
generated
Executable file
3305
samples/react-express-mysql/backend/package-lock.json
generated
Executable file
File diff suppressed because it is too large
Load diff
29
samples/react-express-mysql/backend/package.json
Executable file
29
samples/react-express-mysql/backend/package.json
Executable file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "node-docker-good-defaults",
|
||||
"private": true,
|
||||
"version": "2.0.0",
|
||||
"description": "Node.js Hello world app using docker features for easy docker-compose local dev and solid production defaults",
|
||||
"author": "Bret Fisher <bret@bretfisher.com>",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev-docker": "../node_modules/nodemon/bin/nodemon.js --debug=5858",
|
||||
"dev-host": "nodemon --debug=5858",
|
||||
"start-watch": "nodemon index.js --inspect=0.0.0.0:9229",
|
||||
"start-wait-debuger": "nodemon index.js --inspect-brk=0.0.0.0:9229",
|
||||
"test": "cross-env NODE_ENV=test PORT=8081 mocha --timeout 10000 --exit --inspect=0.0.0.0:9230",
|
||||
"test-watch": "nodemon --exec \"npm test\"",
|
||||
"test-wait-debuger": "cross-env NODE_ENV=test PORT=8081 mocha --no-timeouts --exit --inspect-brk=0.0.0.0:9230"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.16.3",
|
||||
"morgan": "^1.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.1.2",
|
||||
"chai-http": "^4.0.0",
|
||||
"cross-env": "^5.1.4",
|
||||
"mocha": "^5.0.5",
|
||||
"nodemon": "^1.17.5"
|
||||
}
|
||||
}
|
32
samples/react-express-mysql/backend/test/sample.js
vendored
Executable file
32
samples/react-express-mysql/backend/test/sample.js
vendored
Executable file
|
@ -0,0 +1,32 @@
|
|||
const app = require('../index');
|
||||
|
||||
const chai = require('chai');
|
||||
const chaiHttp = require('chai-http');
|
||||
|
||||
chai.use(chaiHttp);
|
||||
chai.should();
|
||||
|
||||
describe('API /healthz', () => {
|
||||
it('it should return 200', (done) => {
|
||||
chai.request(app)
|
||||
.get('/healthz')
|
||||
.end((err, res) => {
|
||||
res.should.have.status(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('API /', () => {
|
||||
it('it should return Welcome message', (done) => {
|
||||
chai.request(app)
|
||||
.get('/')
|
||||
.end((err, res) => {
|
||||
res.should.have.status(200);
|
||||
res.should.to.be.html;
|
||||
res.text.should.be.equal("Hello Docker World\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue