Run Flower using Docker#

The simplest way to get started with Flower is by using the pre-made Docker images, which you can find on Docker Hub.

Before you start, make sure that the Docker daemon is running:

$ docker -v
Docker version 26.0.0, build 2ae903e

If you do not see the version of Docker but instead get an error saying that the command was not found, you will need to install Docker first. You can find installation instruction here.

Note

On Linux, Docker commands require sudo privilege. If you want to avoid using sudo, you can follow the Post-installation steps on the official Docker website.

Important

To ensure optimal performance and compatibility, the SuperLink, SuperNode and ServerApp image must have the same version when running together. This guarantees seamless integration and avoids potential conflicts or issues that may arise from using different versions.

Flower SuperNode#

The SuperNode Docker image comes with a pre-installed version of Flower and serves as a base for building your own SuperNode image.

Important

The SuperNode Docker image currently works only with the 1.9.0-nightly release. A stable version will be available when Flower 1.9.0 (stable) gets released (ETA: May). A SuperNode nightly image must be paired with the corresponding SuperLink and ServerApp nightly images released on the same day. To ensure the versions are in sync, using the concrete tag, e.g., 1.9.0.dev20240501 instead of nightly is recommended.

We will use the quickstart-pytorch example, which you can find in the Flower repository, to illustrate how you can dockerize your ClientApp.

Prerequisites#

Before we can start, we need to meet a few prerequisites in our local development environment. You can skip the first part if you want to run your ClientApp instead of the quickstart-pytorch example.

  1. Clone the Flower repository.

    $ git clone --depth=1 https://github.com/adap/flower.git && cd flower/examples/quickstart-pytorch
    
  2. Verify the Docker daemon is running.

    Please follow the first section on Run Flower using Docker which covers this step in more detail.

Creating a SuperNode Dockerfile#

Let’s assume the following project layout:

$ tree .
.
├── client.py        # ClientApp code
└── <other files>

First, we need to create a requirements.txt file in the directory where the ClientApp code is located. In the file, we list all the dependencies that the ClientApp requires.

flwr-datasets[vision]>=0.0.2,<1.0.0
torch==2.1.1
torchvision==0.16.1
tqdm==4.66.3

Important

Note that flwr is already installed in the flwr/supernode base image, so you only need to include other package dependencies in your requirements.txt, such as torch, tensorflow, etc.

Next, we create a Dockerfile. If you use the quickstart-pytorch example, create a new file called Dockerfile.supernode in examples/quickstart-pytorch.

The Dockerfile.supernode contains the instructions that assemble the SuperNode image.

FROM flwr/supernode:nightly

WORKDIR /app

COPY requirements.txt .
RUN python -m pip install -U --no-cache-dir -r requirements.txt && pyenv rehash

COPY client.py ./
ENTRYPOINT ["flower-client-app", "client:app"]

In the first two lines, we instruct Docker to use the SuperNode image tagged nightly as a base image and set our working directory to /app. The following instructions will now be executed in the /app directory. Next, we install the ClientApp dependencies by copying the requirements.txt file into the image and run pip install. In the last two lines, we copy the client.py module into the image and set the entry point to flower-client-app with the argument client:app. The argument is the object reference of the ClientApp (<module>:<attribute>) that will be run inside the ClientApp.

Building the SuperNode Docker image#

Next, we build the SuperNode Docker image by running the following command in the directory where Dockerfile and ClientApp code are located.

$ docker build -f Dockerfile.supernode -t flwr_supernode:0.0.1 .

We gave the image the name flwr_supernode, and the tag 0.0.1. Remember that the here chosen values only serve as an example. You can change them to your needs.

Running the SuperNode Docker image#

Now that we have built the SuperNode image, we can finally run it.

$ docker run --rm flwr_supernode:0.0.1 client:app \
  --insecure \
  --server 192.168.1.100:9092

Let’s break down each part of this command:

  • docker run: This is the command to run a new Docker container.

  • --rm: This option specifies that the container should be automatically removed when it stops.

  • flwr_supernode:0.0.1: The name the tag of the Docker image to use.

  • --insecure: This option enables insecure communication.

Attention

The --insecure flag enables insecure communication (using HTTP, not HTTPS) and should only be used for testing purposes. We strongly recommend enabling SSL when deploying to a production environment.

  • --server 192.168.1.100:9092: This option specifies the address of the SuperLinks Fleet
    API to connect to. Remember to update it with your SuperLink IP.

Note

To test running Flower locally, you can create a bridge network, use the --network argument and pass the name of the Docker network to run your SuperNodes.

Any argument that comes after the tag is passed to the Flower SuperNode binary. To see all available flags that the SuperNode supports, run:

$ docker run --rm flwr/supernode:nightly --help

Enabling SSL for secure connections#

To enable SSL, we will need to mount a PEM-encoded root certificate into your SuperNode container.

Assuming the certificate already exists locally, we can use the flag --volume to mount the local certificate into the container’s /app/ directory. This allows the SuperNode to access the certificate within the container. Use the --certificates flag when starting the container.

$ docker run --rm --volume ./ca.crt:/app/ca.crt flwr_supernode:0.0.1 client:app \
  --server 192.168.1.100:9092 \
  --certificates ca.crt

Flower ServerApp#

The procedure for building and running a ServerApp image is almost identical to the SuperNode image.

Similar to the SuperNode image, the ServerApp Docker image comes with a pre-installed version of Flower and serves as a base for building your own ServerApp image.

We will use the same quickstart-pytorch example as we do in the Flower SuperNode section. If you have not already done so, please follow the SuperNode Prerequisites before proceeding.

Creating a ServerApp Dockerfile#

Let’s assume the following project layout:

$ tree .
.
├── server.py        # ServerApp code
└── <other files>

First, we need to create a Dockerfile in the directory where the ServerApp code is located. If you use the quickstart-pytorch example, create a new file called Dockerfile.serverapp in examples/quickstart-pytorch.

The Dockerfile.serverapp contains the instructions that assemble the ServerApp image.

FROM flwr/serverapp:1.8.0

WORKDIR /app

COPY server.py ./
ENTRYPOINT ["flower-server-app", "server:app"]

In the first two lines, we instruct Docker to use the ServerApp image tagged 1.8.0 as a base image and set our working directory to /app. The following instructions will now be executed in the /app directory. In the last two lines, we copy the server.py module into the image and set the entry point to flower-server-app with the argument server:app. The argument is the object reference of the ServerApp (<module>:<attribute>) that will be run inside the ServerApp container.

Building the ServerApp Docker image#

Next, we build the ServerApp Docker image by running the following command in the directory where Dockerfile and ServerApp code are located.

$ docker build -f Dockerfile.serverapp -t flwr_serverapp:0.0.1 .

We gave the image the name flwr_serverapp, and the tag 0.0.1. Remember that the here chosen values only serve as an example. You can change them to your needs.

Running the ServerApp Docker image#

Now that we have built the ServerApp image, we can finally run it.

$ docker run --rm flwr_serverapp:0.0.1 \
  --insecure \
  --server 192.168.1.100:9091

Let’s break down each part of this command:

  • docker run: This is the command to run a new Docker container.

  • --rm: This option specifies that the container should be automatically removed when it stops.

  • flwr_serverapp:0.0.1: The name the tag of the Docker image to use.

  • --insecure: This option enables insecure communication.

Attention

The --insecure flag enables insecure communication (using HTTP, not HTTPS) and should only be used for testing purposes. We strongly recommend enabling SSL when deploying to a production environment.

  • --server 192.168.1.100:9091: This option specifies the address of the SuperLinks Driver
    API to connect to. Remember to update it with your SuperLink IP.

Note

To test running Flower locally, you can create a bridge network, use the --network argument and pass the name of the Docker network to run your ServerApps.

Any argument that comes after the tag is passed to the Flower ServerApp binary. To see all available flags that the ServerApp supports, run:

$ docker run --rm flwr/serverapp:1.8.0 --help

Enabling SSL for secure connections#

To enable SSL, we will need to mount a PEM-encoded root certificate into your ServerApp container.

Assuming the certificate already exists locally, we can use the flag --volume to mount the local certificate into the container’s /app/ directory. This allows the ServerApp to access the certificate within the container. Use the --certificates flag when starting the container.

$ docker run --rm --volume ./ca.crt:/app/ca.crt flwr_serverapp:0.0.1 client:app \
  --server 192.168.1.100:9091 \
  --certificates ca.crt

Advanced Docker options#

Using a different Flower version#

If you want to use a different version of Flower, for example Flower nightly, you can do so by changing the tag. All available versions are on Docker Hub.

Pinning a Docker image to a specific version#

It may happen that we update the images behind the tags. Such updates usually include security updates of system dependencies that should not change the functionality of Flower. However, if you want to ensure that you always use the same image, you can specify the hash of the image instead of the tag.

The following command returns the current image hash referenced by the superlink:1.8.0 tag:

$ docker inspect --format='{{index .RepoDigests 0}}' flwr/superlink:1.8.0
flwr/superlink@sha256:1b855d1fa4e344e4d95db99793f2bb35d8c63f6a1decdd736863bfe4bb0fe46c

Next, we can pin the hash when running a new SuperLink container:

$ docker run \
  --rm flwr/superlink@sha256:1b855d1fa4e344e4d95db99793f2bb35d8c63f6a1decdd736863bfe4bb0fe46c \
  --insecure

Setting environment variables#

To set a variable inside a Docker container, you can use the -e <name>=<value> flag.

$ docker run -e FLWR_TELEMETRY_ENABLED=0 \
  --rm flwr/superlink:1.8.0 --insecure