Skip to content

Commit

Permalink
Add Dockerfiles and development Docker Compose script
Browse files Browse the repository at this point in the history
  • Loading branch information
Tymotex committed Aug 8, 2022
1 parent a654c65 commit f39cab1
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 13 deletions.
1 change: 1 addition & 0 deletions client/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
22 changes: 22 additions & 0 deletions client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ---------------------------------------------------------------------------- #
# Stage 1 (Build) #
# ---------------------------------------------------------------------------- #
FROM node:18-alpine AS builder

WORKDIR /app

COPY package.json .
RUN yarn install

COPY . .

RUN ["yarn", "build-docker-compose"]

# ---------------------------------------------------------------------------- #
# Stage 2 (Serve) #
# ---------------------------------------------------------------------------- #

FROM nginx:1.23-alpine

COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/build /app/build
17 changes: 17 additions & 0 deletions client/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# It's necessary to have an `events` directive, even if it's just empty.
# Source: https://stackoverflow.com/questions/54481423/nginx-startup-prompt-emerg-no-events-section-in-configuration.
events {}
http {
server {
root /app/build;
index index.html;

location / {
# This `include` directive is necessary for correctly loading CSS
# files.
# Source: https://stackoverflow.com/questions/10075304/nginx-fails-to-load-css-files.
include /etc/nginx/mime.types;
try_files $uri /index.html;
}
}
}
5 changes: 3 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
"socket.io-client": "^2.3.0"
},
"scripts": {
"start": "NODE_ENV=development react-scripts start",
"build": "NODE_ENV=production react-scripts build",
"start": "REACT_APP_ENVIRONMENT=development react-scripts start",
"build": "REACT_APP_ENVIRONMENT=production react-scripts build",
"build-docker-compose": "REACT_APP_ENVIRONMENT=docker react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand Down
Empty file removed client/src/.env
Empty file.
7 changes: 4 additions & 3 deletions client/src/constants/api-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ export const PORT = 5000;
// Change back to "/api" on deployment. Change IP address between
// http://localhost:5000/api and https://techsuite.dev/api on dev/deployment
// export const BASE_URL = "https://techsuite.dev/api";
export const BASE_URL = process.env.NODE_ENV === 'production' ? "https://techsuite.dev/api" : `http://localhost:${PORT}/api`;
// export const BASE_URL = `http://localhost:${PORT}/api`;
export const BASE_URL = process.env.REACT_APP_ENVIRONMENT === 'production' ? "https://techsuite.dev/api" : `http://localhost:${PORT}/api`;

export const GLOBAL_SOCKET_NAMESPACE = "/ts-socket";
export const PORT_EXT = `:${PORT}`; // Change back to empty string on deployment

// Change from: http:// window.location.hostname + PORT_EXT + GLOBAL_SOCKET_NAMESPACE
// to: https://techsuite.dev` + GLOBAL_SOCKET_NAMESPACE
// export const SOCKET_URI = `http://` + window.location.hostname + PORT_EXT + GLOBAL_SOCKET_NAMESPACE;
export const SOCKET_URI = process.env.NODE_ENV === 'production' ?
`https://techsuite.dev` + GLOBAL_SOCKET_NAMESPACE
export const SOCKET_URI = process.env.REACT_APP_ENVIRONMENT === 'production'
? `https://techsuite.dev` + GLOBAL_SOCKET_NAMESPACE
: `http://` + window.location.hostname + PORT_EXT + GLOBAL_SOCKET_NAMESPACE;
42 changes: 42 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This docker-compose file is meant to be run for development and serves as a
# guideline for a production deployment.
version: '3.8'

# Techsuite consists of 3 services:
# 1. React client at port 3000.
# 2. Flask REST API and websocket server at port 5000.
# 3. PostgreSQL database server at port 4000.
services:
client:
build:
context: client
dockerfile: Dockerfile
ports:
- 3000:80
db:
build:
context: server
dockerfile: Dockerfile.db
environment:
# These credentials are used for creating the db superuser. They're not
# the credentials we use from the API side.
POSTGRES_PASSWORD: 1989
POSTGRES_USER: admin
ports:
- 5432:5432
volumes:
- db-data:/var/lib/postgres/data
api:
build:
context: server
dockerfile: Dockerfile.api
depends_on:
- db
environment:
PORT: 5000
DATABASE_URI: postgresql://tim:1989@db:5432/techsuite
BASE_URI: http://localhost:5000/api
ports:
- 5000:5000
volumes:
db-data:
1 change: 1 addition & 0 deletions server/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
venv
30 changes: 30 additions & 0 deletions server/Dockerfile.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# ----------------------------------- Setup ---------------------------------- #
FROM python:3.10-alpine

WORKDIR /api

COPY requirements.txt .

# There are issues with installing psycopg2 on Alpine Linux (and other Linux
# distributions).
# See a good discussion of dependency issues: https://github.com/psycopg/psycopg2/issues/684.
RUN apk update \
&& apk add postgresql-dev gcc python3-dev musl-dev \
&& pip install psycopg2 \
&& pip install gunicorn \
&& pip install -r requirements.txt

COPY . .

# -------------------------------- Production -------------------------------- #
# Create all tables
RUN echo "create_all()" | python3 -i src/db_manage.py 2> /dev/null

# Using Gunicorn and gevent-websocket server.
# See:
# - https://flask.palletsprojects.com/en/2.2.x/deploying/gunicorn/.
# - https://stackoverflow.com/questions/9444405/gunicorn-and-websockets.
WORKDIR /api/src


CMD gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" -b 0.0.0.0:5000 server:app
13 changes: 13 additions & 0 deletions server/Dockerfile.db
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM postgres:14-alpine

EXPOSE 4000

WORKDIR /

COPY db-init.sh /docker-entrypoint-initdb.d

# Create all the tables and initialise the database with a set of existing
# channels, users, connections, messages, etc.
COPY ./seeds/full-2.sql /docker-entrypoint-initdb.d

# No need to override the default postgres CMD in this Dockerfile.
10 changes: 10 additions & 0 deletions server/db-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
# A script to initialise the PostgreSQL Docker container.

set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER tim WITH PASSWORD '1989';
CREATE DATABASE techsuite;
GRANT ALL PRIVILEGES ON DATABASE techsuite TO tim;
EOSQL
4 changes: 2 additions & 2 deletions server/src/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ SECRET_MESSAGE="baldurs-gate-3"
PORT=5000
DATABASE_URI="postgresql://tim:1989@localhost/techsuite"
BASE_URI="http://localhost:5000/api"
GOOGLE_AUTH_API_CLIENT_ID="Register for the Google+ API and place the client ID here"
GOOGLE_AUTH_API_CLIENT_SECRET="Register for the Google+ API and place the client ID here"
GOOGLE_AUTH_API_CLIENT_ID="929299433508-9sh3n4t2cm1nnebga6bau5kmu4bv6cgd.apps.googleusercontent.com"
GOOGLE_AUTH_API_CLIENT_SECRET="Y1TjrWSd4K90ND-joJwE8G9w"
SMTP_HOST_ADDRESS="smtp.gmail.com"
SMTP_PORT=587
SENDER_EMAIL_ADDRESS=""
Expand Down
8 changes: 2 additions & 6 deletions server/src/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@
# OAuth 2 client setup
client = WebApplicationClient(GOOGLE_CLIENT_ID)

@app.route("/api/asstest", methods=["GET"])
def asstest():
return "HELLO WORLD"

@app.route("/api/google/login", methods=["GET"])
def google_login_redirect():
# Find out what URL to hit for Google login consent page
Expand All @@ -75,7 +71,7 @@ def google_login_redirect():
# scopes that let you retrieve user's profile from Google
request_uri = client.prepare_request_uri(
authorization_endpoint,
redirect_uri="https://techsuite.dev/api/google/login/callback", # TODO: Hardcoded url
redirect_uri="https://techsuite.dev/api/google/login/callback",
scope=["openid", "email", "profile"],
)
print(" ➤ Redirecting user to Google auth page: {}".format(request_uri))
Expand Down Expand Up @@ -391,4 +387,4 @@ def handle_user_channel_leave(event_data):
port = int(sys.argv[1]) if len(sys.argv) > 1 else os.getenv("PORT")
# The port is specified in the .env file (which is parsed and loaded by the python-dotenv module)
printColour(" ➤ Server listening on port {}".format(port))
socketio.run(app, port=port, debug=True)
socketio.run(app, host="0.0.0.0", port=port, debug=True)

0 comments on commit f39cab1

Please sign in to comment.