Deployment#
Pre-knowledge: about Ray#
SecretFlow uses Ray as its distributed framework. A Ray cluster consists of a head node and zero or several slave nodes, for more information about Ray, please visit Ray official website.
Simulation#
SecretFlow is designed for fast simulation on a single host or on multiple nodes with single ray cluster.
Note
SecretFlow with single ray cluster is for simulation only. Please refer to production section below for production.
Standalone mode for simulation#
Use secretflow.init directly to run secretflow in standalone mode. A ray cluster with only one node will be started, and it will automatically shut down when the program exits.
>>> import secretflow as sf
>>> sf.init(parties=['alice', 'bob'], address='local')
Cluster mode for simulation#
In the cluster simulation mode, each Ray node simulates an participant. This is done by adding the participant name as resource tag on each Ray node, and then the calculation task of each participant is dispatched to the corresponding Ray node. The overall communication network is as follows.

The following is an example showing how to build a cluster consisting of alice and bob on multiple nodes.
Start head node#
Start a head node on your first machine with the tag “alice”.
NOTE
Remember to use the real ip and port instead.
{"alice": 16}means that alice can run up to 16 workers at the same time. Just feel free to change it if you like.
ray start --head --node-ip-address="ip" --port="port" --resources='{"alice": 16}' --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see “Ray runtime started.” in the screen output.
Now we have a cluster with a head node only, let us start more nodes.
Start other nodes#
Start a node with the tag “bob” on another machine. The node will connect to the head node and join the cluster.
Note
Replace ip:port with the node-ip-address and port of head node please.
ray start --address="ip:port" --resources='{"bob": 16}' --disable-usage-stats
The node starts successfully if you see “Ray runtime started.” in the screen output.
A Ray cluster consisting of two Ray nodes has been built by now, while the head node simulates alice and the slave node simulates bob.
You can repeat the step above to start more nodes with using other parties as resources tag as you like.
Start SecretFlow#
Now you can start SecretFlow and run your code. The following code shows that alice and bob each execute a function that returns the input value.
Tips
Replace
ip:portinsf.initwith thenode-ip-addressandportof head node please.If you start more nodes (such as carol, davy, etc.), remember to add the new party name in the
parties=['alice', 'bob']parameter.
>>> import secretflow as sf
# Replace with the `node-ip-address` and `port` of head node.
>>> sf.init(parties=['alice', 'bob'], address='ip:port')
>>> alice = sf.PYU('alice')
>>> bob = sf.PYU('bob')
>>> alice(lambda x : x)(2)
<secretflow.device.device.pyu.PYUObject object at 0x7fe932a1a640>
>>> bob(lambda x : x)(2)
<secretflow.device.device.pyu.PYUObject object at 0x7fe6fef03250>
(optional) How to shut down the cluster#
In some cases you would like to shut down the cluster, the following command will help you. Remember to run the command on all machines.
Note that all ray processors on the machine will be stopped, which means all ray clusters will be stopped.
ray stop
(optional) How to setup an SPU in cluster mode#
SPU consists of multi workers on different nodes.
For performance reasons, the major part of SPU is written in C++.
SPU is based on Brpc, which indicates it has a separated service mesh independent of Ray’s networking.
In a word, you need to assign different ports for the SPU for now.
We are working on merging them.
A typical SPU config is as follows.
Tips
Replace
addressinsf.initwith thenode-ip-addressandportof head node please.Fill
addressofalicewith the address which can be accessed byboband choose an unused port different with Ray.listen_addrofalicecan use the same port of aliceaddress.Fill
addressofbobwith the ip which can be accessed byaliceand choose an unused port different with Ray.listen_addrofbobcan use the same port of bobaddress.
import spu
import secretflow as sf
# Use ray head adress please.
sf.init(parties=['alice', 'bob'], address='Ray head node address')
cluster_def={
'nodes': [
{
'party': 'alice',
# Please choose an unused port.
'address': 'ip:port of alice',
'listen_addr': '0.0.0.0:port'
},
{
'party': 'bob',
# Please choose an unused port.
'address': 'ip:port of bob',
'listen_addr': '0.0.0.0:port'
},
],
'runtime_config': {
'protocol': spu.spu_pb2.SEMI2K,
'field': spu.spu_pb2.FM128,
'sigmoid_mode': spu.spu_pb2.RuntimeConfig.SIGMOID_REAL,
}
}
spu = sf.SPU(cluster_def=cluster_def)
For more configurations of SPU, please refer to SPU config
Note
You will see the usage of setup an spu in many tutorials. But
be careful that it works only in standalone mode because sf.utils.testing.cluster_def use 127.0.0.1 as the default ip.
>>> spu = sf.SPU(sf.utils.testing.cluster_def(['alice', 'bob', 'carol']))
Deploy SecretFlow in a docker container with simulation mode#
You may need to understand the concept of docker network firstly. The two main docker networks are host network and bridge network, you can click the link to read the official documentation to learn more.”
SecretFlow recommends to start the container using the host network mode, and the following will explain the reasons to you.
(Recommended) Host network#
When you start the docker container using host network (e.g. run container with --network host), the container will share the network of the host machine. Therefore, no special configuration is required to build a SecretFlow cluster in this case, and you can directly use the address of the host as the communication address between nodes. Refer to the preceding steps for deployment..
(Not recommended) Bridge network#
If you start the Docker container with a bridge network, it means that the container will have an isolated network with a different IP address from the host, and containers on different bridge networks are not connected by default. Although you can map ports to the host through port mapping, since the communication between Ray’s multiple nodes is complex, involving many ports, it is easy to make mistakes and difficult to configure correctly, so we do not recommend using the bridge mode to build the simulation cluster.
If you cannot use the host network for some unavoidable reasons, we hope the following instructions will be helpful for you to deploy SecretFlow using the bridge network.
Scenario 1: Deploying a simulation cluster using multiple Docker containers on a single machine.#
The following steps show how to start multiple containers on one machine. Since it is on the same machine, multiple containers can use the same bridge network for communication.
Create a bridege network
The following command creates a bridge network with network segment 192.168.0.1/24 named sfnet.
Note that this network segment is only an example, and you can modify the network segment address according to your own needs.
docker network create sfnet --subnet 192.168.0.1/24
Start the first container to simulate party
alice
The following command starts the container named secretflow0, uses the bridege network created in the first step, and specifies the ip as 192.168.0.10.
docker run -it --network sfnet --ip 192.168.0.10 --name secretflow1 secretflow/secretflow-anolis8:latest bash
After the container is started successfully, then we start the head node of ray. The following command starts Ray’s head node listening on port 9001 (you are free to choose an unused port).
ray start --head --port=9001 --resources='{"alice": 16}' --include-dashboard=False --disable-usage-stats
Start the second container to simulate party
bob
The following command starts the container named secretflow1, uses the bridege network created in the first step, and specifies the ip as 192.168.0.20.
docker run -it --network sfnet --ip 192.168.0.20 --name secretflow2 secretflow/secretflow-anolis8:latest bash
After starting the container, we start Ray’s slave node. The following command starts a slave node and connects to the head node started in the previous step.
ray start --address=192.168.0.10:9001 --resources='{"bob": 16}' --disable-usage-stats
So far we have built two Ray nodes, representing party alice and bob respectively.
Start SecretFlow
We start SecretFlow in the first container, the following Python code shows that SecretFlow has successfully connected to the Ray cluster.
>>> import secretflow as sf
>>> sf.init(parties=['alice', 'bob'], address='192.168.0.10:9001')
2023-02-18 07:08:29,697 INFO worker.py:1352 -- Connecting to existing Ray cluster at address: 192.168.0.10:9001...
2023-02-18 07:08:29,718 INFO worker.py:1538 -- Connected to Ray cluster.
>>> # your code to run
(Optional) Start the SPU device
This step describes how to start the SPU device. Suppose the SPU uses port 9100 on alice and port 9200 on bob. (port numbers are examples only, you can choose any free port)
import spu
import secretflow as sf
# Use ray head adress please.
sf.init(parties=['alice', 'bob'], address='192.168.0.10:9001')
cluster_def={
'nodes': [
{
'party': 'alice',
'address': '192.168.0.10:9100',
'listen_addr': '0.0.0.0:9100'
},
{
'party': 'bob',
'address': '192.168.0.20:9200',
'listen_addr': '0.0.0.0:9200'
},
],
'runtime_config': {
'protocol': spu.spu_pb2.SEMI2K,
'field': spu.spu_pb2.FM128,
'sigmoid_mode': spu.spu_pb2.RuntimeConfig.SIGMOID_REAL,
}
}
spu = sf.SPU(cluster_def=cluster_def)
# your code to run.
(Not recommended strongly) Scenario 2: Deploy a simulation cluster using multiple docker containers on multiple machines#
Due to the complexity of the Ray communication protocol, including cross-node mutual access and using many ports, it’s really complex and error-prone to deploy multiple containers on multiple machines using the bridge network to build a Ray cluster for simulation. Ray’s official support for this is not good, so we do not recommend this deployment mode.
Production#
SecretFlow provides multi controller mode for production with enhanced security. (If you want to know more, welcome to read Programming in SecretFlow)
A SecretFlow cluster for production consists of several ray clusters, and every party has its own ray cluster. Each participant must execute the code at the same time to complete the task of collaboration. The architecture of the production mode is shown in the figure below.

The following will guide you to deploy SecretFlow for production.
Setup a SecretFlow cluster crossing silo#
The following is an example showing how to build a cluster consisting of alice and bob for production.
Note
Please keep in mind that alice and bob should run the code simultaneously.
Start SecretFlow on the node of alice#
alice starts its ray cluster firstly. Note that the command here is to start Ray’s head node.
ray start --head --node-ip-address="ip" --port="port" --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see “Ray runtime started.” in the screen output. So far, Alice’s Ray cluster has been successfully built.
Then alice initializes SecretFlow with a cluster config and runs the code.
Tips
Replace
ip:portinsf.initwith thenode-ip-addressandportof head node please.Fill
addressofalicewith the address which can be accessed bybob. Remember to choose an unused port different with port of Ray and SPU.Fill
addressofbobwith the address which can be accessed byalice. Remember to choose an unused port different with port of Ray and SPU.Note that
self_partyisalice.Please note that
sf.initdoes not need to provide thepartiesparameter, but needs to provide acluster_configto describe the communication address and port between the two organizations.
cluster_config ={
'parties': {
'alice': {
# replace with alice's real address.
'address': 'ip:port of alice',
'listen_addr': '0.0.0.0:port'
},
'bob': {
# replace with bob's real address.
'address': 'ip:port of bob',
'listen_addr': '0.0.0.0:port'
},
},
'self_party': 'alice'
}
sf.init(address='alice ray head node address', cluster_config=cluster_config)
# your code to run.
Start SecretFlow on the node of bob#
bob starts its ray cluster firstly. Note that the command here is to start the head node of Ray, because bob needs to build a separate Ray cluster.
ray start --head --node-ip-address="ip" --port="port" --include-dashboard=False --disable-usage-stats
Head node starts successfully if you see “Ray runtime started.” in the screen output. So far, Alice’s Ray cluster has been successfully built.
Then bob initializes SecretFlow with a cluster config almost same as alice except for self_party and ray address and runs the code.
Tips
Replace
addressinsf.initwith thenode-ip-addressandportof head node please. Note, here is bob’s head node address, please don’t fill in alice’s.Fill
addressofalicewith the address which can be accessed bybob. Remember to choose an unused port different with port of Ray and SPU.Fill
addressofbobwith the address which can be accessed byalice. Remember to choose an unused port different with port of Ray and SPU.Note that
self_partyisbob.Please note that
sf.initdoes not need to provide thepartiesparameter, but needs to provide acluster_configto describe the communication address and port between the two organizations.
cluster_config ={
'parties': {
'alice': {
# replace with alice's real address.
'address': 'ip:port of alice',
'listen_addr': '0.0.0.0:port'
},
'bob': {
# replace with bob's real address.
'address': 'ip:port of bob',
'listen_addr': '0.0.0.0:port'
},
},
'self_party': 'bob'
}
sf.init(address='bob ray head node address', cluster_config=cluster_config)
# your code to run.
How to setup SPU for production#
The way to build the SPU is the same as the simulation mode, the only difference is that building the SPU also needs to be executed by multiple parties at the same time, please read the previous article for more details.
In order to avoid problems such as connection timeout caused by the startup time difference, you may need to set the link_desc parameter when initialize the SPU to adjust the connection-related parameters. For details, see
SPU .
Suggestions for production#
Enable tls Authentication.
SecretFlow can be configured to use TLS on cross-silo gRPC channels.
An example for alice.
tls_config = { "ca_cert": "ca root cert of other parties (e.g. bob)", "cert": "server cert of alice in pem", "key": "server key of alice in pem", } sf.init(address='ip:port', cluster_config=cluster_config, tls_config=tls_config )
An example for bob.
tls_config = { "ca_cert": "ca root cert of other parties (e.g. alice)", "cert": "server cert of bob in pem", "key": "server key of bob in pem", } sf.init(address='ip:port', cluster_config=cluster_config, tls_config=tls_config )
Enhanced serialization/deserialization.
SecretFlow uses
picklein serialization/deserialization which is vulnerable. You can setcross_silo_serializing_allowed_listwhen init SecretFlow to specify an allowlist to restrict serializable objects. An example could be (You should not use this demo directly. Configure it to your actual needs.)allowed_list = { "numpy.core.numeric": ["*"], "numpy": ["dtype"], } sf.init(address='ip:port', cluster_config=cluster_config, cross_silo_serializing_allowed_list=allowed_list )