Ubuntu + Immich + GPU 加速完整部署
背景
之前一直在用群辉的synology photo,只能说还不错,但说不上优秀。因为查找照片不是很好找,不支持AI,外加最近为了让老婆也能直接自行使用otp,把home下面的photos挪到了根目录下,也就变成了共享照片。这个操作之前没操作过,我是直接用命令cp的,导致我之前编辑的人脸数据,以及相册数据都没了……要从1TB的照片和视频中重新把之前的相册聚起来,基本不太可能。所以就想看看是否有支持AI功能的个人相册,让我轻松找到想找的照片,因此才有了这篇文章。
经过查找,immich不错,比较符合我的要求,正好我还有一台老电脑没有卖,直接利旧了~ 我本想是安装黑群晖的,但经过对比后,果断直接linux + immich + gpu硬件加速了;这样除了把照片慢慢挪过去外,其他的一些非重要数据可以也都挪到老电脑上,老电脑直接装一个smb就可以满足我了,等群辉以后有更好的解决方案,到时再看是否回去。
磁盘规划
推荐分离系统盘和数据盘:
| 盘 | 格式 | 挂载点 | 用途 |
| NVMe 256G | LVM/ext4 | / | 系统 + Docker + Immich 数据库/缓存 |
| 4T 机械盘 | ext4 | /mnt/photos | 照片/视频存储 |
| 1T 机械盘 | ext4 | /mnt/backup | 备份或扩展存储 |
我开始是把4T机械硬盘跟NVME错误的合到一个LVM虚拟磁盘了(可以参考我之前的一篇文章:lvm-resize-ubuntu14.04),通过下面方法可以把机械盘拆开:
用 Live USB 启动,缩小 LV
# 激活 LVM
sudo vgchange -ay
# 检查文件系统
sudo e2fsck -f /dev/mapper/ubuntu--vg-ubuntu--lv
# 查看 NVMe 的 PE 数量
sudo pvdisplay /dev/nvme0n1p3 | grep "Total PE"
# 精确缩小到 NVMe 的 PE 数量(假设是 60268)
sudo lvreduce --resizefs -l 60268 ubuntu-vg/ubuntu-lv
# 移除机械盘
sudo vgreduce ubuntu-vg /dev/sda1
sudo pvremove /dev/sda1
# 确认结果
sudo pvs
sudo vgs
重启后格式化机械盘
# 创建分区
sudo parted /dev/sda --script mklabel gpt mkpart primary ext4 0% 100%
sudo parted /dev/sdb --script mklabel gpt mkpart primary ext4 0% 100%
# 格式化
sudo mkfs.ext4 /dev/sda1
sudo mkfs.ext4 /dev/sdb1
# 创建挂载点
sudo mkdir -p /mnt/photos /mnt/backup
# 挂载
sudo mount /dev/sda1 /mnt/photos
sudo mount /dev/sdb1 /mnt/backup
# 写入 fstab 开机自动挂载
echo "UUID=$(blkid -s UUID -o value /dev/sda1) /mnt/photos ext4 defaults 0 2" | sudo tee -a /etc/fstab
echo "UUID=$(blkid -s UUID -o value /dev/sdb1) /mnt/backup ext4 defaults 0 2" | sudo tee -a /etc/fstab
# 验证
sudo umount /mnt/photos /mnt/backup
sudo mount -a
df -h | grep mnt
扩展NVME磁盘
lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
如果不额外配置,默认会分配大概60G左右给lvm nvme分区,这样会导致nvme分区很快就满了。虽然我把照片都放到其他硬盘上,但docker和相关文件数据库都会存在nvme分区中,这样等超过限制后,immich会挂掉导致无法启动。直接用下面命令扩充到最大:
网络代理配置(Nekoray)
Linux服务器第一件事就是要解决网络问题,经过确认和测试,最终使用Nekoray来作为client,最终还是回归到v2rayN:
安装并运行
https://github.com/2dust/v2rayN
sudo apt install libqt5widgets5 libqt5network5 libqt5gui5 libqt5core5a libqt5svg5 libqt5x11extras5
wget https://github.com/MatsuriDayo/nekoray/releases/download/3.26/nekoray-3.26-2023-12-09-linux64.zip
unzip nekoray-3.26-2023-12-09-linux64.zip
cd nekoray
./nekoray
DNS 配置建议
- 远程 DNS:
8.8.8.8或1.1.1.1(不要用 DoH 格式如https://8.8.8.8/dns-query) - 直连 DNS:
223.5.5.5(阿里)或119.29.29.29(腾讯)
安装 Nvidia 相关工具和 Docker
由于我要使用docker部署immich,为了从docker调用gpu资源,我需要安装Nvidia Container Toolkit
sudo apt update
sudo apt install nvidia-driver-535
sudo reboot
# 验证
nvidia-smi
# 安装docker
sudo -E curl -fsSL https://get.docker.com | sh
# 添加 GPG key
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
# 添加仓库
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# 安装
sudo apt update
sudo apt install -y nvidia-container-toolkit
# 配置 Docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
# 验证容器能看到 GPU
sudo docker run --rm --gpus all nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi
部署 Immich
下载配置文件
mkdir ~/immich && cd ~/immich
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
修改 docker-compose.yml
修改 immich-server,添加外部照片目录挂载。另外默认immich的地理数据对中国地名支持不好,使用社区项目替换,项目地址:https://github.com/ZingLix/immich-geodata-cn,下载解压后有两个目录,分别挂载在volumes下:
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
- /mnt/photos:/mnt/photos:ro # 外部照片目录,只读
- ./geodata:/build/geodata # geodata-cn 数据
- ./i18n-iso-countries/langs:/usr/src/app/server/node_modules/i18n-iso-countries/langs # geodata-cn 数据
修改 immich-machine-learning,启用 CUDA 加速,注意默认的模型对中文支持的很差,建议直接使用XLM-Roberta-Large-Vit-B-16Plus这个模型:
immich-machine-learning:
container_name: immich_machine_learning
# 重要:必须使用 -cuda 后缀的镜像
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda
extends:
file: hwaccel.ml.yml
service: cuda
devices:
- /dev/dri:/dev/dri # 指定gpu路径
volumes:
- model-cache:/cache
- /sys/class/drm:/sys/class/drm:ro # 指定gpu路径
env_file:
- .env
restart: always
healthcheck:
disable: false
修改Docker IP地址分配:
如果使用 tunnel 模式模式搭TZ,他的IP有可能跟Docker IP冲突,所以建议把地址分开:
networks:
default:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
启动 Immich
cd ~/immich
docker compose up -d
验证 GPU 加速是否工作
# 查看容器日志
sudo docker logs immich_machine_learning 2>&1 | grep -i "cuda\|provider"
# 应该看到:
# Setting execution providers to ['CUDAExecutionProvider', 'CPUExecutionProvider']
# 查看 GPU 使用情况
nvidia-smi
# 在容器内验证
sudo docker exec immich_machine_learning nvidia-smi
访问 Immich
打开浏览器访问 http://服务器IP:2283,完成初始化设置。
外部库特点
- Immich 不会移动、重命名、删除你的文件
- 文件夹结构完全由你控制
- AI 识别、人脸分组、时间线都能用
- 在 Immich 里修改 GPS、日期等,存在数据库,原文件不变
- 在 Immich 里删除照片只是从数据库移除,原文件不受影响(这点不是很好,管理不同步,只能把管理好的照片放进去让immich检索和查阅)
从群晖迁移照片
挂载群晖共享文件夹
sudo apt install cifs-utils
sudo mkdir -p /mnt/synology
# 挂载(替换实际信息)
sudo mount -t cifs //群晖IP/photo /mnt/synology -o username=用户名,password=密码,vers=3.0
# 验证
ls /mnt/synology
使用 rsync 复制照片
# 查看数据量
du -sh /mnt/synology
# 预演(不实际复制)
rsync -avP --dry-run /mnt/synology/ /mnt/photos/
# 正式复制
rsync -avP /mnt/synology/ /mnt/photos/
安装Samba服务
安装Samba
虽然用rsync可以同步数据,但无法可视化,我很多工具如Beyoned Compare就无法直接使用,因此还是需要把Samba服务搭起来,这样后面对比和操作都会很简单。
sudo apt install samba -y
ls -ld /mnt/backup /mnt/photos #确认归属
sudo chown -R frank:frank /mnt/photos
sudo chown -R frank:frank /mnt/backup
sudo smbpasswd -a frank & sudo smbpasswd -e frank
sudo nano /etc/samba/smb.conf
[photos]
comment = Photos Library
path = /mnt/photos
browsable = yes
read only = no
valid users = frank
create mask = 0664
directory mask = 0775
force user = frank
[backup]
comment = Backup Drive
path = /mnt/backup
browsable = yes
read only = no
valid users = frank
create mask = 0664
directory mask = 0775
force user = frank
sudo systemctl restart smbd nmbd
sudo systemctl enable smbd nmbd
testparm -s #检查配置,确认两个 share 都出现
解决自动发现问题
Windows 网络发现用的是 WS-Discovery (WSDiscovery) 协议(Windows 10 1709 之后),而不是老的 NetBIOS/WINS。Samba 的 nmbd 只处理 NetBIOS,无法响应 WS-Discovery 广播。
sudo apt install wsdd -y
sudo tee /etc/systemd/system/wsdd.service << 'EOF'
[Unit]
Description=WS-Discovery Daemon
After=network-online.target samba.service
Wants=network-online.target
[Service]
ExecStart=/usr/sbin/wsdd
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable wsdd --now
sudo systemctl status wsdd
参数说明:
-a:归档模式,保留权限、时间等-v:显示详细信息-P:显示进度 + 支持断点续传--delete:(可选)同步删除,源端删除的文件目标端也删除
Immich 使用技巧
人脸管理
- Explore → People 查看识别出的人脸点
- 击人脸可以重命名、合并重复的人、隐藏不相关的人
修改照片/视频日期
- 在照片详情页,点 ⋮ → Edit Date & Time
- 修改存在数据库,原文件不变
机器学习设置
- Administration → Settings → Machine Learning
- 可调整人脸识别置信度、启用/禁用各项 AI 功能
- 上面说的
XLM-Roberta-Large-Vit-B-16Plus这个模型,替换默认的ViT-B-32
任务队列
- Administration → Jobs
- 查看后台任务进度,可手动触发人脸识别、生成缩略图等
- 比如更新geo数据库后,需要重新让immich提取元数据
照片结构变更
如果照片文件夹结构变更,所有人脸和缩率图,亦或是之前提取的元组都需要重新生成,但之前老的数据不会自动清除,会放到immich垃圾桶中存放30天。此时在垃圾桶中选择1个照片,并用crtl + a,可以选择所有过期数据,此时再删除就可以把旧的数据清除掉了。如果不选择照片,直接点清除垃圾桶是删不掉任何数据的。
服务器功耗优化
服务器用于immich需要长期运行,降低功耗可以减少发热和电费
CPU功耗优化
# 安装 cpupower
sudo apt install linux-tools-common linux-tools-$(uname -r)
# 设置为节能模式
sudo cpupower frequency-set -g powersave
# 查看当前状态
cpupower frequency-info
GPU 功耗优化(GTX 1060)
# 开启持久化模式,避免驱动反复加载
sudo nvidia-smi -pm 1
# 功耗限制在 60-70W(默认 120W,跑 AI 推理 60W 足够)
sudo nvidia-smi -pl 60
# 锁定核心频率在 1000MHz,避免瞬间超频导致发热
sudo nvidia-smi -lgc 1000
# 避免重启恢复,写入crontab中:
sudo crontab -e
@reboot nvidia-smi -pm 1 && nvidia-smi -pl 760 && nvidia-smi -lgc 1000
服务器升级及维护
升级
社区很活跃,经常会遇到升级。看到提示后要进github看下是否有 Breaking Changes 标签,有时候需要手动修改 .env 文件或 docker-compose.yml 配置,由于我不是主要服务器,所以直接就升级了,有问题再解决了。方法很简单:
- docker compose pull
- docker compose up -d
存储管理
最近在整理照片,然后逐渐补齐之前确实时间和gps信息的照片,从2006年开始已经整理到2018年了,下面是13年的照片和视频占用的空间,还剩8年,照片和视频只能会越来越多,而不是越来越少:
root@frank-MS:/mnt/photos# sudo docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 5 14.2GB 14.2GB (100%)
Containers 5 5 2.773MB 0B (0%)
Local Volumes 1 1 3.726GB 0B (0%)
Build Cache 0 0 0B 0B
root@frank-MS:/home/frank/immich# sudo du -sh /home/frank/immich/library/*/
2.7G /home/frank/immich/library/backups/
24G /home/frank/immich/library/encoded-video/
8.0K /home/frank/immich/library/library/
8.0K /home/frank/immich/library/profile/
14G /home/frank/immich/library/thumbs/
8.0K /home/frank/immich/library/upload/
| library/encoded-video/ | 24G | 视频转码副本,大头 |
| library/thumbs/ | 14G | 缩略图(3种尺寸) |
| library/backups/ | 2.7G | 数据库自动备份 |
| library/postgres/ | 1.1G | 数据库本体 |
| ML model cache | 3.5G | Docker volume |
| Docker 镜像 | 14.2G | 5个容器镜像 |
| 系统+其他 | ~20G | Ubuntu系统等 |
由于我的 NVME硬盘空间有限,最大也就256G,可用231G,所以我要改变下转码方式。起初我把转码关了,发现Web打开mov这种视频非常卡,iPhone打开OK。但打开默认的,mov这些没问题,但4k的视频加载还是很慢(这里就不纠结为啥这里慢,油管和bilibili没问题,里面肯定有各种原因),一卡一卡的。因此最终把转码策略改成了:“视频超过目标分辨率或格式不支持” ,默认目标分辨率是720p,把转码文件单独放入一个独立硬盘中,正好我还有一个1T的硬盘没有在用:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
- /mnt/photos:/mnt/photos:ro
- ./geodata:/build/geodata
- ./i18n-iso-countries/langs:/usr/src/app/server/node_modules/i18n-iso-countries/langs
- /mnt/backup/immich-encoded-video:/data/encoded-video #202605 update
可以看到,更改后,转码视频增加了小3倍,但问题彻底解决了
root@frank-MS-7B45:/home/frank# sudo du -sh /mnt/backup/immich-encoded-video/
68G /mnt/backup/immich-encoded-video/