本文是对最近在内网离线部署隐私计算分布式联邦学习平台FATE的总结。适用于内网完全隔离网络无法联网的情况。这里隐私计算安全求交的原理不做解释。
资源及环境准备
- 找一台能联网的干净的服务器,安装docker并注册为服务,设置开机自启动。
- Ansibel离线部署包和打包好的docker镜像部署包(由对方节点提供,本方没做修改),传到能联网的服务器上。
- 要求环境在16c/32g/250g左右,能正常启动服务,实际跑业务需要扩容。
指定本地机器IP为内网机器IP
由于在部署过程中,部署脚本会更改许多有关IP的配置,所以在本地将能联网的机器设定为内网机器IP且要保证能联网,以下以Vmware,指定机器IP为10.1xx.1xx.4x为例:
- 设置Vmware为Net模式
- 更改网络
- 更改网关
- DHCP设置
- 以上操作在关机状态下设置后开机再使用命令行操作。
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
部署完成后,检查是否正常启动
- 把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
部署时间较长,可以根据执行部署脚本后的命令查看日志,出现以下提示即为部署成功
- 单节点测试 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命令后出现以下提示即为成功:
注:需要把运行内存调大一些,不然会在这里卡住。
镜像及宿主机目录打包、上传内网、部署
提交镜像、导出、打包、上传
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
即为联通性测试成功。
功能性测试
模拟简单待求交数据,/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即为求交成功。
注:本文只是单节点部署的一次记录,实际部署及联调时需要双方配合,文章内容仅供参考。