Immich部署(K3S版)

前言:

利用现有的K3S集群和群晖部署Immich进行相册存储和整理

环境:

K3S集群:

HOSTNAMEROLESIP
k3s-mastermaster192.168.31.30
k3s-node1worker192.168.31.31
hk-bigbigworkerXX.XX.XX.XX(公网)

image-20250917170746365

群晖: 192.168.31.4
NFS: /volume2/k3s-nfs
SMB: /volume1/photo

过程:

配置文件

SMB StorageClass

  1. 通过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
  1. 通过 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
  1. 通过 **Secret **配置smb密码
# smb-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: smb-secret
  namespace: smb
stringData:
  username: admin
  password: password
  1. 部署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

image-20250917160207006

Immich

  1. 创建命名空间immich
# 01-immich-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: immich
  1. 创建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
    
  2. 创建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'
    
  3. 创建额外的挂载目录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'
    
  4. 创建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"
    
  5. 创建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
    
  6. 创建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
    
  7. 创建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: {}
    
  8. 创建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
    
  9. 创建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
    
  10. 创建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

效果

image-20250917165041470

image-20250917165227793

注意事项

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