ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu 20.04 Docker部署FATE联邦学习框架实操指南

Ubuntu 20.04 Docker部署FATE联邦学习框架实操指南

1. 先回答问题:为什么在 Ubuntu 20.04 上要选择 Docker 部署 FATE

1.1 FATE 联邦学习框架到底解决什么问题

FATE 联邦学习框架的核心场景,是让多个参与方在不直接暴露原始数据的前提下,共同完成模型训练和评估。传统机器学习通常会先把各方数据汇总到中心节点,再统一建模,这在数据合规要求越来越严格的环境里会面临很大阻力。联邦学习换了一个思路:数据留在本地,各方只交换模型参数、梯度或者经过加密计算的中间结果,通过协作得到全局模型。

我第一次接触 FATE 的时候,最大的感受是它不是一个单体软件,而是一整套分布式系统。整套环境包含任务调度节点、计算节点、存储节点、可视化平台和算法组件。部署 FATE 的过程,本质上是在一台或几台机器上把这些组件全部拉起来,并让它们正确互联。这也是为什么很多人用源码方式安装时会卡住:组件太多、依赖太杂,任何一个版本错位都会导致环境起不来。

1.2 源码安装的痛点和 Docker 方案的优势

FATE 的源码部署依赖 Python、Java、MySQL、Redis、Nginx 等一大堆环境。不同组件对 Python 包版本、JVM 版本、系统库版本都有各自要求。就算费劲装好一次,隔几个月想升级小版本,又可能踩到新的依赖冲突。

Docker 方案把这些问题整体封装掉了。镜像里的操作系统、运行时、依赖库和 FATE 组件是配套打包的,部署时只需要拉镜像、启动容器,不用手工解决编译链接和环境变量问题。对新手来说,出错后最有效的恢复手段就是“删掉容器重新来”,这比在物理环境里一层层回滚爽快得多。对老手来说,Docker 也方便做多版本并存和资源隔离,尤其是想要在开发机模拟多个独立 FATE 实例时,容器几乎是最优解。

1.3 单机模拟和多机联邦:先想清楚你要哪种

部署 FATE 之前要明确目标。如果你只是学习联邦学习原理、写算法 Demo、调试数据处理流程,单机 Docker 部署完全够用。单机模式会把多个“参与方”跑在同一台机器的不同容器里,网络互通、任务调度都在本地完成,体验上非常接近真实集群。

但如果你要对接真实业务,让不同机构的机器真正参与联邦训练,那就要走多机部署模式。多机部署涉及角色划分、IP 互通、证书配置、端口开放、时间同步等一系列问题,复杂度比单机高一截。我的建议是先在单机环境把 toy 示例和一个小型真实任务跑通,再考虑多机扩展。顺序反了,你会同时面对“环境问题”和“算法问题”,排查时很难定位边界。

2. Ubuntu 20.04 环境准备:把地基打扎实再动手

2.1 系统、CPU、内存和磁盘的硬性检查

Ubuntu 20.04 是长期支持版本,对 Docker 的兼容性比较成熟,作为 FATE 部署环境是稳妥的选择。部署前先确认系统版本、CPU 架构、内存和磁盘空间。虽然官方文档只给了最低参数,但我建议内存不要低于 8 GB,磁盘剩余空间不要低于 20 GB,架构优先选 x86_64。

cat /etc/os-release uname -a nproc free -h df -h

这四条命令看起来基础,却能避免很多后期问题。我遇到过一台 4 GB 内存的测试机,镜像都拉完了,容器全部启动,结果 MySQL 反复重启。翻日志才发现是内存分配不足,进程被系统杀掉。后来把机器内存扩到 8 GB,同样的部署脚本一次通过。磁盘也是一样,FATE 相关镜像加起来好几个 GB,容器运行时日志、数据库数据还会继续增长,系统盘太满会让 Docker 服务本身出现异常。

2.2 Docker 引擎安装与 docker compose 组件处理

Docker 安装方式不少,我习惯从 Docker 官方源安装,这样能拿到较新的引擎和 compose 插件。如果你所在网络访问官方源不稳定,可以先配置操作系统的软件源镜像,再执行安装。

sudo apt update sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

安装完成后,可以通过sudo docker run hello-world验证引擎是否正常。注意,FATE 部署脚本依赖容器编排能力,需要确保 compose 命令可用。检查方式是执行docker compose version,确认输出正常。如果你同时用独立二进制方式装过旧版 docker-compose,系统里可能同时存在两种调用方式,这会带来隐患:部署脚本里如果写的是docker-compose,而你只保留了docker compose插件,脚本会在编排阶段报 command not found。建议统一成一种,删除多余版本。

2.3 配置镜像加速和日志大小限制

拉取 FATE 镜像时,如果直接连公共镜像仓库,网络环境差一些的时候容易超时。可以给 Docker daemon 配置 mirror 加速地址。不同加速服务的效果差异较大,选择你网络环境里实际可达且信任的地址就好。

sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<'EOF' { "registry-mirrors": ["https://your-mirror.example.com"], "log-driver": "json-file", "log-opts": {"max-size": "50m", "max-file": "3"} } EOF sudo systemctl restart docker

同时限制 Docker 日志文件大小,这个是实操里很容易忽略的点。FATE 容器在训练任务调试阶段会打印大量日志,尤其是 Notebook 和计算节点,一旦日志无限增长,/var/lib/docker 会快速膨胀。我见过最夸张的情况是整个系统盘被容器日志占满,SSH 都登录不进去。加完日志限制后,建议定期用docker system df检查磁盘占用。

2.4 端口清单、防火墙和后期的多机扩张

FATE 单机部署会启动多个容器,占用的端口包括 Web 页面、API 服务、数据库、缓存、任务调度、节点通信等用途。常见的有 8080、8081、3306、6379、9360、9370、9380、8888、8000 等。如果你只是本机演示,端口冲突相对好处理,直接停掉占用端口的服务即可。如果机器开启了防火墙,记得确认这些端口没有被拦截。

多机联调之前,端口规划会直接影响后续联调成本。我建议在部署文档里记一张端口清单,注明每个端口对应什么服务、是否需要对外开放、允许的访问来源是什么。很多多机联调问题都出在“容器起来了但跨机访问不了”,十有八九是安全组规则漏放行了某个通信端口。与其到时候逐台机器排查,不如第一次部署就同步把端口规划做好。

3. Docker 安装 FATE 完整实操:从脚本命令到容器起跑

3.1 认识部署工具包里有什么

FATE 官方部署工具的结构在不同版本里会微调,但核心思路一致:通过一个初始化脚本解析配置,生成 docker-compose.yml,然后拉取镜像、启动容器。拿到部署包后,先别急着跑命令,花十分钟把 README、配置文件和目录结构看一遍。

部署包里常见的内容包括一键部署脚本、compose 模板、环境变量配置、示例证书等。执行脚本之前,建议先看脚本里有没有依赖 curl、unzip、tar 这类基础命令。有些精简系统默认没装 unzip,解压部署包就会失败,但报错提示并不明显。

mkdir -p ~/fate && cd ~/fate unzip fate_docker_deploy.zip -d . cd fate_docker_deploy

3.2 一键部署命令到底在执行什么

把部署包放到固定目录后,执行类似这样的命令:

bash build_standalone_docker.sh --version 1.x.x

脚本会自动完成环境检查、生成 compose 文件、拉取镜像、启动容器并做健康检查。这里的版本号需要替换成你当前部署包的版本,通常 README 里会写清楚。指定版本号的目的是让脚本去拉取对应 tag 的镜像,避免脚本和镜像版本不匹配。

执行过程中会看到大量日志,核心阶段包括:检查端口、生成部署文件、拉取镜像、创建 Docker 网络、启动 MySQL 和 Redis、启动 FATE 各组件、等待健康检查通过。每个阶段都有明显的日志输出,比如pull complete、Creating network、Starting container。卡在哪一步,就大概率是那一步的环境问题,不要盲目重跑整个脚本。

3.3 启动后用 docker ps 验证组件状态

脚本执行完成后,第一时间确认所有容器是否稳定运行。用下面的命令列出容器状态和端口映射:

docker ps --format "table {{.Names}}\t{{.Ports}}\t{{.Status}}"

正常情况下,你会看到 MySQL、Redis、FATE 的调度服务、计算服务、Board 服务、Notebook 等容器都处于 Up 状态。如果某个容器反复 Restarting,就要立刻去看日志。

docker logs <container_name> --tail 200

我个人的经验是,容器能被创建出来已经说明镜像拉取成功,剩下问题多数集中在资源不足、端口冲突、配置依赖这三个方向。查看日志时要看容器第一次启动时的完整输出,而不是只看最后几行。有些错误发生在启动早期,日志滚动后反而被刷掉了。

3.4 访问 FATE Board 和 Notebook,检查部署结果

部署完成后,通过浏览器访问 FATE Board,这是可视化的任务管理界面。默认端口通常是 8080,但不同版本可能有调整,以生成后的 compose 文件里实际映射端口为准。Notebook 入口一般映射在 8888 或 8000,用于写代码和执行联邦学习 pipeline。

远程服务器上访问时,记得把 localhost 换成服务器 IP,并且确认防火墙和安全组已经放行。如果页面打开后显示空白或连接失败,先执行docker ps,再看端口映射有没有生效:

curl -I http://localhost:8080

如果宿主机能通,但浏览器访问时不行,重点查安全组或者云平台防火墙。如果宿主机也访问不通,则检查容器状态和 Board 日志。这里有个小坑:一些部署脚本会给容器名加上随机后缀,浏览器调试时要看准实际映射端口,不要照着文档里的“默认值”死磕。

4. 常见安装失败的场景与排查技巧实录

4.1 镜像拉取超时或连接不稳定

这是出现频率最高的问题。现象通常是部署脚本停在Pulling阶段,进度条长时间不动,或者直接报TLS handshake timeout、i/o timeout这类网络错误。

解决思路分三步。第一步确认宿主机网络能到达镜像仓库,可以用curl -I测试。第二步给 Docker daemon 配置加速 mirror,然后重启 Docker。第三步手动拉取关键镜像,观察具体卡在哪个镜像。手动拉取的命令大概是:

docker pull federatedai/eggroll:1.x.x docker pull federatedai/fateboard:1.x.x docker pull mysql:8.0 docker pull redis:5

手动拉取还有一个好处:能看到磁盘和带宽的真实占用,判断到底是网络慢还是磁盘空间不够。如果某个镜像反复在最后一层失败,大概率是连接被重置,重试几次往往能成功。所有依赖镜像都拉完后,再跑部署脚本就非常快,脚本只在本地做容器创建和启动。

4.2 端口被占用导致容器启动失败

FATE 单机部署占用的服务端口非常多,如果机器上本来就有 MySQL、Redis、Nginx 或者其他 Web 服务,容器编排时很容易报port is already allocated。排查时先确认端口占用情况:

sudo ss -lntp | grep -E '8080|3306|6379|9360|9370|9380|8888|8000'

确认占用后,最简单的办法是停掉冲突服务。如果你确实需要保留原有服务,再考虑修改 compose 端口映射。但这里要注意,FATE 组件之间通过容器网络内部的 service 名和默认端口通信,宿主机映射端口改掉通常不影响容器间互访。可是某些管理端界面或客户端配置文件里写死的地址仍然指向旧端口,只改 compose 表面映射会留下隐藏问题。需要全局搜索配置文件里的端口引用,确保所有关联配置都同步调整。

4.3 内存不足导致 MySQL 或 Redis 反复重启

部署脚本走到最后,容器看似都创建了,但docker ps里 MySQL 或 Redis 一直在 Restarting,这是资源问题的典型信号。查看进程被杀的日志通常会出现OutOfMemoryError或者内核日志里能看到oom-killer。

处理方式首先是释放宿主机内存,关掉不必要的 Java 或 Python 进程。其次,检查 Docker 的资源限制配置,确认 compose 里没有把 mem_limit 设得过低。还可以临时调整/proc/sys/vm/overcommit_memory,但这个内核参数会影响整个系统的内存分配策略,生产环境不要随意更改。最稳妥的方式还是保证宿主机内存至少 8 GB,并预留 2 GB 以上余量给系统本身。

4.4 容器全部正常但训练任务一直等待资源

容器状态正常、页面也能打开,但提交训练任务后一直处于 pending,这类问题隐蔽在通信层。FATE 的计算通信底座会自动注册节点,如果容器无法按预期解析服务名或互相访问,任务就会一直申请不到资源。

这时不要急着看上层训练日志,先进入容器验证网络连通性:

docker exec -it <container_name> bash ping <another_service_name>

确认同一 Docker 网络里的容器能互相ping通。如果 ping 不通,检查 compose 里的自定义网络配置、容器的 network aliases、以及宿主机 hosts 文件。跨多机部署时,还要检查所有节点的时钟是否同步,时间偏差过大会导致通信握手失败。这个问题很隐蔽,不容易在部署阶段暴露,通常要到任务调度阶段才体现。所以多机环境里,第一时间做时间同步可以少踩很多坑。

5. 安装成功后的功能验证与快速上手

5.1 先跑官方 Toy 示例,验证系统闭环

部署环境完成后,不要急着用自己的业务数据跑训练,先把官方自带的 toy_example 跑通。这个示例模拟两个参与方之间的一次极小规模联邦建模,专门用来验证底层通信和任务调度是否正常。

进入 FATE 客户端容器,找到官方示例目录:

docker exec -it <fate_client_container_name> bash cd /data/projects/fate/python/examples/toy_example/ python run_toy_example.py 100 1

看到任务成功返回,说明部署配置没问题。如果这一步失败,后面所有训练任务都可能失败,必须先排查环境。Toy 示例的价值在于它足够简单,问题范围很窄:不是数据问题,不是算法问题,基本就是环境链路问题。

5.2 用 Python 客户端提交一个最小横向训练任务

Toy 示例跑通后,你可以在 Notebook 或命令行客户端里创建一个真实的最小任务。核心流程包括上传数据、定义参与方、编写 pipeline、提交任务、查看结果。

建议从横向联邦学习任务开始,因为它的数据结构最简单:多个参与方拥有相同特征空间、不同样本空间。先复制示例里的 DSL 和 pipeline 配置,把数据路径改成自己的样本数据,跑通后再逐步调整特征工程和模型参数。不要从零开始写 pipeline,示例配置里的组件连接方式往往是最稳定的一套模板,改比写快得多。

5.3 单机模拟多方和真实多机构联动的差异

单机部署的“多个参与方”实际上运行在同一个 Docker network 里,它们之间通过服务名通信,不存在真实跨机构网络链路的时延、丢包、安全隔离问题。因此,单机验证通过只能说明功能逻辑正确,不能完全等同于真实多机构环境的行为。

真正跨机构部署时,需要为每个参与方单独部署一套 FATE 环境,并配置彼此的 IP、端口、证书和角色信息。这时候要考虑网络访问控制、数据传输加密、节点异常恢复等内容。学习阶段先把单机吃透,等有机会接触真实业务环境时,你会发现单机阶段建立的组件概念和排查思路都能直接迁移过去。

6. 部署完成后留下的几条实操建议

6.1 提前为容器设置资源配额

Docker 默认不限制容器的 CPU 和内存使用,但 FATE 训练任务在数据量增大后非常吃资源。如果不做限制,一个任务可能把宿主机内存全部吃掉,导致其他服务甚至 SSH 都失去响应。

建议在 compose 文件里给关键容器增加 resource limits,比如将计算节点容器的内存限制在一个明确的上限。具体数值要根据业务数据量来定,宁可先设置一个观察基线,再根据监控调整。容器资源配额的意义不是限制性能,而是保护宿主机整体稳定性。分布式训练场景里,单个任务异常不能拖垮整台机器,否则排查成本会成倍增加。

6.2 日志和数据目录的日常维护

FATE 的容器会持续产生三类数据:运行日志、数据库内容、模型产物。如果这些数据都落在 Docker 默认目录或系统盘上,磁盘早晚会被写满。建议把数据盘单独挂载,并在 compose 配置中显式指定 volume 路径,让业务数据与系统盘分离。

日常巡检可以关注下面三个命令:

docker system df du -sh /var/lib/docker/* docker system prune -f --volumes

使用docker system prune前务必确认没有需要的容器数据,因为它会清理未被引用的资源。我吃过一次亏,清完临时环境后才发现某个数据库卷没有外部备份,恢复起来非常麻烦。清理操作永远先备份、再执行。

6.3 升级和卸载前一定要留好备份

FATE 版本升级不是简单替换镜像 tag,数据库表结构、组件启动参数、前端页面路由都可能变化。升级前至少做好三件事:导出 MySQL 数据、保存当前 compose 文件、记录当前镜像版本。没有备份就升级,一旦失败,回滚会非常痛苦。

卸载环境也是一样。执行docker compose down -v会连容器、网络和卷一起清理,如果没有提前备份数据,删除之后基本无法找回。我会在每个部署目录里放一个 README,记录部署日期、镜像版本、自定义参数和需要注意的坑。这比依赖记忆可靠得多,尤其当你同时管理多套环境的时候。

最后分享一个很小但很实用的习惯:部署完成后,顺手把 FATE Board 默认账号密码和 MySQL root 密码改掉。很多示例环境停留在默认口令状态,一旦容器暴露在局域网里,容易被扫描工具盯上。改密码只是多花几分钟,却能避免后续被薅成“挖矿肉鸡”的尴尬。等真正开始多机联调时,一个干净、安全、有备份记录的起点会让你从容很多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进