Closed mlabuhn closed 2 months ago
Kubernetes install isn't supported, there is a user contributed guide online or you can attempt to get help from someone on Discord.
Files did not attach for some reason, so adding them as comments.
version: "3.8"
services:
db_recipes:
image: postgres:12-alpine
deploy:
replicas: 1
restart_policy:
condition: any
volumes:
- tandoor_postgres12:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "$${POSTGRES_DB}"]
interval: 30s
timeout: 60s
retries: 5
start_period: 80s
web_recipes:
image: vabene1111/recipes:1.5.14
environment:
DEBUG: ${DEBUG}
SQL_DEBUG: ${SQL_DEBUG}
TANDOOR_PORT: ${TANDOOR_PORT}
ALLOWED_HOSTS: ${ALLOWED_HOSTS}
SECRET_KEY: ${SECRET_KEY}
TIMEZONE: ${TIMEZONE}
DB_ENGINE: ${DB_ENGINE}
POSTGRES_HOST: ${POSTGRES_HOST}
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
FRACTION_PREF_DEFAULT: ${FRACTION_PREF_DEFAULT}
COMMENT_PREF_DEFAULT: ${COMMENT_PREF_DEFAULT}
SHOPPING_MIN_AUTOSYNC_INTERVAL: ${SHOPPING_MIN_AUTOSYNC_INTERVAL}
GUNICORN_MEDIA: ${GUNICORN_MEDIA}
EMAIL_HOST: ${EMAIL_HOST}
EMAIL_PORT: ${EMAIL_PORT}
EMAIL_USE_TLS: ${EMAIL_USE_TLS}
DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}
ACCOUNT_EMAIL_SUBJECT_PREFIX: ${ACCOUNT_EMAIL_SUBJECT_PREFIX}
REVERSE_PROXY_AUTH: ${REVERSE_PROXY_AUTH}
deploy:
replicas: 1
restart_policy:
condition: any
volumes:
- tandoor_static:/opt/recipes/staticfiles
- tandoor_media:/opt/recipes/mediafiles
- tandoor_nginx:/opt/recipes/nginx/conf.d
depends_on:
- db_recipes
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:$${TANDOOR_PORT} || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
nginx_recipes:
image: nginx:mainline-alpine
ports:
- 8080:80
environment:
ALLOWED_HOSTS: ${ALLOWED_HOSTS}
TIMEZONE: ${TIMEZONE}
depends_on:
- web_recipes
deploy:
replicas: 1
restart_policy:
condition: any
volumes:
- tandoor_nginx:/etc/nginx/conf.d:ro
- tandoor_static:/static:ro
- tandoor_media:/media:ro
volumes:
tandoor_postgres12:
tandoor_static:
tandoor_media:
tandoor_nginx:
apiVersion: v1
kind: ConfigMap
metadata:
name: recipes
data:
nginx-config: |-
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name _;
client_max_body_size 128M;
# serve static files
location /static/ {
alias /static/;
}
# serve media files
location /media/ {
alias /media/;
}
# pass requests for dynamic content to gunicorn
location / {
proxy_set_header Host $http_host;
proxy_pass http://recipes:9000;
error_page 502 /errors/http502.html;
}
location /errors/ {
alias /etc/nginx/conf.d/errorpages/;
internal;
}
}
}
gunicorn-config: |-
bind = ['0.0.0.0:9000']
accesslog = '-'
errorlog = '-'
loglevel = 'DEBUG'
chdir = '/opt/recipes'
default_proc_name = 'recipes.wgsi'
forwarded_allow_ips = '*'
proxy_allow_ips = '*'
secure_scheme_headers = {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
threads = 1
timeout = 120
worker_tmp_dir = '/dev/shm'
workers = 2
wgsi_app = 'recipes.wsgi'
---
apiVersion: v1
kind: ConfigMap
metadata:
name: recipes-env
data:
POSTGRES_PORT: "5432"
DEBUG: "1"
ALLOWED_HOSTS: "*"
GUNICORN_MEDIA: "0"
EMAIL_HOST: "mailserver.fqdn.com"
EMAIL_PORT: "587"
EMAIL_USE_TLS: "1"
DEFAULT_FROM_EMAIL: "admin@fqdn.com"
ACCOUNT_EMAIL_SUBJECT_PREFIX: "[Tandoor Recipes]"
TZ: "UTC"
POSTGRES_DB: "tandoor"
POSTGRES_USER: "tandoor"
POSTGRES_HOST: recipes-postgresql
POSTGRES_PORT: "5432"
DB_ENGINE: "django.db.backends.postgresql"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: recipes-media
spec:
resources:
requests:
storage: 200Mi
accessModes:
- ReadWriteOnce
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: recipes-static
spec:
resources:
requests:
storage: 200Mi
accessModes:
- ReadWriteOnce
---
apiVersion: v1
kind: Service
metadata:
name: recipes
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
- port: 9000
targetPort: 9000
protocol: TCP
name: gunicorn
selector:
app.kubernetes.io/name: recipes
app.kubernetes.io/instance: recipes
sessionAffinity: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: recipes
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
type: Recreate
template:
spec:
serviceAccountName: recipes
initContainers:
- name: init-chmod-data
envFrom:
- configMapRef:
name: recipes-env
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: recipes
key: secret-key
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: recipes-postgresql
key: password
image: "vabene1111/recipes:1.5.19"
imagePullPolicy: Always
resources:
requests:
cpu: 250m
memory: 64Mi
command:
- sh
- -c
- |
set -e
source venv/bin/activate
echo "Updating database"
python manage.py migrate
python manage.py collectstatic_js_reverse
python manage.py collectstatic --noinput
echo "Setting media file attributes"
chown -R 65534:65534 /opt/recipes/mediafiles
find /opt/recipes/mediafiles -type d | xargs -r chmod 755
find /opt/recipes/mediafiles -type f | xargs -r chmod 644
echo "Done"
securityContext:
runAsUser: 0
volumeMounts:
- mountPath: /opt/recipes/mediafiles
name: media
# mount as subPath due to lost+found on ext4 pvc
subPath: files
- mountPath: /opt/recipes/staticfiles
name: static
# mount as subPath due to lost+found on ext4 pvc
subPath: files
containers:
- name: recipes-nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
name: http
resources:
limits:
cpu: 250m
memory: 64Mi
requests:
cpu: 5m
memory: 64Mi
volumeMounts:
- mountPath: /media
name: media
# mount as subPath due to lost+found on ext4 pvc
subPath: files
readOnly: true
- mountPath: /static
name: static
# mount as subPath due to lost+found on ext4 pvc
subPath: files
readOnly: true
- name: config
mountPath: /etc/nginx/nginx.conf
subPath: nginx-config
readOnly: true
- name: recipes
image: "vabene1111/recipes:1.5.19"
imagePullPolicy: IfNotPresent
command: ["/opt/recipes/venv/bin/gunicorn"]
args: ["-c", "/etc/gunicorn.conf.py", "recipes.wsgi"]
envFrom:
- configMapRef:
name: recipes-env
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: recipes
key: secret-key
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: recipes-postgresql
key: password
volumeMounts:
- mountPath: /opt/recipes/mediafiles
name: media
# mount as subPath due to lost+found on ext4 pvc
subPath: files
- mountPath: /opt/recipes/staticfiles
name: static
# mount as subPath due to lost+found on ext4 pvc
subPath: files
- mountPath: /etc/gunicorn.conf.py
name: config
subPath: gunicorn-config
readOnly: true
readinessProbe:
httpGet:
path: /
port: 9000
scheme: HTTP
initialDelaySeconds: 600
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 10
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 9000
scheme: HTTP
initialDelaySeconds: 600
timeoutSeconds: 25
successThreshold: 1
failureThreshold: 10
periodSeconds: 10
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 5m
memory: 32Mi
securityContext:
runAsUser: 0
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: media
persistentVolumeClaim:
claimName: recipes-media
- name: static
persistentVolumeClaim:
claimName: recipes-static
- name: config
configMap:
name: recipes
---
# Source: recipes/templates/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: recipes
annotations:
cert-manager.io/cluster-issuer: letsencrypt-production
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: nginx
tls:
- hosts:
- "recipes.fqdn.com"
secretName: recipes-cert
rules:
- host: "recipes.fqdn.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: recipes
port:
number: 80
- path: /media
pathType: Prefix
backend:
service:
name: recipes
port:
number: 80
- path: /static
pathType: Prefix
backend:
service:
name: recipes
port:
number: 80
Tandoor Version
1.5.19
Setup
Kubernetes
Reverse Proxy
Others (please state below)
Other
nginx ingress controller
Bug description
I am in the process of migrating applications from my Docker Swarm setup to a Kubernetes cluster in my home lab.
Tandoor recipes worked beautifully when running as a Docker stack, but is exhibiting strange behaviour in Kubernetes:
[CRITICAL] WORKER TIMEOUT
error in the log. When it recovers, or the page reloads, the recipe exists, but without any external images./mediafiles
directory. I have opened a shell to the recipes (gunicorn) pod, and verified that it is able to write to the volume.The Kubernetes configuration is as close as I can get to the Docker Swarm version, which does not have any of these problems; I am attaching abbreviated & sanitised versions of both for reference, along with the logs of the gunicorn pod. I am omitting the PostgreSQL setup, because that uses an external chart and appears to be working fine.
I have tried adjusting the amount of memory and CPU, tweaked the gunicorn start parameters, verified network connectivity from the pods and numerous other things, all of which turned out to be dead ends. I really don't know what else to try, so would appreciate some help figuring this out.
Relevant logs