feat: add development Docker stack
This commit is contained in:
parent
6844c50497
commit
2d845afd56
10 changed files with 236 additions and 8 deletions
30
README.md
30
README.md
|
@ -7,7 +7,7 @@ This is a template for building a webapp using the following tech stack:
|
||||||
- [Vue Router](https://router.vuejs.org/guide/) - frontend router for Vue
|
- [Vue Router](https://router.vuejs.org/guide/) - frontend router for Vue
|
||||||
- [TailwindCSS](https://tailwindcss.com/docs/configuration) - CSS framework
|
- [TailwindCSS](https://tailwindcss.com/docs/configuration) - CSS framework
|
||||||
- [Axios](https://axios-http.com/docs/intro) - library for making API requests from the frontend
|
- [Axios](https://axios-http.com/docs/intro) - library for making API requests from the frontend
|
||||||
- [Parcel](/https://parceljs.org/docs/) - bundler used for frontend module resolution and asset optimization
|
- [Parcel](https://parceljs.org/docs/) - bundler used for frontend module resolution and asset optimization
|
||||||
- [npm](https://docs.npmjs.com/cli/v7/configuring-npm/package-json) - node package manager for JavaScript packages
|
- [npm](https://docs.npmjs.com/cli/v7/configuring-npm/package-json) - node package manager for JavaScript packages
|
||||||
- **Backend**:
|
- **Backend**:
|
||||||
- [FastAPI](https://fastapi.tiangolo.com/) - Python-framework for backend APIs
|
- [FastAPI](https://fastapi.tiangolo.com/) - Python-framework for backend APIs
|
||||||
|
@ -35,6 +35,11 @@ docker-compose -f production.docker-compose.yml up -d --force-recreate --build -
|
||||||
This starts two containers, called `backend` and `frontend`, and exposes the deployed web application on port `8000`.
|
This starts two containers, called `backend` and `frontend`, and exposes the deployed web application on port `8000`.
|
||||||
You can open a browser and navigate to [http:localhost:8000/](http:localhost:8000/) to try it out.
|
You can open a browser and navigate to [http:localhost:8000/](http:localhost:8000/) to try it out.
|
||||||
|
|
||||||
|
To stop the containers, run the following as root:
|
||||||
|
```sh
|
||||||
|
docker-compose -f production.docker-compose.yml down
|
||||||
|
```
|
||||||
|
|
||||||
### Production Frontend Container
|
### Production Frontend Container
|
||||||
|
|
||||||
The `frontend` production Docker image is built according to `production.frontend.Dockerfile`.
|
The `frontend` production Docker image is built according to `production.frontend.Dockerfile`.
|
||||||
|
@ -74,7 +79,25 @@ This prevents repetition when writing your endpoint code and allows you to acces
|
||||||
|
|
||||||
## Development Configuration
|
## Development Configuration
|
||||||
|
|
||||||
> **TODO:** implement
|
The development configuration can be deployed using the `development.docker-compose.yml` file, by running (as root):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker-compose -f development.docker-compose.yml up -d --build --force-recreate --remove-orphans
|
||||||
|
```
|
||||||
|
|
||||||
|
This starts three containers, called `backend`, `parcel` and `frontend`, and exposes the deployed web application on port `8000`.
|
||||||
|
You can open a browser and navigate to [http:localhost:8000/](http:localhost:8000/) to try it out.
|
||||||
|
|
||||||
|
To stop the containers, run the following as root:
|
||||||
|
```sh
|
||||||
|
docker-compose -f development.docker-compose.yml down
|
||||||
|
```
|
||||||
|
|
||||||
|
The development containers work very similarly to the production containers, with the exception that hot reloading of configuration
|
||||||
|
and sourcecode files is enabled.
|
||||||
|
|
||||||
|
This means that when you modify the frontend or backend sourcecode while the development container is running, the changes are detected
|
||||||
|
and applied automatically, restarting the containers is usually not required.
|
||||||
|
|
||||||
# Customization
|
# Customization
|
||||||
|
|
||||||
|
@ -132,5 +155,6 @@ Depending on the configuration you wish to customize, please refer to each compo
|
||||||
|
|
||||||
# TODOs / Roadmap
|
# TODOs / Roadmap
|
||||||
|
|
||||||
1. Add a development Docker configuration
|
1. Add sqlite/postgres containers
|
||||||
2. Minify CSS in prod
|
2. Minify CSS in prod
|
||||||
|
3. Add testing tools
|
||||||
|
|
38
development.Caddyfile
Normal file
38
development.Caddyfile
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
:3000 {
|
||||||
|
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
@staticfiles {
|
||||||
|
method GET
|
||||||
|
path /static/*
|
||||||
|
}
|
||||||
|
handle @staticfiles {
|
||||||
|
file_server {
|
||||||
|
root /app/public/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy * backend:3001
|
||||||
|
}
|
||||||
|
|
||||||
|
@robots {
|
||||||
|
method GET
|
||||||
|
path /robots.txt
|
||||||
|
path /sitemap.xml
|
||||||
|
}
|
||||||
|
handle @robots {
|
||||||
|
file_server {
|
||||||
|
root /app/robots/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle * {
|
||||||
|
reverse_proxy * parcel:1234
|
||||||
|
}
|
||||||
|
|
||||||
|
log {
|
||||||
|
output stderr
|
||||||
|
format console
|
||||||
|
}
|
||||||
|
}
|
25
development.backend.Dockerfile
Normal file
25
development.backend.Dockerfile
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM python:3
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
ARG CUSTOM_UID
|
||||||
|
ARG CUSTOM_GID
|
||||||
|
ENV CUSTOM_USERNAME=backend
|
||||||
|
ENV CUSTOM_GROUPNAME=backend
|
||||||
|
RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \
|
||||||
|
mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app
|
||||||
|
|
||||||
|
# Copy source files
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} requirements.txt /app/
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} backend /app/backend/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Run ASGI server
|
||||||
|
EXPOSE 3001/tcp
|
||||||
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
|
ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001", "--access-log", "--use-colors", "--log-level", "debug", "--reload"]
|
54
development.docker-compose.yml
Normal file
54
development.docker-compose.yml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
container_name: frontend
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./development.frontend.Dockerfile
|
||||||
|
args:
|
||||||
|
CUSTOM_UID: 1000
|
||||||
|
CUSTOM_GID: 1000
|
||||||
|
environment:
|
||||||
|
TZ: Europe/Berlin
|
||||||
|
ports:
|
||||||
|
- "8000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./public/:/app/public/:ro
|
||||||
|
- ./robots/:/app/robots/:ro
|
||||||
|
- ./Caddyfile:/app/Caddyfile:ro
|
||||||
|
parcel:
|
||||||
|
container_name: parcel
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./development.parcel.Dockerfile
|
||||||
|
args:
|
||||||
|
CUSTOM_UID: 1000
|
||||||
|
CUSTOM_GID: 1000
|
||||||
|
volumes:
|
||||||
|
- ./frontend/:/app/frontend/:ro
|
||||||
|
- ./postcss.config.js:/app/postcss.config.js:ro
|
||||||
|
- ./.postcssrc:/app/.postcssrc:ro
|
||||||
|
- ./tailwind.config.js:/app/tailwind.config.js:ro
|
||||||
|
expose:
|
||||||
|
- "1234"
|
||||||
|
backend:
|
||||||
|
container_name: backend
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./development.backend.Dockerfile
|
||||||
|
args:
|
||||||
|
CUSTOM_UID: 1000
|
||||||
|
CUSTOM_GID: 1000
|
||||||
|
expose:
|
||||||
|
- "3001"
|
||||||
|
volumes:
|
||||||
|
- ./backend/:/app/backend/:ro
|
||||||
|
- ./requirements.txt:/app/requirements.txt:ro
|
||||||
|
|
||||||
|
...
|
33
development.frontend.Dockerfile
Normal file
33
development.frontend.Dockerfile
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM debian:latest
|
||||||
|
|
||||||
|
# Install Caddy
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt update && apt install -y curl && \
|
||||||
|
apt install -y debian-keyring debian-archive-keyring apt-transport-https && \
|
||||||
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
|
||||||
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list && \
|
||||||
|
apt update && apt install -y caddy && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
ARG CUSTOM_UID
|
||||||
|
ARG CUSTOM_GID
|
||||||
|
ENV CUSTOM_USERNAME=webserver
|
||||||
|
ENV CUSTOM_GROUPNAME=webserver
|
||||||
|
RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \
|
||||||
|
mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app
|
||||||
|
|
||||||
|
# Copy source files
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} development.Caddyfile /app/
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} public /app/public/
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
|
|
||||||
|
# Run Caddy in development mode
|
||||||
|
ENTRYPOINT ["caddy", "run", "--config", "/app/development.Caddyfile", "--adapter", "caddyfile", "--watch"]
|
34
development.parcel.Dockerfile
Normal file
34
development.parcel.Dockerfile
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM debian:latest
|
||||||
|
|
||||||
|
# Install packages
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt update && apt install -y curl && \
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_19.x | bash - && apt-get install -y nodejs && \
|
||||||
|
apt install -y debian-keyring debian-archive-keyring apt-transport-https && \
|
||||||
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
|
||||||
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list && \
|
||||||
|
apt update && apt install -y caddy && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
ARG CUSTOM_UID
|
||||||
|
ARG CUSTOM_GID
|
||||||
|
ENV CUSTOM_USERNAME=webserver
|
||||||
|
ENV CUSTOM_GROUPNAME=webserver
|
||||||
|
RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \
|
||||||
|
mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app
|
||||||
|
|
||||||
|
# Copy source files
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js /app/
|
||||||
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} frontend /app/frontend/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Run the parcel file watcher
|
||||||
|
ENTRYPOINT ["npx", "parcel", "frontend/src/html/index.html"]
|
|
@ -1,6 +1,26 @@
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
hello: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
axios
|
||||||
|
.get('/api/hello/')
|
||||||
|
.then(response => (this.hello = response.data))
|
||||||
|
.catch(error => console.log(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<h1 class="font-accent text-5xl">Hello World!</h1>
|
<h1 class="font-accent text-5xl">Hello!</h1>
|
||||||
<p>If you're seeing this text, Vue.js is working correctly!</p>
|
<p>If you're seeing this text, Vue.js is working correctly.</p>
|
||||||
|
<p>The backend API responded with: {{ hello }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -22,4 +22,4 @@ RUN pip install -r requirements.txt
|
||||||
# Run ASGI server
|
# Run ASGI server
|
||||||
EXPOSE 3001/tcp
|
EXPOSE 3001/tcp
|
||||||
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001"]
|
ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001", "--access-log"]
|
||||||
|
|
|
@ -23,7 +23,7 @@ RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \
|
||||||
|
|
||||||
# Copy source files
|
# Copy source files
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js Caddyfile /app/
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js production.Caddyfile /app/
|
||||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} frontend /app/frontend/
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} frontend /app/frontend/
|
||||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} public /app/public/
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} public /app/public/
|
||||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/
|
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/
|
||||||
|
@ -33,4 +33,4 @@ USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
||||||
RUN npm install
|
RUN npm install
|
||||||
RUN npx parcel build frontend/src/html/index.html
|
RUN npx parcel build frontend/src/html/index.html
|
||||||
|
|
||||||
ENTRYPOINT ["caddy", "run", "--config", "/app/Caddyfile"]
|
ENTRYPOINT ["caddy", "run", "--config", "/app/production.Caddyfile"]
|
||||||
|
|
Loading…
Add table
Reference in a new issue