内网离线部署隐私计算联邦学习开源框架FATE

34 阅读8分钟

本文是对最近在内网离线部署隐私计算分布式联邦学习平台FATE的总结。适用于内网完全隔离网络无法联网的情况。这里隐私计算安全求交的原理不做解释。

资源及环境准备

  • 找一台能联网的干净的服务器,安装docker并注册为服务,设置开机自启动。
  • Ansibel离线部署包和打包好的docker镜像部署包(由对方节点提供,本方没做修改),传到能联网的服务器上。
  • 要求环境在16c/32g/250g左右,能正常启动服务,实际跑业务需要扩容。

指定本地机器IP为内网机器IP

由于在部署过程中,部署脚本会更改许多有关IP的配置,所以在本地将能联网的机器设定为内网机器IP且要保证能联网,以下以Vmware,指定机器IP为10.1xx.1xx.4x为例:

  • 设置Vmware为Net模式

image.png

  • 更改网络

image.png

  • 更改网关

image.png

  • DHCP设置

image.png

  • 以上操作在关机状态下设置后开机再使用命令行操作。
nmcli connection modify "ens160" ipv4.method manual ipv4.addresses 10.xx.xx.xx/24 ipv4.gateway 10.xx.xx.xx

检查自己虚机的网络接口,我这里是ens160,有的是ens330。检查命令

ip a # 或 nmcli device status

重新激活链接

nmcli connection down "ens160" 
nmcli connection up "ens160"
  • 网络测试 在虚机上ping百度的网址,或者ping自己本机IP,能通就设置完成。

Dokcer部署

本次部署采用的是docker19版本,官网下载压缩包Docker: Accelerated Container Application Development及部署脚本shield_docker_daemon_install.sh 把docker的压缩包及部署脚本放到/data下,运行下面命令。

sh shield_docker_daemon_install.sh /data

部署完成后,检查是否正常启动 image.png

  • 把docker注册为服务(之前部署的时候没有注册为服务,怀疑是在这里踩了坑) 确认docker及dockerd服务
which docker   #/usr/bin/docker
which dockerd  #/usr/bin/dockerd

确认systemd服务

ls /usr/lib/systemd/system
一般在
/usr/lib/systemd/system/doker.service

如果没有创建这个文件

cat > /usr/lib/systemd/system/docker.service << 'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd   # 注意这个路径是否正确(实际文件中不要有这个注释信息)
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

重新加载systemd

systemctl daemon-reload

设置启动加开机自启动

systemctl enable --now docker

这步可能出错,解决方案:通过ps -ef | grep dockerd,找出所有的dockerd服务,然后kill掉,重新执行systemctl enabel --now docker 然后检查docker服务的状态

systemctl status docker

开始部署

找一个存储大的目录如/data下新建/data1,把离线打包的Ansible及需要部署的docker镜像包放到这个下面。

  • 启动容器
docker run -d --restart unless-stopped -v /data/data1:/data --network host fate_2.2_v7  # fate_2.2_v7 是启动镜像
  • 进入容器
docker exec -it --privileged 66c /bin/bash
  • 以下操作是在root用户下
vim /etc/ansible/ansible.cfg # 把host_key_checking = False注释关掉

cd /etc/security/limits.d
mv 20-nproc.conf 20-nproc.conf_bak  # 备份下文件

vim /etc/security/limits.conf
文件末尾添加:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535

chown -R app:apps /data  # 授权给app用户

vim /etc/sudoers.d/app
加入下面这些配置
app ALL=(ALL) ALL
app ALL=(ALL) NOPASSWD: ALL
Defaults !env_reset

chmod u+w /etc/sudoers

vim /etc/sudoers
在root ALL=(ALL) ALL下面追加:
root ALL=(ALL) NOPASSWD: ALL
app ALL=(ALL) ALL
app ALL=(ALL) NOPASSWD: ALL

chmod u-w /etc/sudoers

netstat -natp | grep sshd 显示36000为正常
  • 切到app用户
mkdir -pv /data/projects /data/temp /data/logs/pipeline /data/logs/fate/mysql
touch /data/logs/fate/mysql/boot.log
touch /data/logs/fate/mysql/init.log
touch /data/logs/fate/mysql/mysqld.log  # 创建一些目录文件

export LANG=en_US.UTF-8

sh deploy/deploy.sh init -g="9998:10.1xx.xx.xx" # IP为部署机器IP

vim deploy/conf/setup.conf # 端口改成36000

sh deploy/deploy.sh render
sh deploy/deploy.sh deploy # 执行部署脚本

在上面执行这个脚本的过程中,可能会出现9001端口超时的问题,是因为supervisor服务没有正常启动,以下是解决方法

cd /data/projects/common/miniconda3/bin/

./python ./supervisord -c /data/projects/common/supervisord/supervisord.conf # 手动启动superviosr服务

再重新执行

sh deploy/deploy.sh deploy

部署时间较长,可以根据执行部署脚本后的命令查看日志,出现以下提示即为部署成功

image.png

  • 单节点测试 app用户下运行以下命令
source /data/projects/fate/bin/init_env.sh

flow init --ip 10.1xx.xx.xx --port 9380

pipeline init --ip 10.xxx.xx.xxx --port 9380

flow test toy -gid 9998 -hid 9998 #标识本方节点ID是9998

运行flow test toy -gid 9998 -hid 9998命令后出现以下提示即为成功:

da72a6f02fa360967ba5a1d918eac76b.png 注:需要把运行内存调大一些,不然会在这里卡住。

镜像及宿主机目录打包、上传内网、部署

提交镜像、导出、打包、上传

docker commit wizardly_khorana fate_v7_custom:1.0 # wizardly_khorana镜像名,fate_v7_custom:1.0新的镜像

docker save fate_v7_custom:1.0 -o fate_v7_custom_1 #保存

zip fate_v7_custom_1.zip fate_v7_custom_1  得到打包的zip镜像 fate_v7_custom_1.zip

docker cp 容器id:<容器内文件路径> <宿主机目标路径> #把打包好的镜像从容器中拿到宿主机上

cp /root/project.yaml /mnt/hgfs/software/ # 从宿主机再拿到本地电脑,这里Vmware需要安装Vmware Tools,就不解释了

把上面部署的包传到内网部署的机器上。

打包宿主机挂载目录、切割、上传

由于启动时挂载了宿主机目录,镜像commit+save之后,无法将宿主机的目录也导出,所以打包宿主机目录也导入到内网。

tar -czvf fate_data.tar.gz data1  打包data1 # 这个包比较大,如果能一次性传更好,传不完就切割上传,命令如下

split -b 1024M data_backup.tar.gz data_backup.tar.gz.part_

同样的方式,把宿主机挂载目录传到内网

cat data_backup.tar.gz.part_1 data_backup.tar.gz.part_2 ... > fate_data_tar.gz #把切割的包再合并

md5sum 原来的在本机的包 和 md5sum 内网合并后的包 # 比较两次的md5值一样,查看文件是否丢失,文件出错

解压宿主机目录

tar -xzvf fate_data.tar.gz -C /data   #把data1解压到/data 和原来保持一致

内网重新启动镜像、检查服务状态

unzip fate_v7_custom_1.zip  #解压

docker load -i fate_v7_custom_1   #加载镜像
预期输出:Loaded image: fate_v7_custom:1.0 #使用 fate_v7_custom:1.0 这个镜像启动容器。

docker run -d --name fate_v7_custom --restart unless-stopped -v /data/data1:/data --network host fate_v7_custom:1.0 # 启动镜像

docker exec -it --privileged 052 /bin/bash # 进入到容器里面

内网的容器重新启动后,某些文件的权限可能有变化,重新执行下面命令给app用户授权

chown -R app:apps /data

有可能supervisor服务也没有启动,切到app用户下,执行下面命令

cd /data/projects/common/miniconda3/bin/

./python ./supervisord -c /data/projects/common/supervisord/supervisord.conf # 手动启动superviosr服务

内网线上检查服务状态,出现和本地测试一样的提示,即为服务成功启动。也是这几个命令

source /data/projects/fate/bin/init_env.sh
flow init --ip 10.1xx.1xx.xx --port 9380
pipeline init --ip 10.1xx.1xx.xx --port 9380
flow test toy -gid 9998 -hid 9998

更改路由配置及添加信任证书

vi /data/projects/fate/osx/conf/broker/route_table.json

替换原来的配置
{
  "route_table":
  {
    "10000":
    {
      "default":[
        {
          "ip": "xx.xx.xx.xx", # 对端的入网访问IP
          "port": 9371,
          "protocol": "grpc",
          "useSSL": false
        }
      ]
    },
    "9998":
    {
      "default":[
        {
          "ip": "xx.xx.xx.xx",  # 内网部署机器IP 
          "port": 9371
        }
      ],
      "fateflow":[
        {
          "ip": "xx.xx.xx.xx", # 内网部署机器IP 
          "port": 9360
        }
      ]
    }
  },
  "self_party":
  [
    "9998"
  ]
}

重启服务,检查服务状态
/data/projects/common/supervisord/service.sh restart all
重启完检查几个服务的状态是否正常,检查9371服务的状态
/data/projects/common/supervisord/service.sh status all
  • 信任证书

把对端给的两个节点间的互相信任证书,放到/data下面解压,app用户操作。

  • 修改配置
vi /data/projects/fate/osx/conf/broker/broker.properties

open.grpc.tls.server=true
grpc.tls.port=9371
# server端公钥
grpc.server.cert.chain.file=/data/key/guest_server.crt
# sever端私钥
grpc.server.private.key.file=/data/key/guest_server_pkcs8.key
# 信任证书
grpc.server.ca.file=/data/key/ca.crt
  • 再次更改路由配置
再重新vi /data/projects/fate/osx/conf/broker/route_table.json

{
  "route_table":
  {
    "10000":
    {
      "default":[
        {
          "ip": "xx.xx.xx.xx",   # 对端的入网IP
          "port": 9371,   
          "protocol": "grpc",
          "certChainFile": "/data/key/host_client.crt",
          "privateKeyFile": "/data/key/host_client_pkcs8.key",
          "caFile": "/data/key/ca.crt",
          "useSSL": true,
          "useKeyStore" : false
        }
      ]
    },
    "9998":
    {
      "default":[
        {
          "ip": "xx.xx.xx.xx",  # 本机部署IP
          "port": 9371
        }
      ],
      "fateflow":[
        {
          "ip": "xx.xx.xx.xx",  # 本机部署IP
          "port": 9360
        }
      ]
    }
  },
  "self_party":
  [
    "9998"
  ]
}
重启服务:
/data/projects/common/supervisord/service.sh restart all

看下9371的服务
netstat -natp | grep 9371

至此路由配置及互相信任证书完成配置。

联通性测试及功能性测试

联通性测试

对端节点向本方节点发起访问请求

 flow test toy -gid 9998 -hid 10000

image.png 即为联通性测试成功。

功能性测试

模拟简单待求交数据,/data下1.txt写入如下信息,为对方数据中的交集。

id
1
3
5
7
9

上传数据

cat upload.json 
{
  "file": "/data/1.txt",
  "head": true,
  "partitions": 1,
  "extend_sid": true,
  "meta": {
    "delimiter": ",",
    "match_id_name": "id"
  },
  "namespace": "experiment",
  "name": "guest_test_0"
}

执行上传

source /data/projects/fate/bin/init_env.sh
flow data upload -c upload.json

对方发起求交任务,得到13579即为求交成功。

注:本文只是单节点部署的一次记录,实际部署及联调时需要双方配合,文章内容仅供参考。