Skip to content

Commit

Permalink
Add Initial Docker Compose Deployment Configuration
Browse files Browse the repository at this point in the history
Add some initial Dockerfiles, an Nginx Config, a Docker Compose config,
& a Makefile for building backend & frontend servers and orchestrating
deployment of the backend, nginx, & postgresql services via Docker
Compose. This work is all still in-progress, we are just ready to test
the CI flow.

Add a new CI action that builds the docker images, tags them with
`latest` & the commit hash, and pushes them to Dockerhub. We will rework
this so a separate job is responsible for tagging to latest for only the
`master` branch.

We need to integrate secrets management into this - as currently the
database is password-less & the JWK is ephemeral. This is okay as this
code won't actually go into production until that is integrated.
  • Loading branch information
prikhi committed Jul 6, 2023
1 parent 8f63ffd commit d52c71b
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
.stack-work
dist
dist-newstyle
output
env.sh
media
33 changes: 33 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,36 @@ jobs:
cache-dependency-path: sleepanarchy-website/package-lock.json
# Dev builds until we can fix SRI plugin on GitHub(prod builds work fine locally)
- run: cd sleepanarchy-website && npm ci && npx purs-tidy check src && npx spago install && npm run build -- --mode development

# Build & Push the docker images
docker-images:
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
image:
- api
- nginx
steps:
- uses: actions/checkout@v3
- name: Pull Commit Hash
id: commit
uses: pr-mpt/actions-commit-hash@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
file: deploy/${{ matrix.image }}/Dockerfile
context: .
push: true
tags: lysergia/sleepanarchy-${{ matrix.image }}:latest,lysergia/sleepanarchy-${{ matrix.image }}:${{ steps.commit.outputs.hash }}
cache-from: type=gha,scope=${{ vars.GITHUB_REF_NAME }}-${{ matrix.image }}
cache-to: type=gha,scope=${{ vars.GITHUB_REF_NAME }}-${{ matrix.image }},mode=max
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
local-up:
docker compose up -d

local-migrate:
docker compose exec api sql-migrate up -env production

local-api-mgmt:
docker compose exec api sleepanarchy-api-management ${CMD}

docker-build:
docker compose build

docker-tag: docker-images
docker tag lysergia/sleepanarchy-nginx:latest lysergia/sleepanarchy-nginx:$(shell git rev-parse HEAD)
docker push lysergia/sleepanarchy-nginx:$(shell git rev-parse HEAD)
docker tag lysergia/sleepanarchy-api:latest lysergia/sleepanarchy-api:$(shell git rev-parse HEAD)
docker push lysergia/sleepanarchy-api:$(shell git rev-parse HEAD)

# TODO: use docker -H ssh://... compose for remote mgmt
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ list has been trimmed down a bit, we'll actually migrate & deploy the site.
* Set prerender.io meta element after page data load.
* Helpers for `pageDataReceived` on init when component has no `apiData`
field or no action for `initialize`.
* Throw my github/gitlab/linkedin in footer as icons
* Blog Posts
* published date formatting(X days ago)
* Add feeds to sidebar? Or footer? Or both?
Expand All @@ -130,7 +131,20 @@ list has been trimmed down a bit, we'll actually migrate & deploy the site.

### DEPLOY

* Dockerize server + prerender + nginx into containers?
* Dockerize server + prerender + nginx into containers
* ~~CI builds images on release/tagged commits, pushes to dockerhub~~
* docker compose instruments services
* ~~nginx only thing exposed to outside world~~
* ~~nginx proxies API server & shares media directory with it~~
* ~~nginx serves frontend prod builds~~
* nginx uses certbot for SSL certs
* nginx uses prerender for server side rendering
* ~~api server has postgres~~
* ~~use api server container to run db migrations, mgmt commands~~
* commands to remotely update prod via SSH
* keep server JWT key secret
* support DB password auth - in backend code & compose file
* health commands for docker


## LICENSE
Expand Down
48 changes: 48 additions & 0 deletions deploy/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# syntax=docker/dockerfile:1

# Build sql-migrate
FROM golang:1-buster AS sql-migrate-builder

RUN GOBIN=$HOME/.local/bin go install github.com/rubenv/sql-migrate/...@latest
RUN mkdir -p /dist
RUN mv $HOME/.local/bin/sql-migrate /dist/sql-migrate


# Build project dependencies
FROM haskell:9.4.5-buster AS dependency-builder

WORKDIR /src

RUN apt-get update && apt-get install -yqq libpq-dev

COPY ./sleepanarchy-api/stack.yaml ./sleepanarchy-api/stack.yaml.lock \
./sleepanarchy-api/package.yaml /src/
RUN stack build --system-ghc --no-install-ghc --dependencies-only


# Build project
FROM haskell:9.4.5-buster AS project-builder

WORKDIR /src

RUN apt-get update && apt-get install -yqq libpq-dev

COPY --from=dependency-builder /root/.stack /root/.stack

COPY ./sleepanarchy-api /src
COPY --from=dependency-builder /src/.stack-work/ /src/.stack-work/
RUN stack install --system-ghc --no-install-ghc

RUN mkdir -p /dist
RUN mv $HOME/.local/bin/* /dist/


# Final minimal image
FROM debian:buster-slim

RUN apt-get update && apt-get install -yqq libpq-dev

COPY --from=sql-migrate-builder /dist/sql-migrate /bin/
COPY --from=project-builder /dist/* /bin/

ENTRYPOINT ["sleepanarchy-api"]
24 changes: 24 additions & 0 deletions deploy/nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# syntax=docker/dockerfile:1

# Build client files
FROM node:20 AS builder

WORKDIR /src

COPY ./sleepanarchy-website/package*.json /src/
RUN npm ci


COPY ./sleepanarchy-website/ /src/
RUN npm run build

RUN mv dist /


# Final minimal image
FROM nginx:1-alpine

RUN rm /etc/nginx/conf.d/default.conf

COPY /deploy/nginx/nginx.conf /etc/nginx/conf.d/sleepanarchy.conf
COPY --from=builder /dist/* /www/
56 changes: 56 additions & 0 deletions deploy/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
server {
# TODO: switch to 443 w/ fallback 80 server that uses HTST
listen 80 default_server;
listen [::]:80 default_server;

server_name _;
http2 on;

root /www;
index index.html;

access_log off;
error_log /dev/stderr info;

client_max_body_size 50M;
client_body_buffer_size 32k;

server_tokens off;

# Only Allow Embedding in Frames From the Same Site
add_header X-Frame-Options sameorigin always;
# Block MimeType Sniffing for Script & Style Tags
add_header X-Content-Type-Options nosniff;
# Tell Browsers to Block XSS Attacks
add_header X-XSS-Protection "1; mode=block";

gzip on;
gzip_buffers 16 16k;
gzip_comp_level 5;
gzip_http_version 1.0;
gzip_proxied any;
gzip_vary on;
gzip_types
text/plain text/css
application/json application/javascript text/javascript
text/xml application/xml application/xml+rss
application/x-font-ttf image/x-icon
;

# TODO: certbot hookup
# TODO: prerender hookup

location / {
try_files $uri /index.html;
}

# TODO: Serve /www/media w/ long expires?
# TODO: JS/CSS have 1yr expires
location = /index.html {
expires -1;
}

location /api/ {
proxy_pass http://api:9001/;
}
}
56 changes: 56 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---

version: '3'

services:
nginx:
build:
context: .
dockerfile: deploy/nginx/Dockerfile
image: lysergia/sleepanarchy-nginx:latest
networks:
- frontend
ports:
- "8080:80"
depends_on:
- api
volumes:
- media:/www/media:ro
api:
build:
context: .
dockerfile: deploy/api/Dockerfile
image: lysergia/sleepanarchy-api:latest
networks:
- frontend
- backend
expose:
- 9001
environment:
- ENVIRONMENT=Production
- DB_HOST=db
- MEDIA_DIRECTORY=/srv/media
volumes:
- media:/srv/media:rw
depends_on:
- db
db:
image: postgres:15
networks:
- backend
expose:
- 5432
environment:
- POSTGRES_USER=sleepanarchy-blog
- POSTGRES_DB=sleepanarchy-blog
- POSTGRES_HOST_AUTH_METHOD=trust
volumes:
- db:/var/lib/postgresql/data:rw

networks:
frontend:
backend:

volumes:
db:
media:

0 comments on commit d52c71b

Please sign in to comment.