Files
kubernetes/invoice-ninja/invoice-ninja.yaml
Dustin C. Hatch e74a6b3142 invoice-ninja: Run in a mutable container
The Invoice Ninja container is not designed to be immutable at all; it
makes a bunch of changes to its own contents when it starts up.
Notably, it copies the contents of the `public` and `storage`
directories from the container image to the persistent volume _and then
deletes the source_.  Additionally, being a Laravel application, it
needs write access to its own code for caching, etc.  Previously, the
`init.sh` script copied the entire `app` directory to a temporary
directory, and then the runtime container mounted that volume over the
top of the original location.  This allowed the root filesystem of the
container to be read-only, while the `app` directory was still mutable.
Unfortunately, this makes the startup process incredibly slow, as it
takes a couple of minutes to copy the whole application.  It's also
pretty pointless, because the application runs as an unprivileged
process, so it wouldn't have write access to the rest of the filesystem
anyway.  As such, I've decided to remove the `readOnlyRootFilesytem`
restriction, and allow the container to run as upstream intends, albeit
begrudgingly.
2024-07-27 12:57:02 -05:00

202 lines
5.2 KiB
YAML

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: invoice-ninja
labels:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
app.kubernetes.io/part-of: invoice-ninja
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 3816Mi
storageClassName: longhorn-static
---
apiVersion: v1
kind: Service
metadata:
name: invoice-ninja
labels:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
app.kubernetes.io/part-of: invoice-ninja
spec:
ports:
- port: 8000
targetPort: http
selector:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: invoice-ninja
labels:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
app.kubernetes.io/part-of: invoice-ninja
spec:
selector:
matchLabels:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
template:
metadata:
labels:
app.kubernetes.io/name: invoice-ninja
app.kubernetes.io/component: invoice-ninja
app.kubernetes.io/part-of: invoice-ninja
spec:
containers:
- name: invoice-ninja
image: &image docker.io/invoiceninja/invoiceninja:5.8.16
command:
- /start.sh
env: &env
- name: DB_HOST
value: invoice-ninja-db
- name: DB_DATABASE
value: ninja
- name: DB_USERNAME
value: ninja
- name: DB_PASSWORD_FILE
value: /run/secrets/invoiceninja/db.password
- name: APP_KEY_FILE
value: /run/secrets/invoiceninja/app.key
- name: APP_CIPHER
value: AES-256-GCM
- name: TRUSTED_PROXIES
value: '*'
envFrom: &envFrom
- configMapRef:
name: invoice-ninja
readinessProbe: &probe
tcpSocket:
port: 9000
periodSeconds: 60
startupProbe:
<<: *probe
periodSeconds: 1
failureThreshold: 60
volumeMounts: &mounts
- mountPath: /run/secrets/invoiceninja
name: secrets
readOnly: true
- mountPath: /start.sh
name: init
subPath: start.sh
- mountPath: /tmp
name: tmp
subPath: tmp
- mountPath: /var/www/app/public
name: data
subPath: public
- mountPath: /var/www/app/public/storage
name: data
subPath: storage-public
- mountPath: /var/www/app/storage
name: data
subPath: storage
- mountPath: /var/www/app/storage/logs
name: tmp
subPath: logs
- name: nginx
image: docker.io/library/nginx:1
ports:
- containerPort: 8000
name: http
readinessProbe: &probe
httpGet:
port: 8000
path: /health
periodSeconds: 60
startupProbe:
<<: *probe
periodSeconds: 1
failureThreshold: 30
securityContext:
readOnlyRootFilesystem: true
runAsUser: 101
runAsGroup: 101
volumeMounts:
- mountPath: /etc/nginx/nginx.conf
name: nginx-conf
subPath: nginx.conf
readOnly: true
- mountPath: /run/nginx
name: run
subPath: nginx
- mountPath: /var/cache/nginx
name: nginx-cache
- mountPath: /var/www/app/public
name: data
subPath: public
readOnly: true
- mountPath: /var/www/app/public/storage
name: data
subPath: storage-public
readOnly: true
- name: cron
image: *image
command:
- sh
- -c
- |
cleanup() { kill -TERM $!; exit; }
trap cleanup TERM
while sleep 60; do php artisan schedule:run; done
env: *env
envFrom: *envFrom
securityContext:
readOnlyRootFilesystem: true
volumeMounts: *mounts
enableServiceLinks: false
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- invoice-ninja-db
securityContext:
runAsNonRoot: True
fsGroup: 1500
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
volumes:
- name: app
emptyDir: {}
- name: data
persistentVolumeClaim:
claimName: invoice-ninja
- name: init
configMap:
name: invoice-ninja-init
defaultMode: 0755
- name: nginx-cache
emptyDir: {}
- name: nginx-conf
configMap:
name: nginx
- name: run
emptyDir:
medium: Memory
- name: secrets
secret:
secretName: invoice-ninja
- name: tmp
emptyDir: {}