一个自行部署的照片托管解决方案伪横评(真水文)。
使用设备:Celeron N5105(无AVX指令集),16G RAM,512G SSD;Arch Linux,容器环境Podman
个人的需求其实很简单,只是一个相册分类 + 照片时间线预览。要说特殊需求大概就是有大量的HEIC图片,毕竟谁的空间也不是大风刮来的,另外最好能够用类MySQL。 要说人还是闲不住,后面实测了Photoprism、Photoview和Immich,所以不知不觉变成真横评了。对于其他服务,可以看这个非常直观的表格。
以下依据为个人2024/06的照片库,约10000张照片,40GB。
Photoprism
算是比较早的开源相册方案了,基本功能令人安心,但使用略有不便,且设置界面可设置的项较少。
- 数据库支持:MariaDB(MySQL)和SQLite,比较友好。
- 部署:方式为容器,需要设置大量环境变量作为配置,而不能在网页上直接修改,较为繁琐。
- 资源占用:不索引时(不含数据库)占用内存42MB左右,索引时约为220MB;数据库中数据65MB,缩略图等数据15GB;容器镜像1.88GB。
- 文件管理:支持导入和外部资料库,后者不改变原有文件结构;HEIC等格式图片会自动转换为JPEG。
- 人脸识别:识别不出几个人,水平不大行。
- 搜索:提前给图片生成标签,可以搜索,也可以自行添加标签。
Photoview
官方认可 AUR,好耶!相对来说,手动安装过程是最简单而且符合直觉的。托打包者和开发者的福,在安装AUR后,只需要修改一下配置文件里的MySQL连接参数(或者直接改成SQLite),然后启动systemd服务即可。功能相对来说简单,不过对我来说够用。人脸识别的准确度很一般,但对我来说也是锦上添花的功能。
提示:如果不想或不能改变文件所有权,建议使用文件ACL setfacl -Rdm 命令为photoview用户授予循环继承权限。
用下来几天发现了两个主要的问题,一个是一次导入过多照片的时候会卡住(假完成),阈值大约100张,另一个是HEIC图片的EXIF可能不能正确识别(提了 issue)。自从作者不太积极开发这个项目之后,感觉基本停滞了。
虽然这个占用是真的小,但需要声明的是,索引的时候仍然会消耗较多CPU,除非每次都大半夜索引,否则还是没有想象中那么省性能的。
- 数据库支持:MySQL或PostgreSQL。
- 部署:有AUR,有Systemd部署文档,但个人建议直接用容器。
- 资源占用:索引时250MB,日常10MB;缩略图等数据占用存储4.5GB,数据库20MB,镜像1.38GB。
- 文件管理:完全尊重外部文件结构,不会改变。但索引有些小bug,见上。
- 人脸识别:聊胜于无吧,精度不大行。
- 搜索:基于文件名的搜索,别的都没有。
Immich
Immich也是后起之秀了,现在Star比前辈Photoprism还多。它相对来说就比较复杂了,占用资源也多很多,算上数据库下来五个容器(但看起来不久之后会变成 4 个)。但是相对的,可自定义度也高很多,尤其是机器学习的部分。
上述机器学习指的是人脸识别和图像搜索,均可以远程进行,即在性能强的机器上单独运行ML容器,然后通过API通信。这对人脸来说十分方便,因为较大的人脸识别模型占用很大,但对于基于CLIP的图像搜索来说就是另一回事了:不光在索引时需要机器学习模块,搜索时也需要。所幸CLIP搜索的原理为对图片和检索词分别生成向量,然后将两者进行对比,而消耗资源比较多的部分是生成图片向量,所以可以先用较强的远程机器生成图片向量,我NUC上的弱鸡CPU只用来跑检索。还算可以接受。
- 数据库支持:PostgreSQL+Redis,需同时运行。
- 部署:似乎十分复杂,个人建议直接用容器。Docker Compose好说,Podman的话会非常麻烦。
- 资源占用:索引时内存基本上吃完(这是我的NUC头一次吃SWAP),如果使用NVIDIA硬件加速机器学习,还会占用约5-8GB显存(因为我卡只有8GB);平时内存占用约400+200MB;缩略图等数据占用5.7GB(可使用WEBP,降低了占用),数据库563MB,镜像1.6GB+790MB(若使用CUDA则为4.55GB)。
- 文件管理:同时支持导入和外部资料库。
- 人脸识别:用较大模型的时候准确度蛮高的。
- 搜索:基于CLIP的自然语言搜索,遥遥领先,但缺点见上。也可以根据人脸、设备等条件筛选。
结语
很缺资源的选Photoview,性能足够的选Immich,嫌Photoview还不够强的选Photoprism。
附录:将 Immich 部署为 Podman Pod
默认以rootful方式部署,将文件放在 /etc/containers/systemd 或其子目录下,systemctl daemon reload 后 systemctl start immich-server.service 即可。
不要忘记修改下面的目录映射和环境变量。两个目录映射中,一个是内部存储(由Immich决定文件结构),一个是外部存储(保留用户的文件结构)。
Pod声明 immich.pod
[Pod]
PodName=immich
PublishPort=2283:3001immich.env
# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# Connection secret for postgres. You should change it to a random password.
# The two values should match
DB_PASSWORD=ZWEuFZHcEyuJJoR6
POSTGRES_PASSWORD=ZWEuFZHcEyuJJoR6
# The values below this line do not need to be changed
###################################################################################
DB_HOSTNAME=immich_postgres
DB_USERNAME=postgres
POSTGRES_USER=postgres
DB_DATABASE_NAME=immich
POSTGRES_DB=immich
REDIS_HOSTNAME=immich_redis
IMMICH_MACHINE_LEARNING_URL=http://immich_machine_learning:3003数据库容器 immich-postgres.container
[Container]
Pod=immich.pod
ContainerName=immich_postgres
EnvironmentFile=immich.env
Image=docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
Volume=pgdata:/var/lib/postgresql/data
HealthCmd=["/usr/bin/pg_isready"]
HealthStartPeriod=30s
HealthInterval=10s
HealthTimeout=5s
HealthRetries=5
Notify=healthy
[Service]
Restart=always缓存容器 immich-redis.container
[Container]
Pod=immich.pod
ContainerName=immich_redis
Image=docker.io/redis:6.2-alpine@sha256:51d6c56749a4243096327e3fb964a48ed92254357108449cb6e23999c37773c5
HealthCmd=["/usr/local/bin/redis-cli", "ping"]
HealthStartPeriod=30s
HealthInterval=10s
HealthTimeout=5s
HealthRetries=5
Notify=healthy
[Service]
Restart=always
[Install]
WantedBy=multi-user.target机器学习容器 immich-machine-learning.container(本地,无硬件加速)
[Container]
Pod=immich.pod
ContainerName=immich_machine_learning
EnvironmentFile=immich.env
Environment=HF_ENDPOINT=https://hf-mirror.com
Environment=LOG_LEVEL=debug
Image=ghcr.io/immich-app/immich-machine-learning:release
AutoUpdate=registry
Volume=model-cache:/cache
HealthCmd=["/bin/bash", "-c", "exec 5<>/dev/tcp/127.0.0.1/3003"]
HealthStartPeriod=30s
HealthInterval=10s
HealthTimeout=5s
HealthRetries=5
Notify=healthy
[Service]
Restart=always机器学习容器 immich-machine-learning.container(远程,CUDA加速)
[Container]
ContainerName=immich_machine_learning
Image=ghcr.io/immich-app/immich-machine-learning:release-cuda
Volume=model-cache:/cache
HealthCmd=["/bin/bash", "-c", "exec 5<>/dev/tcp/127.0.0.1/3003"]
HealthStartPeriod=30s
AutoUpdate=registry
PublishPort=3003:3003
HealthInterval=10s
HealthTimeout=5s
HealthRetries=5
Notify=healthy
Environment=LOG_LEVEL=debug
Environment=HF_ENDPOINT=https://hf-mirror.com
AddDevice=nvidia.com/gpu=all
[Service]
Restart=always微服务(如索引等)容器 immich-microservices.container(带有Intel QSV支持)
[Unit]
Requires=immich-redis.service immich-database.service
After=immich-redis.service immich-database.service
[Container]
Pod=immich.pod
ContainerName=immich_microservices
EnvironmentFile=immich.env
Exec=start.sh microservices
Image=ghcr.io/immich-app/immich-server:release
Volume=/path/to/internal/storage:/usr/src/app/upload:z
Volume=/etc/localtime:/etc/localtime:ro
Volume=/path/to/external/storage:/usr/src/app/external:z
HealthCmd=["/bin/bash", "-c", "exec 5<>/dev/tcp/127.0.0.1/3002"]
HealthStartPeriod=30s
AddDevice=/dev/dri
HealthInterval=10s
HealthTimeout=5s
HealthRetries=5
Notify=healthy
[Service]
Restart=always主服务容器 immich-server.container
[Unit]
Requires=immich-redis.service immich-database.service immich-microservices.service
After=immich-redis.service immich-database.service immich-microservices.service
[Container]
Pod=immich.pod
ContainerName=immich_server
EnvironmentFile=immich.env
Exec=start.sh immich
Image=ghcr.io/immich-app/immich-server:release
AutoUpdate=registry
Volume=/path/to/internal/storage:/usr/src/app/upload:z
Volume=/etc/localtime:/etc/localtime:ro
Volume=/path/to/external/storage:/usr/src/app/external:z
HealthCmd=["/bin/bash", "-c", "exec 5<>/dev/tcp/127.0.0.1/3001"]
HealthStartPeriod=30s
HealthInterval=10s
HealthTimeout=30s
HealthRetries=10
Notify=healthy
[Service]
Restart=always
[Install]
WantedBy=default.target网络上的其他讨论可见 Reddit 帖 1、Reddit 帖 2