From 661410dc7b87e688b48fad0db49e8291708a81cf Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Tue, 20 Apr 2021 12:53:44 +0200 Subject: [PATCH 1/7] Move docker setup to docker-compose based on alpine-images --- .dockerignore | 3 ++- Dockerfile | 20 ---------------- conf/supervisord.conf | 20 ---------------- docker-compose.yml | 18 +++++++++++++++ docker/client.dockerfile | 13 +++++++++++ .../files/etc/nginx/conf.d/default.conf | 23 +++++++++++-------- docker/server.dockerfile | 19 +++++++++++++++ 7 files changed, 65 insertions(+), 51 deletions(-) delete mode 100644 Dockerfile delete mode 100644 conf/supervisord.conf create mode 100644 docker-compose.yml create mode 100644 docker/client.dockerfile rename conf/nginx.conf => docker/files/etc/nginx/conf.d/default.conf (52%) create mode 100644 docker/server.dockerfile diff --git a/.dockerignore b/.dockerignore index d9810c59..a054123e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,5 @@ node_modules/ deploy/ build/ -db/ \ No newline at end of file +db/ +**/*.test.js diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 078c4a51..00000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM ubuntu:latest -WORKDIR /usr/src/app -ENV PORT 80 - -RUN apt-get update && apt-get install -y curl -RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -RUN apt-get update && apt-get install -y nginx supervisor nodejs -RUN rm -rf /var/lib/apt/lists/* - -COPY package*.json ./ -RUN npm install -COPY . . -COPY conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY conf/nginx.conf /etc/nginx/sites-available/default - -RUN npm run build -RUN cp -a build/. /var/www/html/ - -# add support for $PORT env variable -CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/sites-available/default && /usr/bin/supervisord \ No newline at end of file diff --git a/conf/supervisord.conf b/conf/supervisord.conf deleted file mode 100644 index 32d53395..00000000 --- a/conf/supervisord.conf +++ /dev/null @@ -1,20 +0,0 @@ -[supervisord] -nodaemon=true - -[program:app] -directory=/usr/src/app -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 -command=npm run server - -[program:nginx] -command=/usr/sbin/nginx -g "daemon off;" -priority=900 -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 -username=www-data -autorestart=true \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..1d90008b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3' + +services: + client: + build: + context: . + dockerfile: docker/client.dockerfile + container_name: threats-client + restart: unless-stopped + ports: + - "8080:8080" + + server: + build: + context: . + dockerfile: docker/server.dockerfile + container_name: threats-server + restart: unless-stopped diff --git a/docker/client.dockerfile b/docker/client.dockerfile new file mode 100644 index 00000000..f81a79b7 --- /dev/null +++ b/docker/client.dockerfile @@ -0,0 +1,13 @@ +FROM node:15.14.0-alpine3.13 AS builder +WORKDIR /usr/src/app +COPY package.json ./ +COPY package-lock.json ./ +COPY ./public ./public +COPY ./src ./src +RUN npm ci +RUN npm run build + +FROM nginxinc/nginx-unprivileged:1.18-alpine +COPY docker/files/etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf +COPY --from=builder /usr/src/app/build /usr/share/nginx/html/ +EXPOSE 8080 diff --git a/conf/nginx.conf b/docker/files/etc/nginx/conf.d/default.conf similarity index 52% rename from conf/nginx.conf rename to docker/files/etc/nginx/conf.d/default.conf index 551bc140..eac1bd31 100644 --- a/conf/nginx.conf +++ b/docker/files/etc/nginx/conf.d/default.conf @@ -1,20 +1,23 @@ server { - listen $PORT; - root /var/www/html; - index index.html; - server_name _; - location / { - try_files $uri /index.html; - } + listen 8080; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri /index.html; + } + location /api/ { - proxy_pass http://localhost:8001/; + proxy_pass http://server:8001/; } + location /socket.io/ { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; - proxy_pass http://localhost:8000/socket.io/; + proxy_pass http://server:8000/socket.io/; } -} \ No newline at end of file +} diff --git a/docker/server.dockerfile b/docker/server.dockerfile new file mode 100644 index 00000000..a7fefad3 --- /dev/null +++ b/docker/server.dockerfile @@ -0,0 +1,19 @@ +FROM node:15.14.0-alpine3.13 AS builder +WORKDIR /usr/src/app +COPY package.json ./ +COPY package-lock.json ./ +RUN npm ci +# TODO: installing only production dependencies breaks "node -r esm" +#RUN npm ci --only=production + +FROM node:15.14.0-alpine3.13 +RUN apk add dumb-init +WORKDIR /usr/src/app +RUN chown node:node /usr/src/app +USER node +ENV NODE_ENV production +COPY --chown=node:node --from=builder /usr/src/app/node_modules /usr/src/app/node_modules +# TODO: copy only neccessary files +COPY --chown=node:node ./src /usr/src/app/src +CMD [ "dumb-init", "node", "-r", "esm", "/usr/src/app/src/server.js" ] + From 0fbdb4a1f8544bdf45c0f61428bf84307c5d9803 Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Wed, 21 Apr 2021 08:25:12 +0200 Subject: [PATCH 2/7] Move esm to production dependencies --- docker/server.dockerfile | 4 +--- package.json | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docker/server.dockerfile b/docker/server.dockerfile index a7fefad3..afc8b4bc 100644 --- a/docker/server.dockerfile +++ b/docker/server.dockerfile @@ -2,9 +2,7 @@ FROM node:15.14.0-alpine3.13 AS builder WORKDIR /usr/src/app COPY package.json ./ COPY package-lock.json ./ -RUN npm ci -# TODO: installing only production dependencies breaks "node -r esm" -#RUN npm ci --only=production +RUN npm ci --only=production FROM node:15.14.0-alpine3.13 RUN apk add dumb-init diff --git a/package.json b/package.json index bede18e1..7b764fe9 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.2.2", "private": true, "dependencies": { + "esm": "^3.2.25", "@fortawesome/fontawesome-svg-core": "^1.2.19", "@fortawesome/free-solid-svg-icons": "^5.9.0", "@fortawesome/react-fontawesome": "^0.1.4", @@ -46,7 +47,6 @@ ] }, "devDependencies": { - "esm": "^3.2.25", "supertest": "^4.0.2" }, "jest": { From 8f7f407e1a58c137f30352a1aa41ef64de90502d Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Thu, 29 Apr 2021 10:28:30 +0200 Subject: [PATCH 3/7] Cleanup of the folder structure for the whole repository. The main reason for this is a clearer separation between client and server code. Furthermore, this allows to easily select source code deployed to the docker containers --- docker/server.dockerfile | 7 +- package.json | 3 +- src/App.css | 33 ---- src/{ => client}/components/board/board.css | 0 .../components/board/board.ignoretest.js | 0 src/{ => client}/components/board/board.js | 4 +- .../components/dealtcard/dealtcard.js | 0 .../components/dealtcard/dealtcard.test.js | 0 src/{ => client}/components/deck/deck.js | 2 +- src/{ => client}/components/deck/deck.test.js | 0 src/{ => client}/components/footer/footer.js | 2 +- .../components/footer/footer.test.js | 0 .../components/leaderboard/leaderboard.js | 0 .../leaderboard/leaderboard.test.js | 0 src/{ => client}/components/logo/logo.js | 0 src/{ => client}/components/logo/logo.test.js | 0 src/{ => client}/components/model/model.css | 0 src/{ => client}/components/model/model.js | 0 .../components/sidebar/sidebar.css | 0 .../components/sidebar/sidebar.js | 4 +- .../components/sidebar/sidebar.test.js | 0 src/{ => client}/components/status/status.js | 2 +- .../components/status/status.test.js | 0 .../components/threatbar/threatbar.css | 0 .../components/threatbar/threatbar.js | 2 +- .../components/threatbar/threatbar.test.js | 0 src/{ => client}/jointjs/joint-tm.css | 0 src/{ => client}/jointjs/shapes.js | 0 .../pages/__tests__}/about.test.js | 2 +- .../pages/__tests__/app.test.js} | 2 +- .../pages/__tests__}/create.test.js | 2 +- .../about => client/pages}/about.js | 8 +- src/{App.js => client/pages/app.js} | 6 +- .../create => client/pages}/create.js | 16 +- src/{ => client}/serviceWorker.js | 0 .../about => client/styles}/about.css | 0 src/{ => client/styles}/cards.css | 0 .../create => client/styles}/create.css | 0 src/{ => game/__tests__}/definitions.test.js | 2 +- src/game/{ => __tests__}/eop.test.js | 4 +- src/{ => game}/definitions.js | 0 src/game/eop.js | 6 +- src/index.js | 10 +- src/logo.svg | 7 - src/server.js | 142 ------------------ src/{ => server/__tests__}/config.test.js | 2 +- src/{ => server/__tests__}/server.test.js | 32 ++-- src/{ => server}/config.js | 0 src/server/gameServer.js | 31 ++++ src/server/publicApi.js | 120 +++++++++++++++ src/server/server.js | 12 ++ src/{ => utils/__tests__}/utils.test.js | 4 +- src/{ => utils}/constants.js | 0 src/{ => utils}/utils.js | 0 54 files changed, 225 insertions(+), 242 deletions(-) delete mode 100644 src/App.css rename src/{ => client}/components/board/board.css (100%) rename src/{ => client}/components/board/board.ignoretest.js (100%) rename src/{ => client}/components/board/board.js (96%) rename src/{ => client}/components/dealtcard/dealtcard.js (100%) rename src/{ => client}/components/dealtcard/dealtcard.test.js (100%) rename src/{ => client}/components/deck/deck.js (95%) rename src/{ => client}/components/deck/deck.test.js (100%) rename src/{ => client}/components/footer/footer.js (92%) rename src/{ => client}/components/footer/footer.test.js (100%) rename src/{ => client}/components/leaderboard/leaderboard.js (100%) rename src/{ => client}/components/leaderboard/leaderboard.test.js (100%) rename src/{ => client}/components/logo/logo.js (100%) rename src/{ => client}/components/logo/logo.test.js (100%) rename src/{ => client}/components/model/model.css (100%) rename src/{ => client}/components/model/model.js (100%) rename src/{ => client}/components/sidebar/sidebar.css (100%) rename src/{ => client}/components/sidebar/sidebar.js (93%) rename src/{ => client}/components/sidebar/sidebar.test.js (100%) rename src/{ => client}/components/status/status.js (97%) rename src/{ => client}/components/status/status.test.js (100%) rename src/{ => client}/components/threatbar/threatbar.css (100%) rename src/{ => client}/components/threatbar/threatbar.js (99%) rename src/{ => client}/components/threatbar/threatbar.test.js (100%) rename src/{ => client}/jointjs/joint-tm.css (100%) rename src/{ => client}/jointjs/shapes.js (100%) rename src/{components/about => client/pages/__tests__}/about.test.js (91%) rename src/{App.test.js => client/pages/__tests__/app.test.js} (91%) rename src/{components/create => client/pages/__tests__}/create.test.js (90%) rename src/{components/about => client/pages}/about.js (97%) rename src/{App.js => client/pages/app.js} (84%) rename src/{components/create => client/pages}/create.js (95%) rename src/{ => client}/serviceWorker.js (100%) rename src/{components/about => client/styles}/about.css (100%) rename src/{ => client/styles}/cards.css (100%) rename src/{components/create => client/styles}/create.css (100%) rename src/{ => game/__tests__}/definitions.test.js (86%) rename src/game/{ => __tests__}/eop.test.js (97%) rename src/{ => game}/definitions.js (100%) delete mode 100644 src/logo.svg delete mode 100644 src/server.js rename src/{ => server/__tests__}/config.test.js (90%) rename src/{ => server/__tests__}/server.test.js (76%) rename src/{ => server}/config.js (100%) create mode 100644 src/server/gameServer.js create mode 100644 src/server/publicApi.js create mode 100644 src/server/server.js rename src/{ => utils/__tests__}/utils.test.js (96%) rename src/{ => utils}/constants.js (100%) rename src/{ => utils}/utils.js (100%) diff --git a/docker/server.dockerfile b/docker/server.dockerfile index afc8b4bc..62a6ea4f 100644 --- a/docker/server.dockerfile +++ b/docker/server.dockerfile @@ -11,7 +11,8 @@ RUN chown node:node /usr/src/app USER node ENV NODE_ENV production COPY --chown=node:node --from=builder /usr/src/app/node_modules /usr/src/app/node_modules -# TODO: copy only neccessary files -COPY --chown=node:node ./src /usr/src/app/src -CMD [ "dumb-init", "node", "-r", "esm", "/usr/src/app/src/server.js" ] +COPY --chown=node:node ./src/server /usr/src/app/src/server +COPY --chown=node:node ./src/game /usr/src/app/src/game +COPY --chown=node:node ./src/utils /usr/src/app/src/utils +CMD [ "dumb-init", "node", "-r", "esm", "/usr/src/app/src/server/server.js" ] diff --git a/package.json b/package.json index 7b764fe9..484048b3 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "eop", "version": "0.2.2", "private": true, + "main": "src/client/index.js", "dependencies": { "esm": "^3.2.25", "@fortawesome/fontawesome-svg-core": "^1.2.19", @@ -29,7 +30,7 @@ "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", - "server": "node -r esm src/server.js" + "server": "node -r esm src/server/server.js" }, "eslintConfig": { "extends": "react-app" diff --git a/src/App.css b/src/App.css deleted file mode 100644 index b41d297c..00000000 --- a/src/App.css +++ /dev/null @@ -1,33 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/components/board/board.css b/src/client/components/board/board.css similarity index 100% rename from src/components/board/board.css rename to src/client/components/board/board.css diff --git a/src/components/board/board.ignoretest.js b/src/client/components/board/board.ignoretest.js similarity index 100% rename from src/components/board/board.ignoretest.js rename to src/client/components/board/board.ignoretest.js diff --git a/src/components/board/board.js b/src/client/components/board/board.js similarity index 96% rename from src/components/board/board.js rename to src/client/components/board/board.js index 0d3e732c..37537f4a 100644 --- a/src/components/board/board.js +++ b/src/client/components/board/board.js @@ -7,8 +7,8 @@ import Threatbar from '../threatbar/threatbar'; import './board.css'; import request from 'superagent'; import Status from '../status/status'; -import { getDealtCard } from '../../utils'; -import { API_PORT } from '../../constants'; +import { getDealtCard } from '../../../utils/utils'; +import { API_PORT } from '../../../utils/constants'; class Board extends React.Component { static propTypes = { diff --git a/src/components/dealtcard/dealtcard.js b/src/client/components/dealtcard/dealtcard.js similarity index 100% rename from src/components/dealtcard/dealtcard.js rename to src/client/components/dealtcard/dealtcard.js diff --git a/src/components/dealtcard/dealtcard.test.js b/src/client/components/dealtcard/dealtcard.test.js similarity index 100% rename from src/components/dealtcard/dealtcard.test.js rename to src/client/components/dealtcard/dealtcard.test.js diff --git a/src/components/deck/deck.js b/src/client/components/deck/deck.js similarity index 95% rename from src/components/deck/deck.js rename to src/client/components/deck/deck.js index 6de67153..e852213a 100644 --- a/src/components/deck/deck.js +++ b/src/client/components/deck/deck.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { getValidMoves } from '../../utils'; +import { getValidMoves } from '../../../utils/utils'; class Deck extends React.Component { static propTypes = { diff --git a/src/components/deck/deck.test.js b/src/client/components/deck/deck.test.js similarity index 100% rename from src/components/deck/deck.test.js rename to src/client/components/deck/deck.test.js diff --git a/src/components/footer/footer.js b/src/client/components/footer/footer.js similarity index 92% rename from src/components/footer/footer.js rename to src/client/components/footer/footer.js index c5097bac..011126ba 100644 --- a/src/components/footer/footer.js +++ b/src/client/components/footer/footer.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import packageJson from '../../../package.json'; +import packageJson from '../../../../package.json'; import { faHeart } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; diff --git a/src/components/footer/footer.test.js b/src/client/components/footer/footer.test.js similarity index 100% rename from src/components/footer/footer.test.js rename to src/client/components/footer/footer.test.js diff --git a/src/components/leaderboard/leaderboard.js b/src/client/components/leaderboard/leaderboard.js similarity index 100% rename from src/components/leaderboard/leaderboard.js rename to src/client/components/leaderboard/leaderboard.js diff --git a/src/components/leaderboard/leaderboard.test.js b/src/client/components/leaderboard/leaderboard.test.js similarity index 100% rename from src/components/leaderboard/leaderboard.test.js rename to src/client/components/leaderboard/leaderboard.test.js diff --git a/src/components/logo/logo.js b/src/client/components/logo/logo.js similarity index 100% rename from src/components/logo/logo.js rename to src/client/components/logo/logo.js diff --git a/src/components/logo/logo.test.js b/src/client/components/logo/logo.test.js similarity index 100% rename from src/components/logo/logo.test.js rename to src/client/components/logo/logo.test.js diff --git a/src/components/model/model.css b/src/client/components/model/model.css similarity index 100% rename from src/components/model/model.css rename to src/client/components/model/model.css diff --git a/src/components/model/model.js b/src/client/components/model/model.js similarity index 100% rename from src/components/model/model.js rename to src/client/components/model/model.js diff --git a/src/components/sidebar/sidebar.css b/src/client/components/sidebar/sidebar.css similarity index 100% rename from src/components/sidebar/sidebar.css rename to src/client/components/sidebar/sidebar.css diff --git a/src/components/sidebar/sidebar.js b/src/client/components/sidebar/sidebar.js similarity index 93% rename from src/components/sidebar/sidebar.js rename to src/client/components/sidebar/sidebar.js index 59e84152..cfe488a1 100644 --- a/src/components/sidebar/sidebar.js +++ b/src/client/components/sidebar/sidebar.js @@ -4,10 +4,10 @@ import Leaderboard from '../leaderboard/leaderboard'; import DealtCard from '../dealtcard/dealtcard'; import './sidebar.css'; import { Button } from 'reactstrap'; -import { getDealtCard, getDealtCardsForPlayers } from '../../utils' +import { getDealtCard, getDealtCardsForPlayers } from '../../../utils/utils' import { faDownload } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { API_PORT } from '../../constants'; +import { API_PORT } from '../../../utils/constants'; import Footer from '../footer/footer'; class Sidebar extends React.Component { diff --git a/src/components/sidebar/sidebar.test.js b/src/client/components/sidebar/sidebar.test.js similarity index 100% rename from src/components/sidebar/sidebar.test.js rename to src/client/components/sidebar/sidebar.test.js diff --git a/src/components/status/status.js b/src/client/components/status/status.js similarity index 97% rename from src/components/status/status.js rename to src/client/components/status/status.js index bae8d385..54c67e28 100644 --- a/src/components/status/status.js +++ b/src/client/components/status/status.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { grammarJoin, resolvePlayerNames, resolvePlayerName, getPlayers } from '../../utils'; +import { grammarJoin, resolvePlayerNames, resolvePlayerName, getPlayers } from '../../../utils/utils'; class Status extends React.Component { static propTypes = { diff --git a/src/components/status/status.test.js b/src/client/components/status/status.test.js similarity index 100% rename from src/components/status/status.test.js rename to src/client/components/status/status.test.js diff --git a/src/components/threatbar/threatbar.css b/src/client/components/threatbar/threatbar.css similarity index 100% rename from src/components/threatbar/threatbar.css rename to src/client/components/threatbar/threatbar.css diff --git a/src/components/threatbar/threatbar.js b/src/client/components/threatbar/threatbar.js similarity index 99% rename from src/components/threatbar/threatbar.js rename to src/client/components/threatbar/threatbar.js index 920b721b..14fd9cd8 100644 --- a/src/components/threatbar/threatbar.js +++ b/src/client/components/threatbar/threatbar.js @@ -4,7 +4,7 @@ import nl2br from 'react-nl2br'; import { Card, CardHeader, CardBody, CardText, Collapse, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Button, Col, Row, CardFooter, ListGroup, ListGroupItem } from 'reactstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faBolt, faPlus, faEdit, faTrash } from '@fortawesome/free-solid-svg-icons' -import { getComponentName, getTypeString } from '../../utils'; +import { getComponentName, getTypeString } from '../../../utils/utils'; import confirm from 'reactstrap-confirm'; import './threatbar.css'; diff --git a/src/components/threatbar/threatbar.test.js b/src/client/components/threatbar/threatbar.test.js similarity index 100% rename from src/components/threatbar/threatbar.test.js rename to src/client/components/threatbar/threatbar.test.js diff --git a/src/jointjs/joint-tm.css b/src/client/jointjs/joint-tm.css similarity index 100% rename from src/jointjs/joint-tm.css rename to src/client/jointjs/joint-tm.css diff --git a/src/jointjs/shapes.js b/src/client/jointjs/shapes.js similarity index 100% rename from src/jointjs/shapes.js rename to src/client/jointjs/shapes.js diff --git a/src/components/about/about.test.js b/src/client/pages/__tests__/about.test.js similarity index 91% rename from src/components/about/about.test.js rename to src/client/pages/__tests__/about.test.js index 69e4353e..b49795f6 100644 --- a/src/components/about/about.test.js +++ b/src/client/pages/__tests__/about.test.js @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import About from './about'; +import About from '../about'; import { BrowserRouter as Router } from 'react-router-dom' it('renders without crashing', () => { diff --git a/src/App.test.js b/src/client/pages/__tests__/app.test.js similarity index 91% rename from src/App.test.js rename to src/client/pages/__tests__/app.test.js index 07513e0a..adfa2b32 100644 --- a/src/App.test.js +++ b/src/client/pages/__tests__/app.test.js @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App'; +import App from '../app'; it('renders without crashing', () => { /* diff --git a/src/components/create/create.test.js b/src/client/pages/__tests__/create.test.js similarity index 90% rename from src/components/create/create.test.js rename to src/client/pages/__tests__/create.test.js index b1f3b81d..a1b2b43b 100644 --- a/src/components/create/create.test.js +++ b/src/client/pages/__tests__/create.test.js @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import Create from './create'; +import Create from '../create'; import { BrowserRouter as Router } from 'react-router-dom' it('renders without crashing', () => { diff --git a/src/components/about/about.js b/src/client/pages/about.js similarity index 97% rename from src/components/about/about.js rename to src/client/pages/about.js index f1f4c238..fd0e0628 100644 --- a/src/components/about/about.js +++ b/src/client/pages/about.js @@ -1,9 +1,9 @@ import React from 'react'; -import { Container, Card, CardHeader, CardBody, Col, Row } from 'reactstrap'; -import Footer from '../footer/footer'; -import Logo from '../logo/logo'; -import './about.css'; import Helmet from 'react-helmet'; +import { Card, CardBody, CardHeader, Col, Container, Row } from 'reactstrap'; +import Footer from '../components/footer/footer'; +import Logo from '../components/logo/logo'; +import '../styles/about.css'; class About extends React.Component { diff --git a/src/App.js b/src/client/pages/app.js similarity index 84% rename from src/App.js rename to src/client/pages/app.js index 6e66c50c..4480ee4b 100644 --- a/src/App.js +++ b/src/client/pages/app.js @@ -1,8 +1,8 @@ import React from 'react'; import { Client } from 'boardgame.io/react'; -import Board from './components/board/board'; -import { ElevationOfPrivilege } from './game/eop'; -import { SERVER_PORT } from './constants'; +import Board from '../components/board/board'; +import { ElevationOfPrivilege } from '../../game/eop'; +import { SERVER_PORT } from '../../utils/constants'; const url = window.location.protocol+'//'+window.location.hostname+(window.location.port ? ':'+window.location.port: ''); diff --git a/src/components/create/create.js b/src/client/pages/create.js similarity index 95% rename from src/components/create/create.js rename to src/client/pages/create.js index cb92e916..a851de9f 100644 --- a/src/components/create/create.js +++ b/src/client/pages/create.js @@ -1,13 +1,13 @@ -import React from 'react'; -import request from 'superagent'; -import { Container, Card, CardHeader, CardBody, Form, FormGroup, Label, Input, Button, Col, Row, Table, FormText, FormFeedback } from 'reactstrap'; -import { API_PORT } from '../../constants'; import _ from 'lodash'; -import Footer from '../footer/footer'; -import './create.css'; +import React from 'react'; import Helmet from 'react-helmet'; -import Logo from '../logo/logo'; -import { Link } from 'react-router-dom' +import { Link } from 'react-router-dom'; +import { Button, Card, CardBody, CardHeader, Col, Container, Form, FormFeedback, FormGroup, FormText, Input, Label, Row, Table } from 'reactstrap'; +import request from 'superagent'; +import { API_PORT } from '../../utils/constants'; +import Footer from '../components/footer/footer'; +import Logo from '../components/logo/logo'; +import '../styles/create.css'; class Create extends React.Component { diff --git a/src/serviceWorker.js b/src/client/serviceWorker.js similarity index 100% rename from src/serviceWorker.js rename to src/client/serviceWorker.js diff --git a/src/components/about/about.css b/src/client/styles/about.css similarity index 100% rename from src/components/about/about.css rename to src/client/styles/about.css diff --git a/src/cards.css b/src/client/styles/cards.css similarity index 100% rename from src/cards.css rename to src/client/styles/cards.css diff --git a/src/components/create/create.css b/src/client/styles/create.css similarity index 100% rename from src/components/create/create.css rename to src/client/styles/create.css diff --git a/src/definitions.test.js b/src/game/__tests__/definitions.test.js similarity index 86% rename from src/definitions.test.js rename to src/game/__tests__/definitions.test.js index a9f17658..e229257b 100644 --- a/src/definitions.test.js +++ b/src/game/__tests__/definitions.test.js @@ -1,4 +1,4 @@ -import { getThreatDescription } from './definitions'; +import { getThreatDescription } from '../definitions'; it('produces empty value for non-existent card', () => { const description = getThreatDescription("NN"); diff --git a/src/game/eop.test.js b/src/game/__tests__/eop.test.js similarity index 97% rename from src/game/eop.test.js rename to src/game/__tests__/eop.test.js index 8c1e764c..8b499c24 100644 --- a/src/game/eop.test.js +++ b/src/game/__tests__/eop.test.js @@ -1,6 +1,6 @@ -import { shuffleCards, getWinner, ElevationOfPrivilege } from './eop'; import { Client } from 'boardgame.io/client'; -import { STARTING_CARD, INVALID_CARDS } from '../constants'; +import { INVALID_CARDS, STARTING_CARD } from '../../utils/constants'; +import { ElevationOfPrivilege } from '../eop'; describe('game', () => { const spec = { diff --git a/src/definitions.js b/src/game/definitions.js similarity index 100% rename from src/definitions.js rename to src/game/definitions.js diff --git a/src/game/eop.js b/src/game/eop.js index f2d64ad8..78cf64ef 100644 --- a/src/game/eop.js +++ b/src/game/eop.js @@ -1,7 +1,7 @@ import { Game, PlayerView, INVALID_MOVE } from 'boardgame.io/core'; -import { DECK_HANDS, DECK_SUITS, STARTING_CARD, INVALID_CARDS, TRUMP_CARD_PREFIX } from '../constants'; -import { getPlayers, getValidMoves, getDealtCard } from '../utils'; -import { getThreatDescription } from '../definitions.js'; +import { DECK_HANDS, DECK_SUITS, STARTING_CARD, INVALID_CARDS, TRUMP_CARD_PREFIX } from '../utils/constants'; +import { getPlayers, getValidMoves, getDealtCard } from '../utils/utils'; +import { getThreatDescription } from './definitions.js'; import uuidv4 from 'uuid/v4'; import _ from 'lodash'; diff --git a/src/index.js b/src/index.js index f7d4ad32..a5bf1ef9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './cards.css'; +import './client/styles/cards.css'; import 'bootstrap/dist/css/bootstrap.min.css'; import { Route, BrowserRouter as Router } from 'react-router-dom' -import App from './App'; -import Create from './components/create/create'; -import About from './components/about/about'; -import * as serviceWorker from './serviceWorker'; +import App from './client/pages/app'; +import Create from './client/pages/create'; +import About from './client/pages/about'; +import * as serviceWorker from './client/serviceWorker'; ReactDOM.render( diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 6b60c104..00000000 --- a/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/server.js b/src/server.js deleted file mode 100644 index 1dbce080..00000000 --- a/src/server.js +++ /dev/null @@ -1,142 +0,0 @@ -import { Server, FlatFile } from 'boardgame.io/server'; -import { ElevationOfPrivilege } from './game/eop'; -import Router from 'koa-router'; -import Koa from 'koa'; -import cors from '@koa/cors'; -import koaBody from 'koa-body'; -import { getTypeString } from './utils'; -import { getDatabase } from './config'; -import request from 'superagent'; -import uuidv4 from 'uuid/v4'; -import { SERVER_PORT, API_PORT, INTERNAL_API_PORT } from './constants'; - -const app = new Koa(); -const router = new Router(); - -const server = Server({ - games: [ElevationOfPrivilege], - db: getDatabase(), -}); - -router.get('/players/:id', async ctx => { - const gameID = ctx.params.id; - const r = await request - .get(`http://localhost:${INTERNAL_API_PORT}/games/${ElevationOfPrivilege.name}/${gameID}`); - ctx.body = r.body; -}); - -router.post('/create', koaBody(), async ctx => { - const r = await request - .post(`http://localhost:${INTERNAL_API_PORT}/games/${ElevationOfPrivilege.name}/create`) - .send({ - numPlayers: ctx.request.body.players, - }); - - const gameName = ElevationOfPrivilege.name; - const gameId = r.body.gameID; - - const credentials = []; - - for (var i=0; i { - const gameName = ElevationOfPrivilege.name; - const gameID = ctx.params.id; - const model = await server.db.get(`${gameName}:${gameID}:model`); - ctx.body = model; -}); - -router.get('/download/:id', async ctx => { - const gameName = ElevationOfPrivilege.name; - const gameID = ctx.params.id; - const res = await server.db.get(`${gameName}:${gameID}`); - const metadata = await server.db.get(`${gameName}:${gameID}:metadata`); - let model = await server.db.get(`${gameName}:${gameID}:model`); - - // update the model with the identified threats - Object.keys(res.G.identifiedThreats).forEach(diagramIdx => { - Object.keys(res.G.identifiedThreats[diagramIdx]).forEach(componentIdx => { - let diagram = model.detail.diagrams[diagramIdx].diagramJson; - let cell = null; - for (let i=0; i { - let t = res.G.identifiedThreats[diagramIdx][componentIdx][threatIdx]; - threats.push({ - status: "Open", - severity: t.severity, - id: t.id, - methodology: "STRIDE", - type: getTypeString(t.type), - title: t.title, - description: t.description, - mitigation: t.mitigation, - owner: metadata.players[t.owner].name, - game: gameID, - }) - }); - cell.threats = threats; - } - }); - }); - - ctx.attachment(model.summary.title + ".json"); - ctx.body = model; -}); - -const serverHandle = server.run({ - port: SERVER_PORT, - callback: () => { - console.log(`Serving at: http://localhost:${SERVER_PORT}/`); - }, - lobbyConfig: { - apiPort: INTERNAL_API_PORT, - uuid: uuidv4, - apiCallback: () => { - console.log(`Internal API serving at: http://localhost:${INTERNAL_API_PORT}/`); - }, - } -}); - -app.use(cors()); -app.use(router.routes()).use(router.allowedMethods()); -const appHandle = app.listen(API_PORT, () => { - console.log(`API serving at: http://localhost:${API_PORT}/`); -}); - -export { - app, - server, - serverHandle, - appHandle, -} \ No newline at end of file diff --git a/src/config.test.js b/src/server/__tests__/config.test.js similarity index 90% rename from src/config.test.js rename to src/server/__tests__/config.test.js index 5760fbff..18bf83b0 100644 --- a/src/config.test.js +++ b/src/server/__tests__/config.test.js @@ -1,4 +1,4 @@ -import { getDatabase } from './config'; +import { getDatabase } from '../config'; import { FlatFile, Mongo } from 'boardgame.io/server'; it('returns correct Mongo database', () => { diff --git a/src/server.test.js b/src/server/__tests__/server.test.js similarity index 76% rename from src/server.test.js rename to src/server/__tests__/server.test.js index 05473cc2..ac5a3f10 100644 --- a/src/server.test.js +++ b/src/server/__tests__/server.test.js @@ -1,14 +1,14 @@ -import { app, server, serverHandle, appHandle } from './server' +import { gameServer, gameServerHandle, publicApiServer, publicApiServerHandle } from '../server' import request from 'supertest' -import { ElevationOfPrivilege } from './game/eop'; +import { ElevationOfPrivilege } from '../../game/eop'; -it('server is not undefined', async() => { - expect(server).toBeDefined(); +it('gameServer is not undefined', async() => { + expect(gameServer).toBeDefined(); }); it('creates a game without a model', async () => { const players = 3; - const response = await request(app.callback()) + const response = await request(publicApiServer.callback()) .post("/create") .send({ players: players, @@ -22,7 +22,7 @@ it('creates a game without a model', async () => { it('retrieves player info for a game', async () => { const players = 3; - let response = await request(app.callback()) + let response = await request(publicApiServer.callback()) .post("/create") .send({ players: players, @@ -33,13 +33,13 @@ it('retrieves player info for a game', async () => { expect(response.body.game).toBeDefined(); expect(response.body.credentials.length).toBe(players); - response = await request(app.callback()).get(`/players/${response.body.game}`); + response = await request(publicApiServer.callback()).get(`/players/${response.body.game}`); expect(response.body.players.length).toBe(players); }); it('creates a game with a model', async () => { const players = 3; - const response = await request(app.callback()) + const response = await request(publicApiServer.callback()) .post("/create") .send({ players: players, @@ -58,7 +58,7 @@ it('retrieve the model for a game', async () => { const players = 3; const model = { foo: "bar" }; - let response = await request(app.callback()) + let response = await request(publicApiServer.callback()) .post("/create") .send({ players: players, @@ -71,7 +71,7 @@ it('retrieve the model for a game', async () => { expect(response.body.credentials.length).toBe(players); // retrieve the model - response = await request(app.callback()).get(`/model/${response.body.game}`); + response = await request(publicApiServer.callback()).get(`/model/${response.body.game}`); expect(response.body).toStrictEqual(model) }); @@ -146,12 +146,12 @@ it('download the final model for a game', async () => { } }; - await server.db.set(`${gameName}:${gameID}`, state); - await server.db.set(`${gameName}:${gameID}:metadata`, metadata); - await server.db.set(`${gameName}:${gameID}:model`, model); + await gameServer.db.set(`${gameName}:${gameID}`, state); + await gameServer.db.set(`${gameName}:${gameID}:metadata`, metadata); + await gameServer.db.set(`${gameName}:${gameID}:model`, model); // retrieve the model - const response = await request(app.callback()).get(`/download/${gameID}`); + const response = await request(publicApiServer.callback()).get(`/download/${gameID}`); const threats = response.body.detail.diagrams[0].diagramJson.cells[0].threats; expect(threats[0].id).toBe("0"); expect(threats[0].type).toBe("Spoofing"); @@ -163,9 +163,9 @@ it('download the final model for a game', async () => { afterAll(() => { // cleanup - serverHandle.then(s => { + gameServerHandle.then(s => { s.apiServer.close(); s.appServer.close(); }); - appHandle.close(); + publicApiServerHandle.close(); }); \ No newline at end of file diff --git a/src/config.js b/src/server/config.js similarity index 100% rename from src/config.js rename to src/server/config.js diff --git a/src/server/gameServer.js b/src/server/gameServer.js new file mode 100644 index 00000000..3625e0f1 --- /dev/null +++ b/src/server/gameServer.js @@ -0,0 +1,31 @@ +import { Server } from 'boardgame.io/server'; +import uuidv4 from 'uuid/v4'; +import { ElevationOfPrivilege } from '../game/eop'; +import { INTERNAL_API_PORT, SERVER_PORT } from '../utils/constants'; +import { getDatabase } from './config'; + + +const server = Server({ + games: [ElevationOfPrivilege], + db: getDatabase(), +}); + +const runGameServer = () => { + const serverHandle = server.run({ + port: SERVER_PORT, + callback: () => { + console.log(`Game server API (websocket) serving at: http://localhost:${SERVER_PORT}/`); + }, + lobbyConfig: { + apiPort: INTERNAL_API_PORT, + uuid: uuidv4, + apiCallback: () => { + console.log(`Internal API serving at: http://localhost:${INTERNAL_API_PORT}/`); + }, + } + }); + + return [server, serverHandle]; +} + +export default runGameServer; diff --git a/src/server/publicApi.js b/src/server/publicApi.js new file mode 100644 index 00000000..ba118429 --- /dev/null +++ b/src/server/publicApi.js @@ -0,0 +1,120 @@ +import cors from '@koa/cors'; +import Koa from 'koa'; +import koaBody from 'koa-body'; +import Router from 'koa-router'; +import request from 'superagent'; +import { ElevationOfPrivilege } from '../game/eop'; +import { API_PORT, INTERNAL_API_PORT } from '../utils/constants'; +import { getTypeString } from '../utils/utils'; + +const runPublicApi = (gameServer) => { + + const app = new Koa(); + const router = new Router(); + + router.get('/players/:id', async ctx => { + const gameID = ctx.params.id; + const r = await request + .get(`http://localhost:${INTERNAL_API_PORT}/games/${ElevationOfPrivilege.name}/${gameID}`); + ctx.body = r.body; + }); + + router.post('/create', koaBody(), async ctx => { + const r = await request + .post(`http://localhost:${INTERNAL_API_PORT}/games/${ElevationOfPrivilege.name}/create`) + .send({ + numPlayers: ctx.request.body.players, + }); + + const gameName = ElevationOfPrivilege.name; + const gameId = r.body.gameID; + + const credentials = []; + + for (var i=0; i { + const gameName = ElevationOfPrivilege.name; + const gameID = ctx.params.id; + const model = await gameServer.db.get(`${gameName}:${gameID}:model`); + ctx.body = model; + }); + + router.get('/download/:id', async ctx => { + const gameName = ElevationOfPrivilege.name; + const gameID = ctx.params.id; + const res = await gameServer.db.get(`${gameName}:${gameID}`); + const metadata = await gameServer.db.get(`${gameName}:${gameID}:metadata`); + let model = await gameServer.db.get(`${gameName}:${gameID}:model`); + + // update the model with the identified threats + Object.keys(res.G.identifiedThreats).forEach(diagramIdx => { + Object.keys(res.G.identifiedThreats[diagramIdx]).forEach(componentIdx => { + let diagram = model.detail.diagrams[diagramIdx].diagramJson; + let cell = null; + for (let i=0; i { + let t = res.G.identifiedThreats[diagramIdx][componentIdx][threatIdx]; + threats.push({ + status: "Open", + severity: t.severity, + id: t.id, + methodology: "STRIDE", + type: getTypeString(t.type), + title: t.title, + description: t.description, + mitigation: t.mitigation, + owner: metadata.players[t.owner].name, + game: gameID, + }) + }); + cell.threats = threats; + } + }); + }); + + ctx.attachment(model.summary.title + ".json"); + ctx.body = model; + }); + + app.use(cors()); + app.use(router.routes()).use(router.allowedMethods()); + const appHandle = app.listen(API_PORT, () => { + console.log(`Public API serving at: http://localhost:${API_PORT}/`); + }); + + return [app, appHandle] +} + +export default runPublicApi \ No newline at end of file diff --git a/src/server/server.js b/src/server/server.js new file mode 100644 index 00000000..135bd325 --- /dev/null +++ b/src/server/server.js @@ -0,0 +1,12 @@ +import runGameServer from './gameServer'; +import runPublicApi from './publicApi'; + +const [ gameServer, gameServerHandle ] = runGameServer(); +const [ publicApiServer, publicApiServerHandle ] = runPublicApi(gameServer); + +export { + gameServer, + gameServerHandle, + publicApiServer, + publicApiServerHandle +}; diff --git a/src/utils.test.js b/src/utils/__tests__/utils.test.js similarity index 96% rename from src/utils.test.js rename to src/utils/__tests__/utils.test.js index bf5f3d00..0a251869 100644 --- a/src/utils.test.js +++ b/src/utils/__tests__/utils.test.js @@ -1,5 +1,5 @@ -import { getDealtCard, getDealtCardsForPlayers, resolvePlayerNames, resolvePlayerName, grammarJoin, getPlayers, getComponentName, getValidMoves, getTypeString } from './utils' -import { STARTING_CARD } from './constants'; +import { getDealtCard, getDealtCardsForPlayers, resolvePlayerNames, resolvePlayerName, grammarJoin, getPlayers, getComponentName, getValidMoves, getTypeString } from '../utils' +import { STARTING_CARD } from '../constants'; it('gets empty card if no card dealt', async () => { expect(getDealtCard({ diff --git a/src/constants.js b/src/utils/constants.js similarity index 100% rename from src/constants.js rename to src/utils/constants.js diff --git a/src/utils.js b/src/utils/utils.js similarity index 100% rename from src/utils.js rename to src/utils/utils.js From c19a54e63ab8f346fc53efcf376896370c3e1f1e Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Thu, 29 Apr 2021 11:50:48 +0200 Subject: [PATCH 4/7] adapt documentation due to docker-compose --- README.md | 13 +- docs/docker-setup.svg | 568 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 576 insertions(+), 5 deletions(-) create mode 100644 docs/docker-setup.svg diff --git a/README.md b/README.md index 948bd4d3..aebe9f57 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,18 @@ npm run start The UI can also be built and served statically, keep in mind that the values of the port numbers will be hard coded in the generated files. ### Docker -The docker image uses `supervisord` to run both the UI and the server in the same container. The UI is built and served using `nginx`, it is also used to proxy requests from `/api` to the public API. +To start a dockerized version of the EoP game use -``` -docker build . -t eop:latest -docker run --rm -it -p 8080:80 eop:latest +```bash +docker-compose up --build ``` This would start EoP on port `8080` and would be accessible at `http://localhost:8080/`. +The docker-compose setup starts two container: + * `threats-client`: running `nginx` as a reverse proxy and serving the react application + * `threats-server`: running the `nodejs` backends: public API and game server + +![docker-compose setup](docs/docker-setup.svg) ## TODO * Spectator mode @@ -50,7 +54,6 @@ This would start EoP on port `8080` and would be accessible at `http://localhost * Improve test coverage, write tests for possible game states and moves * Refactor and have reusable components * Optimize component renders through `shouldComponentUpdate` -* Optimize docker image, currently using `ubuntu:latest` * Write contributing guide ## Credits diff --git a/docs/docker-setup.svg b/docs/docker-setup.svg new file mode 100644 index 00000000..e5ad4f81 --- /dev/null +++ b/docs/docker-setup.svg @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + docker: server + node + + public API + + game server + docker: client + + nginx + + docker-compose + + + Browser + + + + + + + + + static + react + app + + + + + :8001 + :8000 + :8002 + + + + + + + + + + db + @ + filesystem + + + + + + + + / + /api/ + /socket.io/ + :8080 + + From ca59beda2f904dc5754c946968f470aacc30b64c Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Mon, 10 May 2021 16:01:04 +0200 Subject: [PATCH 5/7] Readded support for a single-container docker deployment as this is needed for the heroku example app --- .dockerignore | 1 + .travis.yml | 2 +- heroku/Dockerfile | 21 +++++++++++++++++++++ heroku/conf/nginx.conf | 20 ++++++++++++++++++++ heroku/conf/supervisord.conf | 20 ++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 heroku/Dockerfile create mode 100644 heroku/conf/nginx.conf create mode 100644 heroku/conf/supervisord.conf diff --git a/.dockerignore b/.dockerignore index a054123e..8b1e8e30 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,3 +3,4 @@ deploy/ build/ db/ **/*.test.js +.heroku/ diff --git a/.travis.yml b/.travis.yml index 23c23a51..c32577ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ matrix: - echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin - echo "$HEROKU_API_KEY" | docker login -u "$HEROKU_USER" --password-stdin registry.heroku.com script: - - docker build -t $REPO:$COMMIT . + - docker build -f heroku/Dockerfile -t $REPO:$COMMIT . - docker tag $REPO:$COMMIT $REPO:latest - docker tag $REPO:$COMMIT $REPO:$TRAVIS_TAG - docker tag $REPO:$COMMIT $REPO:$TRAVIS_TAG diff --git a/heroku/Dockerfile b/heroku/Dockerfile new file mode 100644 index 00000000..48bf2d1d --- /dev/null +++ b/heroku/Dockerfile @@ -0,0 +1,21 @@ +FROM ubuntu:latest +WORKDIR /usr/src/app +ENV PORT 80 + +RUN apt-get update && apt-get install -y curl +RUN curl -sL https://deb.nodesource.com/setup_16.x | bash +RUN apt-get update && apt-get install -y nginx supervisor nodejs +RUN rm -rf /var/lib/apt/lists/* + +COPY package*.json ./ +RUN npm install +COPY . . +COPY heroku/conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY heroku/conf/nginx.conf /etc/nginx/sites-available/default + +RUN npm run build +RUN cp -a build/. /var/www/html/ + +# add support for $PORT env variable +CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/sites-available/default && /usr/bin/supervisord + diff --git a/heroku/conf/nginx.conf b/heroku/conf/nginx.conf new file mode 100644 index 00000000..489a9b8d --- /dev/null +++ b/heroku/conf/nginx.conf @@ -0,0 +1,20 @@ +server { + listen $PORT; + root /var/www/html; + index index.html; + server_name _; + location / { + try_files $uri /index.html; + } + location /api/ { + proxy_pass http://localhost:8001/; + } + location /socket.io/ { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_pass http://localhost:8000/socket.io/; + } +} diff --git a/heroku/conf/supervisord.conf b/heroku/conf/supervisord.conf new file mode 100644 index 00000000..393290d8 --- /dev/null +++ b/heroku/conf/supervisord.conf @@ -0,0 +1,20 @@ +[supervisord] +nodaemon=true + +[program:app] +directory=/usr/src/app +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +command=npm run server + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +priority=900 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +username=www-data +autorestart=true From ac1780de025c33e302c0b013feda0cb28b1b21ab Mon Sep 17 00:00:00 2001 From: Christoph Niehoff Date: Mon, 10 May 2021 16:40:01 +0200 Subject: [PATCH 6/7] Put docker containers into the same network namespace, such that the docker templates can easily be reused for kubernetes --- docker-compose.yml | 1 + docker/files/etc/nginx/conf.d/default.conf | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1d90008b..ac92cc28 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,3 +16,4 @@ services: dockerfile: docker/server.dockerfile container_name: threats-server restart: unless-stopped + network_mode: service:client diff --git a/docker/files/etc/nginx/conf.d/default.conf b/docker/files/etc/nginx/conf.d/default.conf index eac1bd31..c5a823d9 100644 --- a/docker/files/etc/nginx/conf.d/default.conf +++ b/docker/files/etc/nginx/conf.d/default.conf @@ -9,7 +9,7 @@ server { } location /api/ { - proxy_pass http://server:8001/; + proxy_pass http://localhost:8001/; } location /socket.io/ { @@ -18,6 +18,6 @@ server { proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; - proxy_pass http://server:8000/socket.io/; + proxy_pass http://localhost:8000/socket.io/; } } From af992a6f913baeea42ebcd82e9f83a1b85e35c1b Mon Sep 17 00:00:00 2001 From: Osama Khalid Date: Mon, 10 May 2021 21:25:39 +0400 Subject: [PATCH 7/7] using alpine instead of ubuntu for heroku image --- heroku/Dockerfile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/heroku/Dockerfile b/heroku/Dockerfile index 48bf2d1d..4321bcbc 100644 --- a/heroku/Dockerfile +++ b/heroku/Dockerfile @@ -1,21 +1,21 @@ -FROM ubuntu:latest +FROM alpine:3 WORKDIR /usr/src/app ENV PORT 80 -RUN apt-get update && apt-get install -y curl -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -RUN apt-get update && apt-get install -y nginx supervisor nodejs -RUN rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache nginx supervisor nodejs npm COPY package*.json ./ RUN npm install -COPY . . -COPY heroku/conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY heroku/conf/nginx.conf /etc/nginx/sites-available/default +COPY src ./src +COPY public ./public RUN npm run build + +RUN mkdir -p /run/nginx +COPY heroku/conf/supervisord.conf /etc/supervisord.conf +COPY heroku/conf/nginx.conf /etc/nginx/http.d/default.conf + RUN cp -a build/. /var/www/html/ # add support for $PORT env variable -CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/sites-available/default && /usr/bin/supervisord - +CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/http.d/default.conf && /usr/bin/supervisord \ No newline at end of file