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_pgdatatarget: /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=50ps 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 等为 Uphealthyinit_permissionsExited 正常。

然后浏览器打开:

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
相关推荐
weixin_462901971 小时前
TCP+WebSocket双向转发服务器 完整部署运维手册
运维·websocket·tcp/ip
软件资深者2 小时前
QQ音乐PC版 使用教程:去广告绿色便携版音乐播放器,本地曲库管理与在线试听一键搞定,音乐播放器新手 5 分钟上手(2026)
测试工具·容器·娱乐·软件需求
AAA@峥2 小时前
Ceph RBD 块存储全解析:原理与实操汇总
运维·分布式·ceph
2301_777998342 小时前
Linux线程控制——从线程创建到线程分离(第三部分:线程等待 pthread_join)
linux·运维·服务器·c语言·c++
维核科技2 小时前
AI Agent从“玩具“进化成“劳动力“:2026年智能体商业化元年
运维·人工智能·服务器维修·gpu维修
谜之锋3 小时前
Linux 源码编译安装 net-snmp-5.9.1 并配置使用 SNMPv3
linux·运维·服务器·snmpv3
RuiZN3 小时前
Muduo---Channel类
运维·服务器·c++
一直在努力学习的菜鸟3 小时前
阿里云2G2核的服务器可以做什么?
linux·运维
可涵不会debug3 小时前
【LangChain系列】 零基础入门实战:从环境搭建到 LCEL 链式完整 Demo 详解
运维·服务器·langchain·vibe coding