安装 Docker-部署 Qanything/Dify 项目

· 4304字 · 9分钟

登录服务器,在一切开始之前先了解系统环境。

  1. 检查操作系统的类型和版本。服务器是 Anolis os 系统,接近 Centos 8.9,架构类型是 x86_64。
>uanme -a
Linux 主机名称 4.19.91-26.an8.x86_64 #1 SMP Tue May 24 13:10:09 CST 2022 x86_64 x86_64 x86_64 GNU/Linux

>cat /etc/os-release
NAME="Anolis OS"
VERSION="8.9"
ID="anolis"
ID_LIKE="rhel fedora centos"
VERSION_ID="8.9"
PLATFORM_ID="platform:an8"
PRETTY_NAME="Anolis OS 8.9"
ANSI_COLOR="0;31"
HOME_URL="https://openanolis.cn/"
  1. 查看 CPU 核数,内存和磁盘的总量及已使用情况。CPU 有32核(0-31),可用的物理内存剩46G,折腾是够用的。
>lscpu
CPU(s):              32
Thread(s) per core:  2
CPU MHz:             2511.251

>free -h
              total        used        free      shared  buff/cache   available
Mem:           62Gi        14Gi        40Gi       617Mi       7.9Gi        46Gi
Swap:          63Gi          0B        63Gi
  1. 查看是否能连外网。初始状态不能连外网,若要连外网需要配置代理。
>ping baidu.com

一、服务器上安装 Docker 🔗

了解 Docker 需厘清三个概念:仓库(Repository)、镜像(Image)、容器(Container)。

举个栗子,这个网址https://hub.docker.com/是 Docker 官方的仓库,上面有很多镜像(Image),比如有不同版本的 mysql,拉取一个版本的 mysql 镜像到服务器上以后,启动镜像就能生成一个容器,在容器里 mysql 是运行起来的,可以修改的,但容器里的变化不会影响到镜像。再启动一次原来的 mysql 镜像会再生成一个新容器。

我们使用 R 会接触到 CRAN(Comprehensive R Archive Network,分发 R 和 R 包的网络仓库系统),在这个网址https://cran.r-project.org/mirrors.html列示了许多不同的镜像网站的地址,比如常见的清华大学镜像https://mirrors.tuna.tsinghua.edu.cn/CRAN/,这里的镜像(Mirrors)实际上是存放了 R 和 R 包的仓库,当我们在本地电脑上从镜像网站下载安装了 R 和 R 包,任何改动都会保存在本地,如果改错把 R 整崩溃了,只能重新从镜像网站再下载安装。

1.1.离线安装(Anolis8.6) 🔗

之前在另一台服务器上面离线安装了一次,整个过程简单来说就是:手动下载各个 rpm 包–>手动安装–>启动 Docker。

首先,从官方镜像网站国内镜像网站下载以下7个包,可以参照docker-ce/docker-ce-cli/containerd.io这三个主要组件名称选日期同一天的版本。

  1. docker-ce:Docker 社区版引擎。
  2. docker-ce-cli:Docker 命令行工具。
  3. containerd.io:容器。
  4. docker-compose-plugin:编排多个容器。
  5. docker-scan-plugin:用于扫描 Docker 镜像中的安全漏洞。
  6. docker-buildx:用于构建多平台镜像。
  7. docker-ce-rootless-extras:用于支持 Docker 的 Rootless 模式。Rootless 模式允许 Docker 守护进程和容器以非 root 用户身份运行。

接着,依次手动安装7个包,这个过程中会遇到一些问题导致装不上。键者遇到的问题有这些。

  • 需要升级 runc。也是手动下载新版本,随后手动安装即可。
# 备份原来的 runc 二进制文件
sudo mv /usr/bin/runc /usr/bin/runc.bak

# 移动并重命名,然后赋予权限
sudo mv /home/hadoop/docker/runc.amd64 /usr/bin/runc
sudo chmod +x /usr/bin/runc

# 查看是否成功升级
runc --version
  • 需要安装缺少的依赖包。安装 docker-ce 报错缺少 libcgroup,那么就查找一番。安装 containerd.io 报错缺少 containers-common,1.2.4版本太低,换1-82重新装,也要这里那里翻找一会。

  • 有些包的版本之间会起冲突,需要不断反复尝试。下面是键者尝试的过程,这里只是记录,实在是没有参考意义。

# 切换到 rpm 文件所在目录
cd /home/hadoop/docker/
ls -l

# 逐一安装,使用 --disablerepo 选项禁用外部仓库
# 由于和 buildah 包起冲突,暂时用 --skip-broken 跳过
sudo yum localinstall containerd.io-1.6.24-3.1.el8.x86_64.rpm --disablerepo=* --skip-broken
sudo yum localinstall docker-buildx-plugin-0.11.2-1.el8.x86_64.rpm --disablerepo=*
sudo yum localinstall docker-scan-plugin-0.23.0-3.el8.x86_64.rpm --disablerepo=*
sudo yum localinstall docker-compose-plugin-2.24.6-1.el8.x86_64.rpm --disablerepo=*
sudo yum localinstall docker-ce-cli-24.0.6-1.el8.x86_64.rpm --disablerepo=*

# 安装缺失的依赖
sudo yum localinstall libcgroup-0.41-19.el8.x86_64.rpm --disablerepo=*
sudo yum localinstall libcgroup-tools-0.41-19.el8.x86_64.rpm --disablerepo=*

# 三个一起互相依赖,一起安装,跳过冲突
sudo yum localinstall docker-ce-24.0.6-1.el8.x86_64.rpm docker-ce-rootless-extras-24.0.6-1.el8.x86_64.rpm containerd.io-1.6.24-3.1.el8.x86_64.rpm --disablerepo=* --skip-broken

# 检查哪些包没安装上
rpm -qa | grep -E 'docker-ce|docker-ce-cli|containerd.io|docker-buildx|docker-scan|docker-compose|docker-ce-rootless'

# 重新安装 containerd.io
sudo yum localinstall containerd.io-1.6.24-3.1.el8.x86_64.rpm --disablerepo=* ----allowerasing

# docker-ce 和 docker-ce-rootless一起安装
sudo yum localinstall docker-ce-24.0.6-1.el8.x86_64.rpm docker-ce-rootless-extras-24.0.6-1.el8.x86_64.rpm --disablerepo=*

# 查看安装好的 docker 版本
docker --version

1.2.在线安装(Anolis8.9) 🔗

服务器上在线安装 Docker 需要配置很多层网络代理,下面在修改配置文件时统一使用 nano 文本编辑器,因为修改后保存文件只需要按 ctrl + x。

  1. 给服务器配置代理,服务器才可以连接外网。
nano ~/.bashrc

# 在打开的文件中,添加以下内容,并按 ctrl + x 保存
export http_proxy='http://proxy.example.com:port'
export https_proxy='http://proxy.example.com:port'

source ~/.bashrc

# 检查能否连外网
wget www.baidu.com
  1. 配置包管理器(dnf/yum/rpm)的代理,才能正常下载镜像网站的安装包。
# 配置 dnf 的代理
sudo nano /etc/dnf/dnf.conf
# 添加
proxy=http://proxy.example.com:port

# 配置 yum 的代理
sudo nano /etc/yum.conf
# 添加
proxy=http://proxy.example.com:port

# 配置 rpm 的代理
sudo nano /etc/rpm/macros
# 添加
_http_proxy=http://proxy.example.com:port
_https_proxy=http://proxy.example.com:port

# 检查能否联网更新
rpm -qa
sudo dnf update

报出如下错误。

Errors during downloading metadata for repository ‘Anolis8.6-App’:

  • Curl error (28): Timeout was reached for ftp://10.14.140.100/AnolisOS8.6-QU/AppStream/repodata/repomd.xml [Operation too slow. Less than 1000 bytes/sec transferred the last 30 seconds]

Error: Failed to download metadata for repo ‘Anolis8.6-App’: Cannot download repomd.xml: Cannot download repodata/repomd.xml: All mirrors were tried

检查有无与 Anolis8.6相关的仓库,找到 Anolis8.6-App 和 Anolis8.6-Base ,干脆直接禁用。再执行sudo dnf update还是报相似错误,只是报错的仓库变成了 update。明明这次在线安装的系统版本是 Anolis8.9,但是这个 update 仓库指向的地址还是 Anolis8.6,而且ftp://10.14.140.100/AnolisOS8.6-QU_update_last/repodata/repomd.xml这个地址是真的不可访问,干脆把这个仓库也禁用算逑。

# 检查有无与 Anolis8.6相关的仓库,无
ls /etc/yum.repos.d/

# 也检查,有 Anolis8.6-App Anolis8.6-Base 两个
sudo dnf repolist

# 直接禁用
sudo dnf config-manager --set-disabled Anolis8.6-App
sudo dnf config-manager --set-disabled Anolis8.6-Base
sudo dnf config-manager --set-disabled update

# 清理旧缓存,生成新缓存
sudo dnf clean all
sudo dnf makecache
# 再检查能否联网更新
sudo dnf update
  1. 下载并安装 Docker。
# 添加仓库地址的配置文件
sudo nano /etc/yum.repos.d/docker-ce.repo

# 添加以下内容,并按 ctrl + x 保存
[docker-ce-stable]
name=Docker CE Stable - 8
baseurl=https://download.docker.com/linux/centos/8/x86_64/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

sudo dnf clean all
sudo dnf makecache

# 启用配置的仓库下载安装
sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-scan-plugin docker-buildx docker-ce-rootless-extras --enablerepo=docker-ce-stable --skip-broken

# 检查哪些包没安装上,缺少 containerd.io
rpm -qa | grep -E 'docker-ce|docker-ce-cli|containerd.io|docker-buildx|docker-scan|docker-compose|docker-ce-rootless'

# 检查 containerd.io 是否安装成功
containerd --version

# 启动 docker
sudo systemctl start docker

# 检查服务状态,看到 active (running)代表正常
sudo systemctl status docker

● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2024-12-09 16:52:41 CST; 23s ago
Docs: https://docs.docker.com

  1. 配置 docker 的代理,才能正常拉取外网的镜像。
# 修改配置文件
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf

# 添加以下内容,并按 ctrl + x 保存
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:port"
Environment="HTTPS_PROXY=http://proxy.example.com:port"

# 重新加载配置文件
sudo systemctl daemon-reload

# 重启 docker
sudo systemctl restart docker

# 测试能否拉取镜像,如果返回 pull complete 表示能连外网
sudo docker pull hello-world
  1. 建立 docker 用户组,后续使用 docker 命令可以不加 sudo。
# 运行 hello-world
sudo docker run hello-world
# 查看所有容器状态(up 代表运行中)
sudo docker ps -a

# 建立 docker 组
sudo groupadd docker
# 将 hadoop 用户加入 docker 组
sudo usermod -aG docker hadoop

newgrp docker

二、部署 QAnything 项目 🔗

QAnything 是 Github 上面的一个知识库问答项目,根据其中文文档进行部署,步骤很简单。这个项目现在还不够成熟,部署过程中会出错,只能根据报错信息具体问题具体分析。

  1. 安装 Git,克隆项目,启动。

首次启动的过程包括了拉取镜像,如果网速不够快,就得等一会。

# 安装 git
sudo dnf install git  
# 创建新目录
mkdir -p /home/hadoop/QAnything/
# 克隆项目,存到指定目录
git clone https://github.com/netease-youdao/QAnything.git /home/hadoop/QAnything/

cd /home/hadoop/QAnything/

# 启动
docker compose -f docker-compose-linux.yaml up -d
  1. 启动成功但页面打开报 404 错误。

查看logs/debug_logs/debug.log文件,找到以下错误。错误跟数据库中表的操作有关,所以需要登录数据库来查看具体问题。

2024-12-10 06:41:59,285 - [PID: 1118][Sanic-Server-0-0] - [Function: execute_query_] - ERROR - 执行数据库操作失败:1060 (42S21): Duplicate column name ’llm_setting’,SQL:ALTER TABLE QanythingBot ADD COLUMN llm_setting VARCHAR(512) DEFAULT ‘{}’

2024-12-10 06:41:59,286 - [PID: 1118][Sanic-Server-0-0] - [Function: create_tables_] - INFO - Index created successfully: ALTER TABLE QanythingBot ADD COLUMN llm_setting VARCHAR(512) DEFAULT ‘{}’

2024-12-10 06:41:59,287 - [PID: 1118][Sanic-Server-0-0] - [Function: execute_query_] - ERROR - 执行数据库操作失败:1091 (42000): Can’t DROP ‘model’; check that column/key exists,SQL:ALTER TABLE QanythingBot DROP COLUMN model

这个项目用的是 mysql 数据库,登录后根据提示的错误信息查看 QanythingBot 这张表,由于是执行ALTER TABLE QanythingBot DROP COLUMN model语句时报错,看到该表里确实没有名为 model 的字段,所以启动的进程中自动删除该字段才会报错。那么加上这个字段就行。

# 查看容器信息
docker ps 

# 进入 mysql 容器
docker exec -it 603bcf640adb /bin/bash

# 登录 mysql 数据库
mysql -u root -p #密码:123456

需要注意的是,在 mysql 里面执行 sql 语句时,代码末尾需要加上;符号。退出 mysql 是执行exit;,而退出容器是执行exit

# 查看数据库
show databases;

# 切换数据库
use qanything;

show tables;

describe QanythingBot;

#  QanythingBot 表里加上 model 字段
ALTER TABLE QanythingBot ADD COLUMN model VARCHAR(100) DEFAULT NULL;

# 退出数据库
exit;
  1. 页面能正常打开,但机器人无法生成答案。

启动项目后,在本地电脑的浏览器打开http://10.xx.x.xx:8777/qanything/(PS谷歌浏览器能正常显示),配置知识库和模型,提问后机器人不回答,报错模型配置有问题。先检查容器是否能正常连外网,不能就再给容器配置代理。

docker ps 

# 进入 qanything 容器,原来每次重启容器 id 会变
docker exec -it 2074837a9aaa /bin/bash

# 检查容器能否连外网,不能
wget baidu.com

# 退出容器
exit

# 改 yaml 文件
nano docker-compose-linux.yaml

# 在 qanything_local 的 environment 里添加
- HTTPS_PROXY=http://proxy.example.com:port 
- HTTP_PROXY=http://proxy.example.com:port 
- NO_PROXY=localhost,127.0.0.1,.home.com.cn,10. 

再试,还是不行。根据之前在本地电脑基于本地知识库构建 RAG 应用的经验,寻找包含"OpenAI"关键词的.py文件,配置代理。

# 再进入 qanything 容器
docker exec -it 2074837a9aaa /bin/bash

# 查找文件
find / -name "*.py" -exec grep -Hn "OpenAI" {} \;

找到QAnything/qanything_kernel/core/chains/condense_q_chain.py文件,加上代理设置。

# 修改前
class RewriteQuestionChain:def __init__(self, model_name, openai_api_key, openai_api_base):self.chat_model = ChatOpenAI(
  model_name = model_name,
  openai_api_key = openai_api_key,
  openai_api_base = openai_api_base,
  temperature = 0,
  model_kwargs = {
    "top_p":0.01, "seed":1234
  }
)

# 修改后
class RewriteQuestionChain:def __init__(self, model_name, openai_api_key, openai_api_base):self.chat_model = ChatOpenAI(
  model_name = model_name,
  openai_api_key = "sk-x",
  openai_api_base = "https://xxxx",
  http_client = httpx.Client(
    proxy = "http://xxxxx:port",
    transport = httpx.HTTPTransport(local_address = "0.0.0.0"),
  ),
  temperature = 0,
  model_kwargs = {
    "top_p":0.01, "seed":1234
  }
)

改完以后,再重新启动,机器人就可以正常生成答案。

  1. 将修改过的容器另存为新镜像,保存在本地服务器。

最开始用docker-compose-linux.yaml文档一次性启动多个镜像时,每个镜像都生成了一个新的容器,后来由于报错在 mysql 和 qanything_local 的容器内进行修改。由于对容器的修改不会改变原始镜像,如果不提交保存,万一服务器重启或者镜像重启,就会在原始镜像的基础上生成新容器,之前的修改会消失,因此改过的容器需要另存为新镜像。

# 查看容器 id
docker ps

# 将修改过的容器提交为新镜像
docker commit 2074837a9aaa modify-qanything-linux:v1.5.1
docker commit 603bcf640adb modify-mysql:8.4

# 改 yaml 文件,把 mysql 和 qanything_local 的镜像名字改成新的
nano docker-compose-linux.yaml

# 关闭
docker compose -f docker-compose-linux.yaml down

# 再启动
docker compose -f docker-compose-linux.yaml up -d

此次部署过程中没遇到过端口被占用的情况,如果遇到了的话,需要修改 yaml 文件中的端口号(port)。

三、部署 Dify 项目 🔗

Dify 是 Github 上的一个开源项目,参照社区版 docker compose 部署,全程顺利进行,没有再出任何问题。正常启动后,访问http://10.xx.x.xx/install,在页面上进行后续配置。

# 克隆项目源代码到服务器指定目录
git clone https://github.com/langgenius/dify.git /home/hadoop/Dify2/

# 进入指定目录
cd /home/hadoop/Dify2/docker/

# 复制环境变量
cp .env.example .env

# 启动
docker compose up -d

# 根据上一步的结果检查各端口有无被占用
sudo netstat -tuln | grep :5001

# 检查容器状态
docker compose ps

# 将来在指定目录下更新 Dify
docker compose down
git pull origin main
docker compose pull
docker compose up -d

# 关闭
docker compose down

总的来说,Docker 本身竟然意外地简单,由于代码都写在文件里,执行 Docker 命令就是操作各种文件。略显复杂的地方是服务器有防火墙,如果要从外网拉取镜像,需要一层层配置网络代理,但现在有 AI 辅助,这样的复杂也可忽略不计了。另外就是成熟的项目都使用 docker compose 定义和运行多个容器,而具体的定义从各个容器中抽离出来写在了docker-compose.yaml文件里,而 yaml 语法简单、非常易读,没有函数全是参数名和参数值,对人类十分友好。

R