Immich部署(K3S版)
前言:
利用现有的K3S集群和群晖部署Immich进行相册存储和整理
环境:
K3S集群:
| HOSTNAME | ROLES | IP |
|---|---|---|
| k3s-master | master | 192.168.31.30 |
| k3s-node1 | worker | 192.168.31.31 |
| hk-bigbig | worker | XX.XX.XX.XX(公网) |

群晖: 192.168.31.4
NFS: /volume2/k3s-nfs
SMB: /volume1/photo
过程:
配置文件
SMB StorageClass
- 通过Helm Charts 部署csi-driver-smb
helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts
helm repo update
helm install csi-driver-smb csi-driver-smb/csi-driver-smb --namespace kube-system --version v1.18.0
- 通过 Endpoints + Service 的方式,把一个集群外的群晖提供的SMB 服务(
192.168.31.4:445)引入到集群中
# smb-endpoint.yaml
---
apiVersion: v1
kind: Endpoints
metadata:
name: smb
namespace: smb
subsets:
- addresses:
- ip: 192.168.31.4 # 目标 IP 地址
ports:
- port: 445 # SMB 服务的端口
protocol: TCP
name: smbport
- 通过 **Secret **配置smb密码
# smb-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: smb-secret
namespace: smb
stringData:
username: admin
password: password
- 部署StorageClass
# smb-sc-immich.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: smb-immich
provisioner: smb.csi.k8s.io
parameters:
# On Windows, "*.default.svc.cluster.local" could not be recognized by csi-proxy
source: //smb.smb.svc.cluster.local/photo # 此处 Pod 内部通过 Service 名称访问 SMB 共享目录 /photo
# if csi.storage.k8s.io/provisioner-secret is provided, will create a sub directory
# with PV name under source
csi.storage.k8s.io/provisioner-secret-name: smb-secret # 对应03步骤创建的secret名称
csi.storage.k8s.io/provisioner-secret-namespace: smb
csi.storage.k8s.io/node-stage-secret-name: smb-secret
csi.storage.k8s.io/node-stage-secret-namespace: smb
volumeBindingMode: Immediate
allowVolumeExpansion: true
reclaimPolicy: Retain
mountOptions:
- dir_mode=0777
- file_mode=0777
- uid=1001
- gid=1001
- noperm
- mfsymlinks
- cache=strict
- noserverino # required to prevent data corruption

Immich
- 创建命名空间immich
# 01-immich-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: immich
-
创建immich-postgresql数据库的持久化pvc(k3s的数据持久化使用的是nfs提供的storageclass [nfs-client])
# 02-immich-db-pvc.yaml --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: immich-db-pvc namespace: immich labels: app: immich spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi # Match or be less than the PV's capacity storageClassName: 'nfs-client' # 此处提前部署好的nfs的storageclass -
创建immich-library的pvc,对应immich的**/usr/src/app/upload**这个目录,此目录为immich用户上传照片的默认目录
# 03-immich-library-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: immich-library-pvc namespace: immich labels: app: immich spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: 'smb-immich' -
创建额外的挂载目录pvc
# 04-immich-ext-library-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nas-icloud-photos-pvc namespace: immich labels: app: immich spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi # Match or be less than the PV's capacity storageClassName: 'smb-immich' -
创建immich server的配置文件
# 05-immich-configmap.yaml kind: ConfigMap apiVersion: v1 metadata: name: immich-env namespace: immich labels: app: immich data: DB_DATABASE_NAME: "immich" DB_HOSTNAME: "immich-database" # 此处也是以service的方式去访问db数据库 DB_USERNAME: "immich" IMMICH_MACHINE_LEARNING_URL: "http://immich-machine-learning:3003" # 此处是调用immich机器学习的url,一同部署在immich的命名空间中,所以以service的方式去访问 REDIS_HOSTNAME: "redis.redis.svc.cluster.local" # 此处用了部署在k3s的公共redis,请自行替换 REDIS_PORT: "6379" REDIS_DBINDEX: "2" REDIS_PASSWORD: "" DISABLE_REVERSE_GEOCODING: "false" REVERSE_GEOCODING_PRECISION: "2" PUBLIC_LOGIN_PAGE_MESSAGE: "" PUID: "0" PGID: "0" DB_PASSWORD: "dbpassword" -
创建immich-db-deployment文件,运行postgresql数据库
# 06-immich-db-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: immich-database namespace: immich spec: replicas: 1 selector: matchLabels: app: immich-database template: metadata: labels: app: immich-database spec: containers: - name: immich-postgres image: "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0" imagePullPolicy: Always ports: - containerPort: 5432 env: - name: POSTGRES_USER valueFrom: configMapKeyRef: name: immich-env key: DB_USERNAME - name: POSTGRES_PASSWORD valueFrom: configMapKeyRef: name: immich-env key: DB_PASSWORD - name: POSTGRES_DB valueFrom: configMapKeyRef: name: immich-env key: DB_DATABASE_NAME volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data subPath: postgres volumes: - name: pgdata persistentVolumeClaim: claimName: immich-db-pvc -
创建immich-db-service服务
# 07-immich-db-service.yaml kind: Service apiVersion: v1 metadata: name: immich-database namespace: immich labels: app: immich-database spec: type: ClusterIP selector: app: immich-database ports: - name: tcp-postgresql port: 5432 targetPort: 5432 -
创建immich-deployment,运行机器学习服务
# 08-immich-ml-deployment.yaml kind: Deployment apiVersion: apps/v1 metadata: name: immich-machine-learning namespace: immich labels: app: immich-machine-learning spec: strategy: type: Recreate selector: matchLabels: app: immich-machine-learning template: metadata: labels: app: immich-machine-learning spec: securityContext: fsGroup: 0 serviceAccountName: default automountServiceAccountToken: true dnsPolicy: ClusterFirst enableServiceLinks: true containers: - name: immich-machine-learning image: "ghcr.io/immich-app/immich-machine-learning:release" imagePullPolicy: Always ports: - containerPort: 3003 env: - name: DB_PASSWORD valueFrom: configMapKeyRef: name: immich-env key: DB_PASSWORD - name: TRANSFORMERS_CACHE value: /cache envFrom: - configMapRef: name: immich-env optional: false livenessProbe: failureThreshold: 3 httpGet: path: /ping port: 3003 initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /ping port: 3003 initialDelaySeconds: 0 periodSeconds: 10 timeoutSeconds: 1 volumeMounts: - name: cache mountPath: /cache volumes: - name: cache emptyDir: {} -
创建immich机器学习服务的service
# 09-immich-ml-service.yaml kind: Service apiVersion: v1 metadata: name: immich-machine-learning namespace: immich labels: app: immich-machine-learning spec: type: ClusterIP selector: app: immich-machine-learning ports: - port: 3003 targetPort: 3003 protocol: TCP -
创建immich-server deployment, 运行immich主服务
# 10-immich-server-deployment.yaml kind: Deployment apiVersion: apps/v1 metadata: name: immich-server namespace: immich labels: app: immich-server spec: strategy: type: Recreate selector: matchLabels: app: immich-server template: metadata: labels: app: immich-server spec: securityContext: fsGroup: 0 serviceAccountName: default dnsPolicy: ClusterFirst initContainers: - name: postgresql-isready image: "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0" imagePullPolicy: Always env: - name: POSTGRES_USER valueFrom: configMapKeyRef: name: immich-env key: DB_USERNAME - name: POSTGRES_DB valueFrom: configMapKeyRef: name: immich-env key: DB_DATABASE_NAME command: - /bin/sh - -c - until pg_isready -U "${POSTGRES_USER}" -d "dbname=${POSTGRES_DB}" -h immich-database -p 5432 ; do sleep 2 ; done containers: - name: immich-server image: "ghcr.io/immich-app/immich-server:release" imagePullPolicy: Always securityContext: runAsUser: 0 ports: - containerPort: 3001 env: - name: DB_PASSWORD valueFrom: configMapKeyRef: name: immich-env key: DB_PASSWORD envFrom: - configMapRef: name: immich-env optional: false livenessProbe: failureThreshold: 120 httpGet: path: /server/ping port: 2283 initialDelaySeconds: 10 periodSeconds: 120 timeoutSeconds: 1 readinessProbe: failureThreshold: 120 httpGet: path: /server/ping port: 2283 initialDelaySeconds: 10 periodSeconds: 120 timeoutSeconds: 1 # 此处挂载,对应着前面创建的PVC volumeMounts: - name: library mountPath: /usr/src/app/upload subPath: library - name: ext-library mountPath: /photos subPath: icloud_photos # 可选 #- name: nas-photos # mountPath: /nas-photos volumes: - name: library persistentVolumeClaim: claimName: immich-library-pvc - name: ext-library persistentVolumeClaim: claimName: nas-icloud-photos-pvc # 可选 #- name: nas-photos # persistentVolumeClaim: # claimName: nas-photos-pvc -
创建immich server的service (可选用nodeport暴露的方式)
# 11-immich-server-service.yaml
kind: Service
apiVersion: v1
metadata:
name: immich-server
namespace: immich
labels:
app: immich-server
spec:
type: NodePort
selector:
app: immich-server
ports:
- port: 2283
targetPort: 2283
nodePort: 32283
protocol: TCP
```
12. 创建immich-ingress暴露服务
```yaml
# 12-immich-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: immich-private
namespace: immich
labels:
app: immich
spec:
ingressClassName: traefik
rules:
- host: immich.crazy.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: immich-server
port:
number: 2283
```
13. 可选的nas额外配置挂载
```yaml
# 13-immich-nas-photos-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nas-photos-pvc
namespace: immich
labels:
app: immich
spec:
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 20Gi # Match or be less than the PV's capacity
storageClassName: 'smb-immich'
部署
依次按照此顺序部署 namespace > pvc > service > db > immich machine-learning > immich server > ingress
效果


注意事项
- StorageClass

- Immich数据的持久化SMB存储挂载情况
reclaimPolicy的策略为: Retain(默认策略Delete,当PVC删除,PV及数据会连带删除)

- Postgresql数据的持久化NFS的挂载情况,reclaimPolicy的策略为 Retain
