Merge pull request #28 from jdrouet/express-mysql
react-express-mysql: fetch version from mysql
This commit is contained in:
commit
a06e22defb
1
react-express-mysql/.gitignore
vendored
Normal file
1
react-express-mysql/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
@ -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" ]
|
||||||
|
18
react-express-mysql/backend/healthcheck.js
vendored
18
react-express-mysql/backend/healthcheck.js
vendored
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
78
react-express-mysql/backend/index.js
vendored
78
react-express-mysql/backend/index.js
vendored
@ -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;
|
|
668
react-express-mysql/backend/package-lock.json
generated
668
react-express-mysql/backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||||
|
20
react-express-mysql/backend/src/config.js
vendored
Normal file
20
react-express-mysql/backend/src/config.js
vendored
Normal 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 :)
|
||||||
|
};
|
7
react-express-mysql/backend/src/database.js
vendored
Normal file
7
react-express-mysql/backend/src/database.js
vendored
Normal 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
48
react-express-mysql/backend/src/index.js
vendored
Executable 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
|
||||||
|
//
|
36
react-express-mysql/backend/src/server.js
vendored
Normal file
36
react-express-mysql/backend/src/server.js
vendored
Normal 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;
|
49
react-express-mysql/backend/test/sample.js
vendored
49
react-express-mysql/backend/test/sample.js
vendored
@ -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();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user