Deploy Mealie recipe manager #299
12 changed files with 338 additions and 0 deletions
Add Mealie recipe manager service
Deploy Mealie on minikube-indri for meal planning and prep automation. Built from source via forge mirror (mirrors/mealie) with multi-stage Dockerfile: Node.js frontend + Python/uv backend. Includes ArgoCD app, k8s manifests, Caddy proxy entry, and service documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
commit
bd2b02f51c
|
|
@ -91,6 +91,9 @@ caddy_services:
|
|||
- name: ollama
|
||||
host: "ollama.{{ caddy_domain }}"
|
||||
backend: "https://ollama.tail8d86e.ts.net"
|
||||
- name: mealie
|
||||
host: "meals.{{ caddy_domain }}"
|
||||
backend: "https://meals.tail8d86e.ts.net"
|
||||
- name: sifaka
|
||||
host: "nas.{{ caddy_domain }}"
|
||||
backend: "http://sifaka:5000"
|
||||
|
|
|
|||
17
argocd/apps/mealie.yaml
Normal file
17
argocd/apps/mealie.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: mealie
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
|
||||
targetRevision: main
|
||||
path: argocd/manifests/mealie
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: mealie
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
57
argocd/manifests/mealie/deployment.yaml
Normal file
57
argocd/manifests/mealie/deployment.yaml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mealie
|
||||
namespace: mealie
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mealie
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mealie
|
||||
spec:
|
||||
containers:
|
||||
- name: mealie
|
||||
image: registry.ops.eblu.me/blumeops/mealie:kustomized
|
||||
ports:
|
||||
- containerPort: 9000
|
||||
env:
|
||||
- name: BASE_URL
|
||||
value: "https://meals.ops.eblu.me"
|
||||
- name: ALLOW_SIGNUP
|
||||
value: "false"
|
||||
- name: TZ
|
||||
value: "America/Los_Angeles"
|
||||
- name: MAX_WORKERS
|
||||
value: "1"
|
||||
- name: WEB_CONCURRENCY
|
||||
value: "1"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /app/data
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "1000Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/app/about
|
||||
port: 9000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/app/about
|
||||
port: 9000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: mealie-data
|
||||
25
argocd/manifests/mealie/ingress-tailscale.yaml
Normal file
25
argocd/manifests/mealie/ingress-tailscale.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: mealie-tailscale
|
||||
namespace: mealie
|
||||
annotations:
|
||||
tailscale.com/proxy-class: "default"
|
||||
tailscale.com/proxy-group: "ingress"
|
||||
gethomepage.dev/enabled: "true"
|
||||
gethomepage.dev/name: "Mealie"
|
||||
gethomepage.dev/group: "Home"
|
||||
gethomepage.dev/icon: "mealie.png"
|
||||
gethomepage.dev/description: "Recipe manager"
|
||||
gethomepage.dev/href: "https://meals.ops.eblu.me"
|
||||
gethomepage.dev/pod-selector: "app=mealie"
|
||||
spec:
|
||||
ingressClassName: tailscale
|
||||
defaultBackend:
|
||||
service:
|
||||
name: mealie
|
||||
port:
|
||||
number: 9000
|
||||
tls:
|
||||
- hosts:
|
||||
- meals
|
||||
14
argocd/manifests/mealie/kustomization.yaml
Normal file
14
argocd/manifests/mealie/kustomization.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: mealie
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
- pvc.yaml
|
||||
- ingress-tailscale.yaml
|
||||
|
||||
images:
|
||||
- name: registry.ops.eblu.me/blumeops/mealie
|
||||
newTag: v3.12.0-0000000
|
||||
13
argocd/manifests/mealie/pvc.yaml
Normal file
13
argocd/manifests/mealie/pvc.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mealie-data
|
||||
namespace: mealie
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: local-path
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
13
argocd/manifests/mealie/service.yaml
Normal file
13
argocd/manifests/mealie/service.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mealie
|
||||
namespace: mealie
|
||||
spec:
|
||||
selector:
|
||||
app: mealie
|
||||
ports:
|
||||
- name: http
|
||||
port: 9000
|
||||
targetPort: 9000
|
||||
protocol: TCP
|
||||
142
containers/mealie/Dockerfile
Normal file
142
containers/mealie/Dockerfile
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# Mealie — self-hosted recipe manager
|
||||
# Built from source via forge mirror of mealie-recipes/mealie
|
||||
# Based on upstream docker/Dockerfile (multi-stage: Node frontend + Python backend)
|
||||
|
||||
ARG CONTAINER_APP_VERSION=v3.12.0
|
||||
|
||||
###############################################
|
||||
# Frontend Build
|
||||
###############################################
|
||||
FROM node:24-slim AS frontend-builder
|
||||
|
||||
ARG CONTAINER_APP_VERSION
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y git ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN git clone --depth 1 --branch ${CONTAINER_APP_VERSION} \
|
||||
https://forge.ops.eblu.me/mirrors/mealie.git /src
|
||||
|
||||
WORKDIR /src/frontend
|
||||
|
||||
RUN yarn install \
|
||||
--prefer-offline \
|
||||
--frozen-lockfile \
|
||||
--non-interactive \
|
||||
--production=false \
|
||||
--network-timeout 1000000
|
||||
|
||||
RUN yarn generate
|
||||
|
||||
###############################################
|
||||
# Python Base
|
||||
###############################################
|
||||
FROM python:3.12-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 \
|
||||
VENV_PATH="/opt/mealie"
|
||||
|
||||
ENV PATH="$VENV_PATH/bin:$PATH"
|
||||
|
||||
RUN useradd -u 911 -U -d $MEALIE_HOME -s /bin/bash abc \
|
||||
&& usermod -G users abc \
|
||||
&& mkdir $MEALIE_HOME
|
||||
|
||||
###############################################
|
||||
# Backend Package Build
|
||||
###############################################
|
||||
FROM python-base AS backend-builder
|
||||
|
||||
ARG CONTAINER_APP_VERSION
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y curl git ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip install uv
|
||||
|
||||
RUN git clone --depth 1 --branch ${CONTAINER_APP_VERSION} \
|
||||
https://forge.ops.eblu.me/mirrors/mealie.git /src
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY --from=frontend-builder /src/frontend/dist ./mealie/frontend
|
||||
|
||||
RUN uv build --out-dir dist
|
||||
|
||||
RUN uv export --no-editable --no-emit-project --extra pgsql --format requirements-txt --output-file dist/requirements.txt \
|
||||
&& MEALIE_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])") \
|
||||
&& echo "mealie[pgsql]==${MEALIE_VERSION} \\" >> dist/requirements.txt \
|
||||
&& pip hash dist/mealie-${MEALIE_VERSION}-py3-none-any.whl | tail -n1 | tr -d '\n' >> dist/requirements.txt \
|
||||
&& echo " \\" >> dist/requirements.txt \
|
||||
&& pip hash dist/mealie-${MEALIE_VERSION}.tar.gz | tail -n1 >> dist/requirements.txt
|
||||
|
||||
###############################################
|
||||
# Python Venv Build
|
||||
###############################################
|
||||
FROM python-base AS venv-builder
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
libwebp-dev \
|
||||
ffmpeg \
|
||||
libsasl2-dev libldap2-dev libssl-dev \
|
||||
gnupg gnupg2 gnupg1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN python3 -m venv --upgrade-deps $VENV_PATH
|
||||
|
||||
COPY --from=backend-builder /src/dist /dist
|
||||
|
||||
RUN . $VENV_PATH/bin/activate \
|
||||
&& pip install --require-hashes -r /dist/requirements.txt --find-links /dist
|
||||
|
||||
###############################################
|
||||
# Production Image
|
||||
###############################################
|
||||
FROM python-base AS production
|
||||
|
||||
ENV PRODUCTION=true
|
||||
ENV TESTING=false
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
curl \
|
||||
ffmpeg \
|
||||
gosu \
|
||||
iproute2 \
|
||||
libldap-common \
|
||||
libldap2 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /run/secrets
|
||||
|
||||
COPY --from=venv-builder $VENV_PATH $VENV_PATH
|
||||
|
||||
ENV NLTK_DATA="/nltk_data/"
|
||||
RUN mkdir -p $NLTK_DATA
|
||||
RUN python -m nltk.downloader -d $NLTK_DATA averaged_perceptron_tagger_eng
|
||||
|
||||
VOLUME ["$MEALIE_HOME/data/"]
|
||||
ENV APP_PORT=9000
|
||||
|
||||
EXPOSE ${APP_PORT}
|
||||
|
||||
COPY --from=backend-builder /src/docker/healthcheck.sh $MEALIE_HOME/healthcheck.sh
|
||||
RUN chmod +x $MEALIE_HOME/healthcheck.sh
|
||||
HEALTHCHECK CMD $MEALIE_HOME/healthcheck.sh
|
||||
|
||||
ENV HOST=0.0.0.0
|
||||
|
||||
COPY --from=backend-builder /src/docker/entry.sh $MEALIE_HOME/run.sh
|
||||
RUN chmod +x $MEALIE_HOME/run.sh
|
||||
|
||||
LABEL org.opencontainers.image.title="Mealie"
|
||||
LABEL org.opencontainers.image.description="Self-hosted recipe manager"
|
||||
LABEL org.opencontainers.image.source="https://github.com/mealie-recipes/mealie"
|
||||
|
||||
ENTRYPOINT ["/app/run.sh"]
|
||||
1
docs/changelog.d/deploy-mealie.feature.md
Normal file
1
docs/changelog.d/deploy-mealie.feature.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Deploy Mealie recipe manager on minikube-indri for meal planning and prep automation.
|
||||
|
|
@ -40,6 +40,7 @@ DNS points to [[indri]]'s Tailscale IP. TLS via Let's Encrypt (ACME DNS-01 with
|
|||
| [[navidrome]] | https://dj.ops.eblu.me | Music streaming |
|
||||
| [[jellyfin]] | https://jellyfin.ops.eblu.me | Media server |
|
||||
| [[postgresql]] | pg.ops.eblu.me:5432 | Database |
|
||||
| [[mealie]] | https://meals.ops.eblu.me | Recipe manager |
|
||||
| [[sifaka|Sifaka]] | https://nas.ops.eblu.me | NAS dashboard |
|
||||
|
||||
## Public Services (`*.eblu.me`)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ Registry of all applications deployed via [[argocd]].
|
|||
| `cv` | cv | `argocd/manifests/cv/` | [[cv]] |
|
||||
| `forgejo-runner` | forgejo-runner | `argocd/manifests/forgejo-runner/` | [[forgejo]] CI |
|
||||
| `ollama` | ollama | `argocd/manifests/ollama/` | [[ollama]] |
|
||||
| `mealie` | mealie | `argocd/manifests/mealie/` | [[mealie]] |
|
||||
|
||||
## Sync Policies
|
||||
|
||||
|
|
|
|||
51
docs/reference/services/mealie.md
Normal file
51
docs/reference/services/mealie.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
title: Mealie
|
||||
modified: 2026-03-16
|
||||
tags:
|
||||
- service
|
||||
- recipes
|
||||
---
|
||||
|
||||
# Mealie
|
||||
|
||||
Self-hosted recipe manager with a REST API. Part of the meal planning pipeline: Mealie stores categorized recipes, a planner script selects balanced meals, and [[ollama]] generates a unified cooking timeline.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **URL** | https://meals.ops.eblu.me |
|
||||
| **Tailscale URL** | https://meals.tail8d86e.ts.net |
|
||||
| **Namespace** | `mealie` |
|
||||
| **Image** | `registry.ops.eblu.me/blumeops/mealie` (built from source) |
|
||||
| **Database** | SQLite (local, at `/app/data/`) |
|
||||
| **API Docs** | https://meals.ops.eblu.me/docs |
|
||||
| **Upstream** | https://github.com/mealie-recipes/mealie |
|
||||
| **Manifests** | `argocd/manifests/mealie/` |
|
||||
|
||||
## Features
|
||||
|
||||
- Full REST API (FastAPI) for recipe CRUD, filtering by tag/category
|
||||
- Structured recipe data: ingredients (quantity/unit/food), step-by-step instructions
|
||||
- Built-in meal planning and shopping lists
|
||||
- Recipe import from URLs
|
||||
- API token auth for automation
|
||||
|
||||
## Storage
|
||||
|
||||
- 2Gi PVC at `/app/data/` via `local-path` storageClassName
|
||||
- SQLite database (sufficient for single-user, no network storage concerns on minikube)
|
||||
- Recipe images and assets stored alongside the database
|
||||
|
||||
## Networking
|
||||
|
||||
| Endpoint | Reachable from |
|
||||
|----------|----------------|
|
||||
| `https://meals.ops.eblu.me` | Tailnet clients (via Caddy) |
|
||||
| `https://meals.tail8d86e.ts.net` | Tailnet clients |
|
||||
| `http://mealie.mealie.svc.cluster.local:9000` | In-cluster |
|
||||
|
||||
## Related
|
||||
|
||||
- [[ollama]] — LLM backend for meal timeline generation
|
||||
- [[borgmatic]] — Data backup
|
||||
Loading…
Add table
Add a link
Reference in a new issue