Photoprism
Photoprism is a photo library management system that lets you manage all of your photos and had companion apps for your phone to also help you upload those pictures as well
Product: Photoprism
0
Install Type: Manifest Files
Container Image: Docker
Installation Details
While there are no official Kubernetes instrustions for Photoprims, we can adapt the Photoprism Pure Docker Install Instructions to guide us in creating the appropriate manifests.
Now let's create the files we'll need to configure Photoprims in Kubernetes
The following manifest files assume you will want to install this to a namespace named media, an nginx ingress named nginx, and Cert Manager configured to use the ACME provider Let's Encrypt. Please adjust for your particular needs.
00-media-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: media
labels:
name: media
01-config.yaml
This will define the environment variables for your Photoprism installation. You should consult the Photoprism Configuration Docs for configuration options. I configure some general settings and database connections but there are many other options can also be configured.
I am currently using a central MariaDB database for my installation. You will need to adjust or remove these options as needed. Also, you will see that some more sensitive items are stored as a Secret rather than a ConfigMap.
---
apiVersion: v1
kind: ConfigMap
metadata:
name: photoprism-configs
namespace: media
data:
TZ: "America/New_York"
PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password)
PHOTOPRISM_SITE_URL: "https://your.photos.url/" # server URL in the format "http(s)://domain.name(:port)/(path)"
PHOTOPRISM_DISABLE_TLS: "true" # disables HTTPS/TLS even if the site URL starts with https:// and a certificate is available
PHOTOPRISM_DEFAULT_TLS: "false" # defaults to a self-signed HTTPS/TLS certificate if no other certificate is available
PHOTOPRISM_ORIGINALS_LIMIT: "100000" # file size limit for originals in MB (increase for high-res video)
PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip)
PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic
PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality)
PHOTOPRISM_EXPERIMENTAL: "true" # enables experimental features
PHOTOPRISM_DISABLE_CHOWN: "false" # disables updating storage permissions via chmod and chown on startup
PHOTOPRISM_DISABLE_WEBDAV: "false" # disables built-in WebDAV server
PHOTOPRISM_DISABLE_SETTINGS: "false" # disables settings UI and API
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # disables all features depending on TensorFlow
PHOTOPRISM_DISABLE_FACES: "false" # disables face detection and recognition (requires TensorFlow)
PHOTOPRISM_DISABLE_CLASSIFICATION: "false" # disables image classification (requires TensorFlow)
PHOTOPRISM_DISABLE_VECTORS: "false" # disables vector graphics support
PHOTOPRISM_DISABLE_RAW: "false" # disables indexing and conversion of RAW images
PHOTOPRISM_RAW_PRESETS: "false" # enables applying user presets when converting RAW images (reduces performance)
PHOTOPRISM_JPEG_QUALITY: "85" # a higher value increases the quality and file size of JPEG images and thumbnails (25-100)
PHOTOPRISM_DETECT_NSFW: "false" # automatically flags photos as private that MAY be offensive (requires TensorFlow)
PHOTOPRISM_UPLOAD_NSFW: "true" # allows uploads that MAY be offensive (no effect without TensorFlow)
# PHOTOPRISM_DATABASE_DRIVER: "sqlite" # SQLite is an embedded database that doesn't require a server
PHOTOPRISM_DATABASE_DRIVER: "mysql" # use MariaDB 10.5+ or MySQL 8+ instead of SQLite for improved performance
PHOTOPRISM_DATABASE_SERVER: "your.database.server:3306" # MariaDB or MySQL database server (hostname:port)
PHOTOPRISM_DATABASE_NAME: "photoprism" # MariaDB or MySQL database schema name
PHOTOPRISM_SITE_CAPTION: "My Photo Album"
PHOTOPRISM_SITE_DESCRIPTION: "" # meta site description
PHOTOPRISM_SITE_AUTHOR: "" # meta site author
## Video Transcoding (https://docs.photoprism.app/getting-started/advanced/transcoding/):
# PHOTOPRISM_FFMPEG_ENCODER: "software" # H.264/AVC encoder (software, intel, nvidia, apple, raspberry, or vaapi)
# PHOTOPRISM_FFMPEG_SIZE: "1920" # video size limit in pixels (720-7680) (default: 3840)
# PHOTOPRISM_FFMPEG_BITRATE: "32" # video bitrate limit in Mbit/s (default: 50)
## Run/install on first startup (options: update https gpu tensorflow davfs clitools clean):
# PHOTOPRISM_INIT: "https gpu tensorflow"
---
apiVersion: v1
kind: Secret
metadata:
name: photoprism-secrets
namespace: media
type: Opaque
stringData:
PHOTOPRISM_DATABASE_USER: "photoprism" # MariaDB or MySQL database user name
PHOTOPRISM_DATABASE_PASSWORD: "YourSuperSecretPassword" # MariaDB or MySQL database user password
PHOTOPRISM_ADMIN_PASSWORD: "YourSuperSecretPassword" # initial admin password (8-72 characters)
PHOTOPRISM_ADMIN_USER: "admin" # admin login username
02-storage.yaml
Even though I'm using an NFS share on a NAS to store my media, Photoprism will need some local storage for it's own use. I defined a 250 MB config volume using Longhorn for this volume.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: media
name: photprism-storage
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 10Gi
03-deploy.yaml
The Deployment brings together the configuration and storage with the container image.
In addition I'm using an NFS share named storage. You will probably need to alter this for your needs. Be sure to adjust the appropriate volume and volumeMount definitions from the YAML below.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: photoprism
namespace: media
labels:
app: photoprism
app.kubernetes.io/name: photoprism
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: photoprism
template:
metadata:
labels:
app: photoprism
app.kubernetes.io/name: photoprism
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
volumes:
- name: photoprism-storage
persistentVolumeClaim:
claimName: photoprism-storage
- name: photoprism-pictures
nfs:
server: your.nfs.server
path: /path/to/pictures
- name: photoprism-import
nfs:
server: your.nfs.server
path: /path/to/importPictures
containers:
- name: photoprism
image: photoprism/photoprism:latest
imagePullPolicy: Always
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "4"
memory: 8Gi
ports:
- containerPort: 2342
volumeMounts:
- name: photoprism-storage
mountPath: /photoprism/storage
- name: photoprism-pictures
mountPath: /photoprism/originals
- name: photoprism-import
mountPath: /photoprism/import
envFrom:
- configMapRef:
name: photoprism-configs
- secretRef:
name: photoprism-secrets
livenessProbe:
httpGet:
path: /
port: 2342
initialDelaySeconds: 20
periodSeconds: 5
04-service.yaml
The service will help expose the pod for use. I leverage ClusterIP with an Ingress, but you could use a LoadBalancer type (with something like MetalLB to expose Photoprism on an IP outside of your cluster directly.
kind: Service
apiVersion: v1
metadata:
name: photoprism-service
namespace: media
spec:
selector:
app: photoprism
ports:
- protocol: TCP
port: 2342
targetPort: 2342
type: ClusterIP
05-ingress.yaml
An Ingress is one way to expose your services and can allow you to use Cert Manager to create TLS certificates for your site as well. In the annotations: {} section
I set an annotation (nginx.ingress.kubernetes.io/proxy-body-size: "0") to disable Nginx size limitations for uploads
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: photoprism-ingress
namespace: media
annotations:
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
ingressClassName: nginx
rules:
- host: your.photoprism.url
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: photoprism-service
port:
number: 2342
tls:
- hosts:
- your.photoprism.url
secretName: photoprism-ext-tls
build-photoprism.sh
Now that we have prepared our manifests we need to deploy them to the cluster with kubectl. I create shell scripts for all my deployments so I can quickly redeploy if I make any adjustments. The below script does assume you have configured kubectl properly already.
#!/bin/bash
kubectl apply -f 00-media-namespace.yaml \
-f 01-config.yaml \
-f 02-storage.yaml \
-f 03-deploy.yaml \
-f 04-service.yaml \
-f 05-ingress.yaml
We can deploy the manifests for Photoprism to the Kubernetes cluster by executing the following:
chmod 755 build-photoprism.sh
./build-photoprism.sh
I keep all my manifests, scripts, and helm charts in a private git repository for version control and archival storage While it is certainly not required to deploy Photoprism, it has made my life a little easier.