chore: refactor-docker-structure (#1948)

* move dockerfiles to dedicated folder

* consolidate docker related files to docker dir

* update CI references

* experimental omni style container

* update makefile commands

* update references

* fix whitespace

* single container docs

* update build paths

* adds omni style build

* set context
This commit is contained in:
Hayden 2022-12-31 10:01:15 -08:00 committed by GitHub
parent c4eebaccca
commit e281f53488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 366 additions and 127 deletions

View file

@ -58,7 +58,7 @@ jobs:
port: ${{ secrets.DEMO_SERVER_PORT }} port: ${{ secrets.DEMO_SERVER_PORT }}
script_stop: true script_stop: true
script: | script: |
cd ~/docker/mealie-next cd ~/docker/mealie
docker-compose pull docker-compose pull
docker-compose down -v docker-compose down -v
docker-compose up -d docker-compose up -d

View file

@ -70,7 +70,7 @@ jobs:
run: | run: |
poetry run black . --check poetry run black . --check
- name: Lint (Flake8) - name: Lint (Ruff)
run: | run: |
make backend-lint make backend-lint

View file

@ -40,11 +40,10 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Frontend Image - name: Build Frontend Image
working-directory: "frontend"
run: | run: |
docker build --push --no-cache \ docker build --push --no-cache \
--tag hkotel/mealie:frontend-${{ inputs.tag }} \ --tag hkotel/mealie:frontend-${{ inputs.tag }} \
--platform linux/amd64,linux/arm64 . --platform linux/amd64,linux/arm64 --file=./docker/frontend.Dockerfile .
build-backend: build-backend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -77,4 +76,37 @@ jobs:
docker build --push --no-cache \ docker build --push --no-cache \
--tag hkotel/mealie:api-${{ inputs.tag }} \ --tag hkotel/mealie:api-${{ inputs.tag }} \
--build-arg COMMIT=$(git rev-parse HEAD) \ --build-arg COMMIT=$(git rev-parse HEAD) \
--platform linux/amd64,linux/arm64 . --platform linux/amd64,linux/arm64 --file=./docker/api.Dockerfile .
build-omni:
runs-on: ubuntu-latest
name: Build Backend
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
with:
image: tonistiigi/binfmt:latest
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
install: true
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Omni-Image
run: |
docker build --push --no-cache \
--tag hkotel/mealie:omni-${{ inputs.tag }} \
--build-arg COMMIT=$(git rev-parse HEAD) \
--platform linux/amd64,linux/arm64 --file=./docker/omni.Dockerfile .

View file

@ -15,7 +15,7 @@ jobs:
- name: Build Dockerfile - name: Build Dockerfile
run: | run: |
docker build -t mealie . docker build -t mealie --file=./docker/api.Dockerfile .
- name: Run Trivy vulnerability scanner - name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master uses: aquasecurity/trivy-action@master

View file

@ -15,7 +15,7 @@ jobs:
- name: Build Dockerfile - name: Build Dockerfile
run: | run: |
docker build -t mealie ./frontend/ docker build -t mealie --file=./docker/frontend.Dockerfile .
- name: Run Trivy vulnerability scanner - name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master uses: aquasecurity/trivy-action@master

View file

@ -46,7 +46,6 @@
"package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig", "package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig",
"pyproject.toml": "poetry.lock, alembic.ini, .pylintrc", "pyproject.toml": "poetry.lock, alembic.ini, .pylintrc",
"netlify.toml": "runtime.txt", "netlify.toml": "runtime.txt",
"docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml",
"README.md": "LICENSE, SECURITY.md" "README.md": "LICENSE, SECURITY.md"
} }
} }

View file

@ -1,48 +0,0 @@
# WARNING: currently not functional, see #756, #1072
# Use root/example as user/password credentials
version: "3.4"
services:
# Vue Frontend
mealie-frontend:
container_name: mealie-frontend
image: mealie-frontend:dev
build:
context: ./frontend
dockerfile: Dockerfile.frontend
restart: always
ports:
- 9920:8080
environment:
- GLOBAL_MIDDLEWARE=null
- BASE_URL=""
- ALLOW_SIGNUP=true
volumes:
- ./frontend/:/app
- /app/node_modules
# Fast API
mealie-api:
container_name: mealie-api
image: mealie-api:dev
build:
context: ./
target: development
dockerfile: Dockerfile
restart: always
ports:
- 9921:9000
environment:
TZ: America/Anchorage # Specify Correct Timezone for Date/Time to line up correctly.
volumes:
- ./dev/data:/app/dev/data
- ./mealie:/app/mealie
# Mkdocs
mealie-docs:
container_name: mealie-docs
image: squidfunk/mkdocs-material
restart: always
ports:
- 9922:8000
volumes:
- ./docs:/docs

View file

@ -51,33 +51,6 @@ COPY ./poetry.lock ./pyproject.toml ./
# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally # install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
RUN poetry install -E pgsql --only main RUN poetry install -E pgsql --only main
###############################################
# Development Image
###############################################
FROM python-base as development
ENV PRODUCTION=false
ENV TESTING=false
# copying poetry and venv into image
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
# copy backend
COPY ./mealie $MEALIE_HOME/mealie
COPY ./poetry.lock ./pyproject.toml $MEALIE_HOME/
# Alembic
COPY ./alembic $MEALIE_HOME/alembic
COPY ./alembic.ini $MEALIE_HOME/
# venv already has runtime deps installed we get a quicker install
WORKDIR $MEALIE_HOME
RUN . $VENV_PATH/bin/activate && poetry install --with main,dev
WORKDIR /
RUN chmod +x $MEALIE_HOME/mealie/run.sh
ENTRYPOINT $MEALIE_HOME/mealie/run.sh "reload"
############################################### ###############################################
# CRFPP Image # CRFPP Image
############################################### ###############################################
@ -135,5 +108,6 @@ EXPOSE ${APP_PORT}
HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1 HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1
COPY ./docker/api.entry.sh $MEALIE_HOME/mealie/run.sh
RUN chmod +x $MEALIE_HOME/mealie/run.sh RUN chmod +x $MEALIE_HOME/mealie/run.sh
ENTRYPOINT $MEALIE_HOME/mealie/run.sh ENTRYPOINT $MEALIE_HOME/mealie/run.sh

35
mealie/run.sh → docker/api.entry.sh Executable file → Normal file
View file

@ -22,7 +22,7 @@ change_user() {
echo "Switching to dedicated user" echo "Switching to dedicated user"
exec gosu $PUID "$BASH_SOURCE" "$@" exec gosu $PUID "$BASH_SOURCE" "$@"
elif [ "$(id -u)" = $PUID ]; then elif [ "$(id -u)" = $PUID ]; then
echo " echo "
User uid: $PUID User uid: $PUID
User gid: $PGID User gid: $PGID
@ -41,28 +41,19 @@ init() {
poetry run python /app/mealie/db/init_db.py poetry run python /app/mealie/db/init_db.py
} }
if [ "$ARG1" == "reload" ]; then echo "Production"
echo "Hot Reload!"
init change_user
# Start API init
python /app/mealie/app.py
GUNICORN_PORT=${API_PORT:-9000}
# Start API
if [ "$WEB_GUNICORN" == 'true' ]; then
echo "Starting Gunicorn"
gunicorn mealie.app:app -b 0.0.0.0:$GUNICORN_PORT -k uvicorn.workers.UvicornWorker -c /app/gunicorn_conf.py --preload
else else
echo "Production" uvicorn mealie.app:app --host 0.0.0.0 --port $GUNICORN_PORT
change_user
init
GUNICORN_PORT=${API_PORT:-9000}
# Start API
if [ "$WEB_GUNICORN" == 'true' ]; then
echo "Starting Gunicorn"
gunicorn mealie.app:app -b 0.0.0.0:$GUNICORN_PORT -k uvicorn.workers.UvicornWorker -c /app/gunicorn_conf.py --preload
else
uvicorn mealie.app:app --host 0.0.0.0 --port $GUNICORN_PORT
fi
fi fi

View file

@ -8,8 +8,8 @@ services:
limits: limits:
memory: 500M memory: 500M
build: build:
context: ./frontend context: ../
dockerfile: Dockerfile dockerfile: ./docker/frontend.Dockerfile
restart: always restart: always
volumes: volumes:
- mealie-data:/app/data/ - mealie-data:/app/data/
@ -43,9 +43,9 @@ services:
limits: limits:
memory: 1000M memory: 1000M
build: build:
context: ./ context: ../
target: production target: production
dockerfile: Dockerfile dockerfile: ./docker/api.Dockerfile
restart: always restart: always
volumes: volumes:
- mealie-data:/app/data/ - mealie-data:/app/data/

View file

@ -2,16 +2,16 @@ FROM node:16 as builder
WORKDIR /app WORKDIR /app
COPY . . COPY ./frontend .
RUN yarn install \ RUN yarn install \
--prefer-offline \ --prefer-offline \
--frozen-lockfile \ --frozen-lockfile \
--non-interactive \ --non-interactive \
--production=false \ --production=false \
# https://github.com/docker/build-push-action/issues/471 # https://github.com/docker/build-push-action/issues/471
--network-timeout 1000000 --network-timeout 1000000
RUN yarn build RUN yarn build
RUN rm -rf node_modules && \ RUN rm -rf node_modules && \
@ -29,7 +29,8 @@ WORKDIR /app
# copying caddy into image # copying caddy into image
COPY --from=builder /app . COPY --from=builder /app .
COPY ./Caddyfile /app/ COPY ./docker/frontend.Caddyfile /app/Caddyfile
COPY ./docker/frontend.entry.sh /app/run.sh
ENV HOST 0.0.0.0 ENV HOST 0.0.0.0
EXPOSE 3000 EXPOSE 3000

View file

@ -4,4 +4,4 @@
caddy start --config /app/Caddyfile caddy start --config /app/Caddyfile
# Start Node Application # Start Node Application
yarn start -p 3001 yarn start -p 3001

156
docker/omni.Dockerfile Normal file
View file

@ -0,0 +1,156 @@
FROM node:16 as builder
WORKDIR /app
COPY ./frontend .
RUN yarn install \
--prefer-offline \
--frozen-lockfile \
--non-interactive \
--production=false \
# https://github.com/docker/build-push-action/issues/471
--network-timeout 1000000
RUN yarn build
RUN rm -rf node_modules && \
NODE_ENV=production yarn install \
--prefer-offline \
--pure-lockfile \
--non-interactive \
--production=true
###############################################
# Base Image - Python
###############################################
FROM python:3.10-slim as python-base
ENV MEALIE_HOME="/app"
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
POETRY_HOME="/opt/poetry" \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_NO_INTERACTION=1 \
PYSETUP_PATH="/opt/pysetup" \
VENV_PATH="/opt/pysetup/.venv"
# prepend poetry and venv to path
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
# create user account
RUN useradd -u 911 -U -d $MEALIE_HOME -s /bin/bash abc \
&& usermod -G users abc \
&& mkdir $MEALIE_HOME
###############################################
# Builder Image
###############################################
FROM python-base as builder-base
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
curl \
build-essential \
libpq-dev \
libwebp-dev \
tesseract-ocr-all \
# LDAP Dependencies
libsasl2-dev libldap2-dev libssl-dev \
gnupg gnupg2 gnupg1 \
&& pip install -U --no-cache-dir pip
# install poetry - respects $POETRY_VERSION & $POETRY_HOME
ENV POETRY_VERSION=1.3.1
RUN curl -sSL https://install.python-poetry.org | python3 -
# copy project requirement files here to ensure they will be cached.
WORKDIR $PYSETUP_PATH
COPY ./poetry.lock ./pyproject.toml ./
# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
RUN poetry install -E pgsql --only main
###############################################
# CRFPP Image
###############################################
FROM hkotel/crfpp as crfpp
RUN echo "crfpp-container"
###############################################
# Production Image
###############################################
FROM python-base as production
ENV PRODUCTION=true
ENV TESTING=false
ARG COMMIT
ENV GIT_COMMIT_HASH=$COMMIT
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
gosu \
tesseract-ocr-all \
curl \
gnupg \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get install -y curl \
&& curl -sL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y nodejs \
&& curl -L https://www.npmjs.com/install.sh | sh
# Add Yarn
RUN npm install -g yarn
# copying poetry and venv into image
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
ENV LD_LIBRARY_PATH=/usr/local/lib
COPY --from=crfpp /usr/local/lib/ /usr/local/lib
COPY --from=crfpp /usr/local/bin/crf_learn /usr/local/bin/crf_learn
COPY --from=crfpp /usr/local/bin/crf_test /usr/local/bin/crf_test
# copy backend
COPY ./mealie $MEALIE_HOME/mealie
COPY ./poetry.lock ./pyproject.toml $MEALIE_HOME/
COPY ./gunicorn_conf.py $MEALIE_HOME
# Alembic
COPY ./alembic $MEALIE_HOME/alembic
COPY ./alembic.ini $MEALIE_HOME/
# venv already has runtime deps installed we get a quicker install
WORKDIR $MEALIE_HOME
RUN . $VENV_PATH/bin/activate && poetry install -E pgsql --only main
WORKDIR /
# Grab CRF++ Model Release
RUN python $MEALIE_HOME/mealie/scripts/install_model.py
VOLUME [ "$MEALIE_HOME/data/" ]
ENV APP_PORT=9000
EXPOSE ${APP_PORT}
HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1
# ----------------------------------
# Copy Frontend
# copying caddy into image
COPY --from=builder /app $MEALIE_HOME/frontend/
ENV HOST 0.0.0.0
EXPOSE ${APP_PORT}
COPY ./docker/omni.entry.sh $MEALIE_HOME/run.sh
RUN chmod +x $MEALIE_HOME/run.sh
ENTRYPOINT $MEALIE_HOME/run.sh

View file

@ -0,0 +1,46 @@
version: "3.4"
services:
omni-mealie:
container_name: mealie
image: mealie-omni:dev
build:
context: ../
target: production
dockerfile: ./docker/omni.Dockerfile
restart: always
volumes:
- mealie-data:/app/data/
ports:
- 9091:3000
environment:
ALLOW_SIGNUP: "false"
DB_ENGINE: sqlite # Optional: 'sqlite', 'postgres'
# =====================================
# Postgres Config
POSTGRES_USER: mealie
POSTGRES_PASSWORD: mealie
POSTGRES_SERVER: postgres
POSTGRES_PORT: 5432
POSTGRES_DB: mealie
# =====================================
# Web Concurrency
WEB_GUNICORN: true
WORKERS_PER_CORE: 0.5
MAX_WORKERS: 1
WEB_CONCURRENCY: 1
# =====================================
# Email Configuration
# SMTP_HOST=
# SMTP_PORT=587
# SMTP_FROM_NAME=Mealie
# SMTP_AUTH_STRATEGY=TLS # Options: 'TLS', 'SSL', 'NONE'
# SMTP_FROM_EMAIL=
# SMTP_USER=
# SMTP_PASSWORD=
volumes:
mealie-data:
driver: local

59
docker/omni.entrypoint.sh Normal file
View file

@ -0,0 +1,59 @@
# Start Backend API
#!/bin/bash
# Strict Mode
# set -e
# IFS=$'\n\t'
# Get PUID/PGID
PUID=${PUID:-911}
PGID=${PGID:-911}
add_user() {
groupmod -o -g "$PGID" abc
usermod -o -u "$PUID" abc
}
change_user() {
# If container is started as root then create a new user and switch to it
if [ "$(id -u)" = "0" ]; then
add_user
chown -R $PUID:$PGID /app
echo "Switching to dedicated user"
exec gosu $PUID "$BASH_SOURCE" "$@"
elif [ "$(id -u)" = $PUID ]; then
echo "
User uid: $PUID
User gid: $PGID
"
fi
}
init() {
# $MEALIE_HOME directory
cd /app
# Activate our virtual environment here
. /opt/pysetup/.venv/bin/activate
# Initialize Database Prerun
poetry run python /app/mealie/db/init_db.py
}
# change_user
init
GUNICORN_PORT=${API_PORT:-9000}
# Start API
if [ "$WEB_GUNICORN" == 'true' ]; then
echo "Starting Gunicorn"
gunicorn mealie.app:app -b 0.0.0.0:$GUNICORN_PORT -k uvicorn.workers.UvicornWorker -c /app/gunicorn_conf.py --preload &
else
uvicorn mealie.app:app --host 0.0.0.0 --port $GUNICORN_PORT &
fi
# ------------------------------
# Start Frontend Nuxt Server
cd /app/frontend && yarn start -p 3000

View file

@ -2,8 +2,7 @@
## Getting a Token ## Getting a Token
Mealie supports long-live api tokens in the user frontend. See [user settings page](../users-groups/user-settings.md) Mealie supports long-live api tokens in the user frontend. These can be created on the `/user/profile/api-tokens` page.
## Key Components ## Key Components

View file

@ -0,0 +1,35 @@
# Using the Omni Image
Since [#1948](https://github.com/hay-kot/mealie/pull/1948) we've started publishing an experimental image that merges both the frontend and backend services into a single container image. This image is currently in an experimental state, and should be used with caution. Continued support for this image will be based on user feedback and demand, if you're using this image please let us know how it's working for you.
- [Feedback Discussion](https://github.com/hay-kot/mealie/discussions/1949)
**For Environmental Variable Configuration See:**
Note that frontend and backend configurations are both applied to the same container.
- [Frontend Configuration](./frontend-config.md)
- [Backend Configuration](./backend-config.md)
```yaml
---
version: "3.7"
services:
mealie-omni:
image: hkotel/mealie:omni-nightly
container_name: mealie
volumes:
- mealie-data:/app/data/
environment:
- ALLOW_SIGNUP=true
- PUID=1000
- PGID=1000
- TZ=America/Anchorage
- BASE_URL=https://mealie.yourdomain.com
restart: always
volumes:
mealie-data:
driver: local
```

View file

@ -53,11 +53,6 @@ As to why we need a database?
* [FastAPI](https://fastapi.tiangolo.com/) * [FastAPI](https://fastapi.tiangolo.com/)
* [Docker](https://www.docker.com/) * [Docker](https://www.docker.com/)
<!-- ROADMAP -->
## Road Map
[See Roadmap](../../roadmap.md)
<!-- CONTRIBUTING --> <!-- CONTRIBUTING -->
## Contributing ## Contributing

File diff suppressed because one or more lines are too long

View file

@ -70,6 +70,7 @@ nav:
- Installation Checklist: "documentation/getting-started/installation/installation-checklist.md" - Installation Checklist: "documentation/getting-started/installation/installation-checklist.md"
- SQLite (Recommended): "documentation/getting-started/installation/sqlite.md" - SQLite (Recommended): "documentation/getting-started/installation/sqlite.md"
- PostgreSQL: "documentation/getting-started/installation/postgres.md" - PostgreSQL: "documentation/getting-started/installation/postgres.md"
- Single Container (Experimental): "documentation/getting-started/installation/single-container.md"
- Frontend Configuration: "documentation/getting-started/installation/frontend-config.md" - Frontend Configuration: "documentation/getting-started/installation/frontend-config.md"
- Backend Configuration: "documentation/getting-started/installation/backend-config.md" - Backend Configuration: "documentation/getting-started/installation/backend-config.md"
- Usage: - Usage:

View file

@ -122,12 +122,11 @@ frontend-lint: ## 🧺 Run yarn lint
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Docker makefile # Docker makefile
docker-dev: ## 🐳 Build and Start Docker Development Stack docker/omni: ## 🐳 Build and start the omni style container
docker-compose -f docker-compose.dev.yml -p dev-mealie down && \ cd docker && docker-compose -f omni.docker-compose.yml -p mealie-omni up --build
docker-compose -f docker-compose.dev.yml -p dev-mealie up --build
docker-prod: ## 🐳 Build and Start Docker Production Stack docker/prod: ## 🐳 Build and Start Docker Production Stack
docker-compose -f docker-compose.yml -p mealie up --build cd docker && docker-compose -f docker-compose.yml -p mealie up --build
generate: generate:
poetry run python dev/code-generation/main.py poetry run python dev/code-generation/main.py