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
|
||||
- [TailwindCSS](https://tailwindcss.com/docs/configuration) - CSS framework
|
||||
- [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
|
||||
- **Backend**:
|
||||
- [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`.
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
> **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
|
||||
|
||||
|
@ -132,5 +155,6 @@ Depending on the configuration you wish to customize, please refer to each compo
|
|||
|
||||
# TODOs / Roadmap
|
||||
|
||||
1. Add a development Docker configuration
|
||||
1. Add sqlite/postgres containers
|
||||
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>
|
||||
<div class="p-8">
|
||||
<h1 class="font-accent text-5xl">Hello World!</h1>
|
||||
<p>If you're seeing this text, Vue.js is working correctly!</p>
|
||||
<h1 class="font-accent text-5xl">Hello!</h1>
|
||||
<p>If you're seeing this text, Vue.js is working correctly.</p>
|
||||
<p>The backend API responded with: {{ hello }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -22,4 +22,4 @@ 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"]
|
||||
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
|
||||
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} public /app/public/
|
||||
COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/
|
||||
|
@ -33,4 +33,4 @@ USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000}
|
|||
RUN npm install
|
||||
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