| <!-- |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| # Running Python pipelines on a local Flink cluster |
| |
| This guide describes a contributor workflow for validating Python Beam pipelines |
| against a real local Flink standalone cluster. It is useful when embedded Flink |
| is not enough, for example when validating streaming source behavior, checkpoint |
| boundaries, or runner-visible job state in the Flink dashboard. |
| |
| The commands assume a Unix shell (Linux, macOS, or WSL2 on Windows) with `curl`, |
| `tar`, and `java` on the `PATH`. |
| |
| * [What this setup validates](#what-this-setup-validates) |
| * [Prerequisites](#prerequisites) |
| * [Start a local Flink cluster](#start-a-local-flink-cluster) |
| * [Run a Beam Python pipeline](#run-a-beam-python-pipeline) |
| * [Troubleshooting](#troubleshooting) |
| * [Stop the cluster](#stop-the-cluster) |
| |
| ## What this setup validates |
| |
| This setup runs three components: |
| |
| 1. A Flink standalone cluster, consisting of a JobManager and a TaskManager. |
| 1. A Beam Flink Job Server, started by the Python `FlinkRunner`. |
| 1. A Python SDK harness, using `--environment_type=LOOPBACK` for local |
| development. |
| |
| The Flink dashboard at `http://localhost:8081` shows the submitted Beam jobs. |
| This is different from embedded Flink mode, where the cluster is started only |
| for the lifetime of one job and is not useful for manual dashboard inspection. |
| |
| ## Prerequisites |
| |
| Install or prepare the following: |
| |
| * Docker Desktop (optional), only for the alternative method of obtaining the |
| Flink distribution. |
| * A Unix shell: Linux, macOS, or WSL2 on Windows. |
| * Java 11 on the `PATH`. |
| * A Python environment with the Beam SDK dependencies installed. |
| * A Beam source checkout for the Python code under test. |
| * A Flink 1.20 Job Server jar built from the same Beam checkout when validating |
| unreleased Beam changes. |
| |
| For a source-built Job Server jar, run this command from the Beam checkout: |
| |
| ```sh |
| ./gradlew :runners:flink:1.20:job-server:shadowJar |
| ``` |
| |
| The jar is written under: |
| |
| ```text |
| runners/flink/1.20/job-server/build/libs/ |
| ``` |
| |
| ## Start a local Flink cluster |
| |
| Use a Flink distribution whose minor version matches a Flink version supported |
| by your Beam version. See the [Flink Version Compatibility](https://beam.apache.org/documentation/runners/flink/#flink-version-compatibility) |
| table in the Flink Runner documentation, and confirm the exact patch version on |
| the [Flink downloads page](https://flink.apache.org/downloads.html). This guide |
| uses Flink 1.20. |
| |
| Download and unpack the binary distribution: |
| |
| ```sh |
| FLINK_VERSION=1.20.1 |
| curl -fLO "https://archive.apache.org/dist/flink/flink-${FLINK_VERSION}/flink-${FLINK_VERSION}-bin-scala_2.12.tgz" |
| tar -xzf "flink-${FLINK_VERSION}-bin-scala_2.12.tgz" -C "$HOME" |
| export FLINK_HOME="$HOME/flink-${FLINK_VERSION}" |
| ``` |
| |
| Ensure these settings exist in `$FLINK_HOME/conf/config.yaml`: |
| |
| ```yaml |
| jobmanager.rpc.address: localhost |
| rest.address: localhost |
| taskmanager.numberOfTaskSlots: 2 |
| ``` |
| |
| Start the cluster. The JobManager and TaskManager run as background daemons: |
| |
| ```sh |
| "$FLINK_HOME/bin/start-cluster.sh" |
| ``` |
| |
| Verify that the JobManager and TaskManager are available: |
| |
| ```sh |
| curl -fsS http://localhost:8081/overview |
| ``` |
| |
| Expected output includes one TaskManager and two slots: |
| |
| ```json |
| {"taskmanagers":1,"slots-total":2,"slots-available":2,"jobs-running":0} |
| ``` |
| |
| You can also open the Flink dashboard in a browser: |
| |
| ```text |
| http://localhost:8081 |
| ``` |
| |
| ### Alternative: extract Flink from the Docker image |
| |
| If a direct download is not available, copy the distribution out of the Flink |
| Docker image with `docker cp`: |
| |
| ```sh |
| docker create --name flink-dist flink:1.20 |
| docker cp flink-dist:/opt/flink "$HOME/flink-1.20" |
| docker rm flink-dist |
| export FLINK_HOME="$HOME/flink-1.20" |
| ``` |
| |
| A distribution copied out of a Docker image can contain the container hostname in |
| `conf/config.yaml`; see [Troubleshooting](#troubleshooting). |
| |
| ## Run a Beam Python pipeline |
| |
| For local Python development, use `FlinkRunner`, point it at the standalone |
| cluster, and use `LOOPBACK` so the Python SDK harness runs in the local process. |
| |
| Use a source checkout on `PYTHONPATH` when validating unreleased Python changes. |
| Set paths for your environment: |
| |
| ```sh |
| export BEAM_CHECKOUT="$HOME/beam" |
| export PYTHON="$HOME/beamenv/bin/python" |
| export FLINK_JOB_SERVER_JAR="$(find "$BEAM_CHECKOUT/runners/flink/1.20/job-server/build/libs" \ |
| -name 'beam-runners-flink-1.20-job-server-*.jar' | head -n 1)" |
| ``` |
| |
| Run a small pipeline: |
| |
| ```sh |
| printf 'to be or not to be\nbeam runs on flink\n' > /tmp/beam-flink-input.txt |
| |
| PYTHONPATH="$BEAM_CHECKOUT/sdks/python" "$PYTHON" -m apache_beam.examples.wordcount \ |
| --runner=FlinkRunner \ |
| --flink_master=localhost:8081 \ |
| --flink_version=1.20 \ |
| --flink_job_server_jar="$FLINK_JOB_SERVER_JAR" \ |
| --environment_type=LOOPBACK \ |
| --input=/tmp/beam-flink-input.txt \ |
| --output=/tmp/beam-flink-counts |
| ``` |
| |
| For released Beam, omit `--flink_job_server_jar` and the `PYTHONPATH` prefix; the |
| `FlinkRunner` downloads a Job Server matching `--flink_version` automatically. The |
| source checkout and built jar are only needed to test unreleased changes. |
| |
| Check the dashboard or REST API after the run: |
| |
| ```sh |
| curl -fsS http://localhost:8081/jobs/overview |
| ``` |
| |
| The job should be `FINISHED`. |
| |
| ## Troubleshooting |
| |
| If the TaskManager does not register, check `$FLINK_HOME/conf/config.yaml`. |
| When a distribution is copied out of a Docker image, the file might contain the |
| container hostname. Replace it with: |
| |
| ```yaml |
| jobmanager.rpc.address: localhost |
| ``` |
| |
| If a Python job fails on native Windows with an invalid path containing `:`, |
| run the Python driver and Job Server from WSL2. Some staged artifact names used |
| by the portable runner are valid on Linux but invalid as native Windows file |
| names. |
| |
| On WSL2, keep at least one shell open in the distribution while the cluster runs. |
| Closing the last shell can stop the distribution and its background daemons. |
| |
| If the job starts but the Python transforms do not execute, check the |
| environment type. `LOOPBACK` is intended for local development. For a remote |
| or multi-machine Flink cluster, use a containerized environment instead. |
| |
| ## Stop the cluster |
| |
| Stop the local cluster when you finish collecting results: |
| |
| ```sh |
| "$FLINK_HOME/bin/stop-cluster.sh" |
| ``` |