--- apiVersion: apps/v1 kind: Deployment metadata: name: bookwyrm-worker namespace: bookwyrm-application labels: app: bookwyrm component: worker spec: replicas: 1 selector: matchLabels: app: bookwyrm component: worker template: metadata: labels: app: bookwyrm component: worker spec: securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault # Init container for Redis readiness only initContainers: - name: wait-for-redis image: /library/bookwyrm-worker:latest command: ["/bin/bash", "-c"] args: - | echo "Waiting for Redis..." max_attempts=30 attempt=1 while [ $attempt -le $max_attempts ]; do if python -c " import redis import os try: broker_url = os.environ.get('REDIS_BROKER_URL', 'redis://localhost:6379/0') r_broker = redis.from_url(broker_url) r_broker.ping() activity_url = os.environ.get('REDIS_ACTIVITY_URL', 'redis://localhost:6379/1') r_activity = redis.from_url(activity_url) r_activity.ping() exit(0) except Exception as e: exit(1) " >/dev/null 2>&1; then echo "Redis is ready!" exit 0 fi echo "Redis not ready (attempt $attempt/$max_attempts), waiting..." sleep 2 attempt=$((attempt + 1)) done echo "Redis failed to become ready after $max_attempts attempts" exit 1 envFrom: - configMapRef: name: bookwyrm-config - secretRef: name: bookwyrm-secrets securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1000 containers: - name: bookwyrm-worker image: /library/bookwyrm-worker:latest imagePullPolicy: Always env: - name: CONTAINER_TYPE value: "worker" - name: DJANGO_SETTINGS_MODULE value: "bookwyrm.settings" - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace envFrom: - configMapRef: name: bookwyrm-config - secretRef: name: bookwyrm-secrets resources: requests: cpu: 500m memory: 1Gi limits: cpu: 2000m # Allow internal scaling like PieFed (concurrency=2 can burst) memory: 3Gi # Match PieFed pattern for multiple internal workers volumeMounts: - name: app-storage mountPath: /app/images subPath: images - name: app-storage mountPath: /app/static subPath: static - name: app-storage mountPath: /app/exports subPath: exports - name: backups-storage mountPath: /backups - name: cache-storage mountPath: /tmp livenessProbe: exec: command: - /bin/bash - -c - "python -c \"import redis,os; r=redis.from_url(os.environ['REDIS_BROKER_URL']); r.ping()\"" initialDelaySeconds: 60 periodSeconds: 60 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: exec: command: - python - -c - "import redis,os; r=redis.from_url(os.environ['REDIS_BROKER_URL']); r.ping(); print('Worker ready')" initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1000 volumes: - name: app-storage persistentVolumeClaim: claimName: bookwyrm-app-storage - name: cache-storage persistentVolumeClaim: claimName: bookwyrm-cache-storage - name: backups-storage persistentVolumeClaim: claimName: bookwyrm-backups nodeSelector: kubernetes.io/arch: arm64 tolerations: - effect: NoSchedule key: node-role.kubernetes.io/control-plane operator: Exists --- apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: bookwyrm-worker-hpa namespace: bookwyrm-application spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: bookwyrm-worker minReplicas: 1 # Always keep workers running for background tasks maxReplicas: 2 # Minimal horizontal scaling - workers scale internally metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 375 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 250 behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 60 policies: - type: Percent value: 100 periodSeconds: 60