Merge pull request #28 from jdrouet/express-mysql

react-express-mysql: fetch version from mysql
This commit is contained in:
Guillaume LOURS 2020-03-24 15:15:12 +01:00 committed by GitHub
commit a06e22defb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 672 additions and 306 deletions

1
react-express-mysql/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -1,36 +1,31 @@
# if you're doing anything beyond your local machine, please pin this to a specific version at https://hub.docker.com/_/node/ # 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 FROM node:lts
RUN mkdir -p /opt/app
# set our node environment, either development or production # set our node environment, either development or production
# defaults to production, compose overrides this to development on build and run # defaults to production, compose overrides this to development on build and run
ARG NODE_ENV=production ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV ENV NODE_ENV $NODE_ENV
WORKDIR /code
# default to port 80 for node, and 9229 and 9230 (tests) for debug # default to port 80 for node, and 9229 and 9230 (tests) for debug
ARG PORT=80 ARG PORT=80
ENV PORT $PORT ENV PORT $PORT
EXPOSE $PORT 9229 9230 EXPOSE $PORT 9229 9230
# you'll likely want the latest npm, reguardless of node version, for speed and fixes COPY package.json /code/package.json
RUN npm i npm@latest -g COPY package-lock.json /code/package-lock.json
RUN npm ci
# 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 # check every 30s to ensure this service returns HTTP 200
HEALTHCHECK --interval=30s CMD node healthcheck.js HEALTHCHECK --interval=30s \
CMD node healthcheck.js
# copy in our source code last, as it changes the most # copy in our source code last, as it changes the most
WORKDIR /opt/app COPY . /code
COPY . /opt/app
# if you want to use npm start instead, then use `docker run --init in production` # 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 # 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 # 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 # I still can't come up with a good production way to run with npm and graceful shutdown
CMD [ "node", "index.js" ] CMD [ "node", "src/index.js" ]

View File

@ -1,20 +1,20 @@
var http = require("http"); const http = require("http");
var options = { const options = {
timeout: 2000, timeout: 2000,
host: 'localhost', host: "localhost",
port: process.env.PORT || 8080, port: process.env.PORT || 8080,
path: '/healthz' // must be the same as HEALTHCHECK in Dockerfile path: "/healthz" // must be the same as HEALTHCHECK in Dockerfile
}; };
var request = http.request(options, (res) => { const request = http.request(options, res => {
console.info('STATUS: ' + res.statusCode); console.info("STATUS: " + res.statusCode);
process.exitCode = (res.statusCode === 200) ? 0 : 1; process.exitCode = res.statusCode === 200 ? 0 : 1;
process.exit(); process.exit();
}); });
request.on('error', function(err) { request.on("error", function(err) {
console.error('ERROR', err); console.error("ERROR", err);
process.exit(1); process.exit(1);
}); });

View File

@ -1,78 +0,0 @@
// 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.json({ message: 'Hello Docker World!' });
});
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;

File diff suppressed because it is too large Load Diff

View File

@ -4,20 +4,20 @@
"version": "2.0.0", "version": "2.0.0",
"description": "Node.js Hello world app using docker features for easy docker-compose local dev and solid production defaults", "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>", "author": "Bret Fisher <bret@bretfisher.com>",
"main": "index.js", "main": "src/index.js",
"scripts": { "scripts": {
"start": "node index.js", "start": "node src/index.js",
"dev-docker": "../node_modules/nodemon/bin/nodemon.js --debug=5858", "start-watch": "nodemon src/index.js --inspect=0.0.0.0:9229",
"dev-host": "nodemon --debug=5858", "start-wait-debuger": "nodemon src/index.js --inspect-brk=0.0.0.0:9229",
"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": "cross-env NODE_ENV=test PORT=8081 mocha --timeout 10000 --exit --inspect=0.0.0.0:9230",
"test-watch": "nodemon --exec \"npm test\"", "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" "test-wait-debuger": "cross-env NODE_ENV=test PORT=8081 mocha --no-timeouts --exit --inspect-brk=0.0.0.0:9230"
}, },
"dependencies": { "dependencies": {
"express": "^4.16.3", "express": "^4.16.3",
"morgan": "^1.8.1" "knex": "^0.20.13",
"morgan": "^1.8.1",
"mysql2": "^2.1.0"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.1.2", "chai": "^4.1.2",

View File

@ -0,0 +1,20 @@
const fs = require("fs");
const readFileSync = filename => fs.readFileSync(filename).toString("utf8");
// Constants
module.exports = {
database: {
host: process.env.DATABASE_HOST || "localhost",
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_DB,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD
? readFileSync(process.env.DATABASE_PASSWORD)
: null
},
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 :)
};

View File

@ -0,0 +1,7 @@
const knex = require('knex');
const { database } = require('./config');
module.exports = knex({
client: 'mysql2',
connection: database,
});

48
react-express-mysql/backend/src/index.js vendored Executable file
View File

@ -0,0 +1,48 @@
const app = require("./server");
const { port } = require("./config");
const 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.exit(1);
}
process.exit(0);
});
}
//
// need above in docker container to properly exit
//

View File

@ -0,0 +1,36 @@
// simple node web server that displays hello world
// optimized for Docker image
const 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.
const 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.
const database = require("./database");
// Appi
const app = express();
app.use(morgan("common"));
app.get("/", function(req, res, next) {
database.raw('select VERSION() version')
.then(([rows, columns]) => rows[0])
.then((row) => res.json({ message: `Hello from MySQL ${row.version}` }))
.catch(next);
});
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");
});
module.exports = app;

View File

@ -1,32 +1,33 @@
const app = require('../index'); const chai = require("chai");
const chaiHttp = require("chai-http");
const chai = require('chai'); const app = require("../src/server");
const chaiHttp = require('chai-http');
chai.use(chaiHttp); chai.use(chaiHttp);
chai.should(); chai.should();
describe('API /healthz', () => { describe("API /healthz", () => {
it('it should return 200', (done) => { it("it should return 200", done => {
chai.request(app) chai
.get('/healthz') .request(app)
.end((err, res) => { .get("/healthz")
res.should.have.status(200); .end((err, res) => {
done(); res.should.have.status(200);
}); done();
}); });
});
}); });
describe('API /', () => { describe("API /", () => {
it('it should return Welcome message', (done) => { it("it should return Welcome message", done => {
chai.request(app) chai
.get('/') .request(app)
.end((err, res) => { .get("/")
res.should.have.status(200); .end((err, res) => {
res.should.to.be.html; res.should.have.status(200);
res.text.should.be.equal("Hello Docker World\n"); res.should.to.be.html;
done(); res.text.should.be.equal("Hello Docker World\n");
}); done();
}); });
});
}); });

View File

@ -5,17 +5,23 @@ services:
args: args:
- NODE_ENV=development - NODE_ENV=development
context: backend context: backend
command: ../node_modules/.bin/nodemon --inspect=0.0.0.0:9229 command: npm run start-watch
environment: environment:
- DATABASE_DB=example
- DATABASE_USER=root
- DATABASE_PASSWORD=/run/secrets/db-password
- DATABASE_HOST=db
- NODE_ENV=development - NODE_ENV=development
ports: ports:
- 80:80 - 80:80
- 9229:9229 - 9229:9229
- 9230:9230 - 9230:9230
secrets:
- db-password
volumes: volumes:
- ./backend:/opt/app:delegated - ./backend/src:/code/src:ro
- ./backend/package.json:/opt/package.json - ./backend/package.json:/code/package.json
- ./backend/package-lock.json:/opt/package-lock.json - ./backend/package-lock.json:/code/package-lock.json
- back-notused:/opt/app/node_modules - back-notused:/opt/app/node_modules
networks: networks:
- public - public