dify的docker部署

dify的docker部署

bash 复制代码
cd ~
rm -rf dify
git clone --depth 1 https://gitee.com/dify_ai/dify.git
cd dify

# 尽量切到 1.16.0(若镜像暂无该 tag,先用默认分支也可先起)
git fetch --tags
git checkout 1.16.0 2>/dev/null || echo "镜像可能还没同步到 1.16.0,先用当前分支部署"

cd docker
cp .env.example .env
docker compose up -d

关键故障是 PostgreSQL 没起来,不是 init_permissions 退出(那个是正常的)。先查 db_postgres 的真实报错:

核心问题是 Postgres 容器启动失败,后面的 API/Worker 会因此被跳过。init_permissions Exited 是正常的,可以忽略。

先看真正报错(必做)

在 docker 目录执行:

bash 复制代码
docker compose logs db_postgres
# 或
docker logs docker-db_postgres-1

根因已经明确:不是内存,是 Postgres 数据目录写不进去。

text 复制代码
could not write to file "postmaster.pid": Operation not permitted
could not write to file "pg_wal/xlogtemp.33": Operation not permitted

容器在 initdb,但往挂载卷写文件被拒绝(权限 / SELinux 很常见,尤其 CentOS)。


修复步骤(按顺序做)

在 docker 目录执行:

1. 停服务并清掉半初始化的库目录

bash 复制代码
cd ~/dify/docker   # 改成你的实际路径
docker compose down

# 看 Postgres 挂载的是哪个目录
grep -A30 'db_postgres:' docker-compose.yaml | grep -E 'volumes|pgdata|postgres' 

ls -la volumes/

Dify 常见路径类似:volumes/db/data 或带 pgdata 的目录。确认后删除(新装无数据可删):

bash 复制代码
# 下面按你 ls 到的实际目录改,常见是这几种之一:
rm -rf ./volumes/db
# 或
# rm -rf ./volumes/postgres

2. 重建目录并交给 Postgres 用户(UID 999)

bash 复制代码
mkdir -p ./volumes/db/data
chown -R 999:999 ./volumes/db
chmod -R 700 ./volumes/db/data

若实际路径不是 volumes/db,对真实数据目录 做同样的 chown 999:999。

3. CentOS:处理 SELinux(很关键)

bash 复制代码
getenforce

若是 Enforcing:

bash 复制代码
# 给 Docker 卷目录正确上下文
chcon -Rt svirt_sandbox_file_t ./volumes/db

# 或临时关闭验证是否就是 SELinux(确认后再决定是否长期关闭)
# setenforce 0

4. 再启动并盯日志

bash 复制代码
docker compose up -d db_postgres
docker compose logs -f db_postgres

看到类似 database system is ready to accept connections / 容器 healthy 后:

bash 复制代码
docker compose up -d
docker compose ps

若仍报 Operation not permitted

再查这几项:

bash 复制代码
# 1) 数据目录是否在特殊挂载上(NFS/只读)
df -h ./volumes
mount | grep $(df ./volumes | tail -1 | awk '{print $1}')

# 2) 是否开了 user namespace 重映射
cat /etc/docker/daemon.json

# 3) 用临时容器验证能否写入
docker run --rm -v "$(pwd)/volumes/db/data:/var/lib/postgresql/data/pgdata" \
  postgres:15-alpine id

SELinux 已经是 Disabled ,可以排除。剩下就是:宿主机绑定目录对容器内的 postgres(UID 999)不可写。

按下面两条路做,优先走 命名卷(最省事)。


立刻执行:改用命名卷(推荐)

在 docker 目录:

bash 复制代码
docker compose down

cat > docker-compose.override.yml <<'EOF'
services:
  db_postgres:
    volumes:
      - dify_pgdata:/var/lib/postgresql/data
volumes:
  dify_pgdata:
EOF

docker compose up -d db_postgres
docker compose logs -f db_postgres

成功标志:日志里出现 database system is ready to accept connections,不再刷 Permission denied。

然后:

bash 复制代码
docker compose up -d
docker compose ps

若仍想用原来的 ./volumes/db 绑定

先看真实挂载和权限:

bash 复制代码
grep -A50 '^  db_postgres:' docker-compose.yaml | head -60
ls -laN ./volumes ./volumes/db ./volumes/db/data 2>/dev/null

再彻底重建权限:

bash 复制代码
docker compose down
rm -rf ./volumes/db
mkdir -p ./volumes/db/data
chown -R 999:999 ./volumes/db
chmod 700 ./volumes/db/data

# 验证:用同一 UID 能否在挂载点建目录
docker run --rm -u 999:999 \
  -v "$(pwd)/volumes/db/data:/var/lib/postgresql/data" \
  busybox mkdir -p /var/lib/postgresql/data/pgdata

docker compose up -d db_postgres
docker compose logs --tail=50 db_postgres

若上面的 busybox mkdir 也失败,说明目录仍不可写(属主不对、或父目录权限拦了),把 ls -laN 输出贴出来。


顺便清理孤儿容器警告(可选)

bash 复制代码
docker rm -f trendradar trendradar-mcp 2>/dev/null

与 Dify 无关,只是以前的容器还在。


建议: 直接用第一段 docker-compose.override.yml。SELinux 已关,命名卷一般一次就能过。成功或还有报错,把 logs --tail=40 发我。

你这条命令 搜偏了 :命中的是别的服务 depends_on 里的 db_postgres,不是数据库服务本身的定义,所以看不到 volumes / image。

换下面几条:

bash 复制代码
# 1) 看 db_postgres 服务完整配置(含 volumes)
docker compose config --format json | python3 -c "
import json,sys
c=json.load(sys.stdin)
s=c['services'].get('db_postgres') or c['services'].get('postgres')
print(json.dumps(s, indent=2, ensure_ascii=False) if s else '找不到 db_postgres 服务')
"

# 没有 python3 就用:
docker compose config | awk '/^  db_postgres:/{p=1} p&&/^  [a-z]/{if(!/^  db_postgres:/)exit} p'

# 2) 确认 override 是否生效
ls -la docker-compose.override.yml
cat docker-compose.override.yml

# 3) 看容器实际挂载
docker inspect docker-db_postgres-1 --format '{{json .Mounts}}' | python3 -m json.tool

期望结果: Mounts 里应是 type=volume、名字类似 docker_dify_pgdata / dify_pgdata,而不是 Source 指向宿主机 .../volumes/db/data。

若仍是绑定目录,说明 override 没生效,重新写并重启:

bash 复制代码
cat > docker-compose.override.yml <<'EOF'
services:
  db_postgres:
    volumes:
      - dify_pgdata:/var/lib/postgresql/data
    shm_size: "256mb"
    security_opt:
      - seccomp:unconfined
    privileged: true
volumes:
  dify_pgdata:
EOF

docker compose down
docker compose up -d db_postgres
docker compose logs -f db_postgres

把下面三段贴出来即可继续判断:

  1. cat docker-compose.override.yml
  2. docker inspect ... Mounts
  3. docker compose logs --tail=40 db_postgres

命名卷已经生效了,这一步是对的。

从你贴的 docker compose config 可以看出:

  • image: postgres:15-alpine(Dify 固定用 15,不是随便 latest)
  • source: dify_pgdata → target: /var/lib/postgresql/data
  • docker-compose.override.yml 已加载

也就是说:不再是宿主机 ./volumes/db 权限问题 。若日志里还有 Operation not permitted,就是 Docker/内核安全策略或存储层的问题。


下一步(直接做)

把 override 加强后再起一次:

bash 复制代码
cat > docker-compose.override.yml <<'EOF'
services:
  db_postgres:
    volumes:
      - dify_pgdata:/var/lib/postgresql/data
    shm_size: "256mb"
    security_opt:
      - seccomp:unconfined
    privileged: true
volumes:
  dify_pgdata:
EOF

docker compose down
# 清掉可能半初始化坏掉的卷
docker volume rm docker_dify_pgdata dify_pgdata 2>/dev/null
docker volume ls | grep -i dify

docker compose up -d db_postgres
sleep 3
docker compose logs --tail=50 db_postgres
docker compose ps db_postgres

同时确认实际挂载:

bash 复制代码
docker inspect docker-db_postgres-1 --format '{{range .Mounts}}{{.Type}} {{.Name}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'

怎么判断结果

日志 含义
ready to accept connections / 状态 healthy 成功,再 docker compose up -d
仍是 Operation not permitted 写 pid/WAL 容器卷这条路在这台机不好使 → 改用本机 Postgres
Cannot allocate memory / 被 Kill 内存不够(你机子约 3.7G,且配置里还有 effective_cache_size=4096MB,偏激进)

补充两点

  1. profiles: [postgresql]

    只起库时用 docker compose up -d db_postgres 没问题;全量启动若库没起来,可加:

    bash 复制代码
    export COMPOSE_PROFILES=postgresql
    docker compose up -d
  2. postgres:15-alpine 不是"没用最新"

    这是 Dify Compose 锁定的数据库大版本,和 Dify 应用 tag(如 1.16.0)是两回事,不要改成 postgres:latest。


先跑上面的 privileged 重启,把 logs --tail=50 和 ps db_postgres 贴出来。若还是 EPERM,就给你一套「本机 yum 装 Postgres + 改 .env」的最短命令。

Postgres 已经正常了。

  • 日志:database system is ready to accept connections
  • 状态:Up ... (healthy)
  • 挂载:命名卷 docker_dify_pgdata(方案生效)

接下来把整套服务拉起来:

bash 复制代码
# 若 compose 里库在 postgresql profile,建议带上
export COMPOSE_PROFILES=postgresql

docker compose up -d
docker compose ps

期望:api / worker / web / nginx / redis 等为 Up 或 healthy;init_permissions 为 Exited 正常。

然后浏览器打开:

text 复制代码
http://服务器公网IP/install

若 api 起不来,把下面输出贴出来:

bash 复制代码
docker compose ps
docker compose logs --tail=50 api
free -h

(机器约 3.7G 内存,全量起来后仍可能紧张,必要时加 Swap。)

部署已经起来了。

13/13 里该亮的都亮了:api / web / worker / nginx / db_postgres(healthy) 等均正常;init_permissions Exited 是一次性任务,正常。

访问

浏览器打开:

text 复制代码
http://你的服务器公网IP/install
相关推荐
一个天蝎座 白勺 程序猿13 小时前
KingbaseES数据库归档重做日志文件管理:从配置到运维的实战指南
运维·数据库·oracle·kingbasees·金仓数据库
分布式存储与RustFS17 小时前
镜像仓库的层别堆本地盘:用 RustFS 给 Docker Registry 当 S3 后端
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
陈希12317 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
@兽血沸腾19 小时前
Windows系统安装Jenkins部署应用至远程Windows服务器操作指南
运维·服务器·jenkins
闲云自留地1 天前
K8s 的记忆大脑!ETCD 集群部署、etcdctl 命令与备份恢复全通关
容器·kubernetes·etcd
讯捷蓝达1 天前
戴尔R720xd服务器卡死在 “Configuring Memory...Done“,换了内存还是卡?问题根本不在内存
运维·服务器
爱和冰阔落1 天前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
lisanmengmeng1 天前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮1 天前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
上火的金鱼妹1 天前
k8s生产实际问题排查(网关,数据库读写等)
运维·服务器