Skip to content

Commit

Permalink
Merge pull request #265 from sivertschou/dockerize
Browse files Browse the repository at this point in the history
Dockerize and enable preview deployments
  • Loading branch information
sivertschou authored Nov 25, 2023
2 parents 0e75be4 + 3dd1fe1 commit f04c48d
Show file tree
Hide file tree
Showing 24 changed files with 571 additions and 67 deletions.
81 changes: 81 additions & 0 deletions .github/workflows/build-and-deploy-preview.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Build and deploy preview

on:
pull_request:
types:
- opened
- synchronize

env:
tag: preview-${{ github.event.number }}

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build, tag and push backend
uses: docker/build-push-action@v5
with:
file: ./apps/backend/Dockerfile
tags: ${{ vars.DOCKERHUB_USERNAME }}/dundring-backend:${{ env.tag }}
push: true

- name: Build, tag and push frontend
uses: docker/build-push-action@v5
with:
file: ./apps/frontend/Dockerfile
push: true
tags: ${{ vars.DOCKERHUB_USERNAME }}/dundring-frontend:${{ env.tag }}

deploy:
runs-on: ubuntu-latest
needs: build
environment: preview
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Add docker compose file to server
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
source: docker/preview/docker-compose.yaml
target: previews/${{ env.tag }}
strip_components: 2

- name: Start the containers with Docker Compose
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}

script: |
cd previews/${{ env.tag }}
TAG=${{ env.tag }} \
docker-compose pull
TAG=${{ env.tag }} \
DB_USERNAME=dundring \
DB_PASSWORD=password \
CLOUDFLARE_DNS_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }} \
MAIL_HOST=${{ secrets.MAIL_HOST }} \
MAIL_PORT=${{ secrets.MAIL_PORT }} \
MAIL_USER=${{ secrets.MAIL_USER }} \
MAIL_PASSWORD='${{ secrets.MAIL_PASSWORD }}' \
docker-compose up -d
78 changes: 78 additions & 0 deletions .github/workflows/build-and-deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Build and deploy dev

on:
push:
branches: [master]

env:
tag: dev

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build, tag and push backend
uses: docker/build-push-action@v5
with:
file: ./apps/backend/Dockerfile
tags: ${{ vars.DOCKERHUB_USERNAME }}/dundring-backend:${{ env.tag }}
push: true

- name: Build, tag and push frontend
uses: docker/build-push-action@v5
with:
file: ./apps/frontend/Dockerfile
push: true
tags: ${{ vars.DOCKERHUB_USERNAME }}/dundring-frontend:${{ env.tag }}

deploy:
runs-on: ubuntu-latest
needs: build
environment: dev
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Add docker compose file to server
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
source: docker/dev/docker-compose.yaml
target: dev
strip_components: 2

- name: Start the containers with Docker Compose
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}

script: |
cd dev
docker-compose pull
DB_USERNAME=${{ DB_USERNAME }} \
DB_PASSWORD=${{ DB_PASSWORD }} \
CLOUDFLARE_DNS_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }} \
MAIL_HOST=${{ secrets.MAIL_HOST }} \
MAIL_PORT=${{ secrets.MAIL_PORT }} \
MAIL_USER=${{ secrets.MAIL_USER }} \
MAIL_PASSWORD='${{ secrets.MAIL_PASSWORD }}' \
TOKEN_SECRET=${{ secrets.TOKEN_SECRET }} \
docker-compose up -d
26 changes: 0 additions & 26 deletions .github/workflows/build.yaml

This file was deleted.

43 changes: 43 additions & 0 deletions apps/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FROM node:16-alpine AS base

FROM base AS builder
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
WORKDIR /app
RUN yarn global add turbo
COPY . .
RUN turbo prune --scope=@dundring/backend --docker

# Add lockfile and package.json's of isolated subworkspace
FROM base AS installer
RUN apk add --no-cache libc6-compat
RUN apk add --no-cache openssl1.1-compat
RUN apk update
WORKDIR /app

# First install dependencies (as they change less often)
COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/yarn.lock ./yarn.lock
RUN yarn install --ignore-scripts --frozen-lockfile

# Build the project and its dependencies
COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json

RUN yarn turbo run build --filter=@dundring/backend

FROM base AS runner
RUN apk add --no-cache openssl1.1-compat
WORKDIR /app

# Don't run production as root
RUN addgroup --system --gid 1001 expressjs
RUN adduser --system --uid 1001 expressjs
# USER expressjs
COPY --from=installer /app .

# CMD libs/database && node apps/backend/build/server.js
ENTRYPOINT ["/app/apps/backend/docker-entrypoint.sh"]
CMD node /app/apps/backend/build/server.js
9 changes: 9 additions & 0 deletions apps/backend/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
set -e

cd libs/database

# Run the database migration
yarn db:migrate

exec "$@"
2 changes: 1 addition & 1 deletion apps/backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ app.use(cors());
app.use('/api', router);

const httpServer = http.createServer(app);
const wss = new WebSocket.Server({ server: httpServer });
const wss = new WebSocket.Server({ server: httpServer, path: '/api' });

const checkEnvConfig = () => {
if (!process.env.PORT) {
Expand Down
42 changes: 42 additions & 0 deletions apps/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
FROM node:16-alpine AS base

FROM base AS builder
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
WORKDIR /app
RUN yarn global add turbo
COPY . .
RUN turbo prune --scope=@dundring/frontend --docker

# Add lockfile and package.json's of isolated subworkspace
FROM base AS installer
RUN apk add --no-cache libc6-compat
RUN apk add --no-cache openssl1.1-compat
RUN apk update
WORKDIR /app

# First install dependencies (as they change less often)
COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/yarn.lock ./yarn.lock
RUN yarn install --ignore-scripts --frozen-lockfile

# Build the project and its dependencies
COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json

RUN yarn turbo run build --filter=@dundring/frontend

# Use a lightweight web server to serve the static files
FROM nginx:1.25.2-alpine AS runner

# Copy the built React app from the build stage to the NGINX web server
COPY --from=installer /app/apps/frontend/dist /usr/share/nginx/html
COPY /apps/frontend/nginx.conf /etc/nginx/conf.d/default.conf

# Expose port 80 for incoming HTTP traffic
EXPOSE 80

# Start the NGINX web server
CMD ["nginx", "-g", "daemon off;"]
7 changes: 7 additions & 0 deletions apps/frontend/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
server {
root /usr/share/nginx/html;

location / {
try_files $uri $uri/ /index.html;
}
}
8 changes: 4 additions & 4 deletions apps/frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import {
WorkoutRequestBody,
WorkoutsResponseBody,
} from '@dundring/types';
export const domain = import.meta.env.VITE_DOMAIN || 'http://localhost:3000';
import { getEnv } from './utils/environment';

export const httpUrl =
import.meta.env.VITE_HTTP_URL || 'http://localhost:8080/api';
export const domain = location.origin;

export const wsUrl = import.meta.env.VITE_WS_URL || 'ws://localhost:8080';
export const httpUrl = getEnv().dundringHttpServerUrl;
export const wsUrl = getEnv().dundringWsServerUrl;

const get = async <T>(
url: string,
Expand Down
4 changes: 1 addition & 3 deletions apps/frontend/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

interface ImportMetaEnv {
readonly VITE_APP_TITLE: string;
readonly VITE_DOMAIN: string;
readonly VITE_HTTP_URL: string;
readonly VITE_WS_URL: string;
readonly VITE_ENV_OVERRIDE: string;
}

interface ImportMeta {
Expand Down
35 changes: 35 additions & 0 deletions apps/frontend/src/utils/environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
interface Environment {
dundringHttpServerUrl: string;
dundringWsServerUrl: string;
}

export const getEnv = (): Environment => {
const envOverride = import.meta.env.VITE_ENV_OVERRIDE || null;

switch (envOverride) {
case 'test':
return {
dundringHttpServerUrl: 'https://test.dundring.com/api',
dundringWsServerUrl: 'wss://test.dundring.com/api',
};
case 'prod':
return {
dundringHttpServerUrl: 'https://dundring.com/api',
dundringWsServerUrl: 'wss://dundring.com/api',
};
default:
if (isSecureConnection()) {
return {
dundringHttpServerUrl: `https://${location.hostname}/api`,
dundringWsServerUrl: `wss://${location.hostname}/api`,
};
}

return {
dundringHttpServerUrl: 'http://localhost:8080/api',
dundringWsServerUrl: 'ws://localhost:8080/api',
};
}
};

const isSecureConnection = () => location.protocol === 'https:';
Loading

0 comments on commit f04c48d

Please sign in to comment.