使用 clusterIP 调度程序和端口转发在 gke 上安装 dask - 在 python 中创建 dask.distibuted 客户端时 tcp 连接超时

Installing dask on gke with clusterIP scheduler and port forwarding - tcp connection times out when creating a dask.distibuted client in python

我尝试使用 helm 和 tiller 在 gke 集群上部署 dask。 我没有为我的集群创建外部 IP 的权限,因此我将 dask 调度程序设置为 clusterIP 而不是负载均衡器。然后我使用 kubectl 提供的端口转发将 dask scehduler 服务转发到我的本地机器。

我有一个 python 代码(一个简单的 dask 示例),我想在其中将分布式客户端连接到 dask 调度程序的(转发的)tcp 端口并在我的 gke 集群中启动计算。 但是我在 tcp 连接上收到超时。

我想知道在此过程中我可能哪里出错了,或者我是否需要在我的 gcp 帐户中启用更多权限才能使其正常工作。非常感谢您提供的任何指示。 请注意,我能够在转发的 http 端口上打开 jupyter notebook,并且能够触发 dask 在我的 gke

上创建的默认 3 个工作人员的一些计算

我粘贴在 python 代码 I 运行、我看到的错误、pods 的当前状态、节点、gke 上 dask 的服务设置和命令我曾经在我的 gcp-gke

上设置 dask

我的示例 python 程序 (dask-example.py)

#!/usr/bin/env python3

from dask.distributed import Client
import dask.array as da

client = Client('tcp://127.0.0.1:8080')

array = da.ones((1000, 1000, 1000))

mn = array.mean().compute()  # Should print 1.0

print(mn)

错误消息(在 运行 python3 dask-example.py):

Traceback (most recent call last):
  File "/home/userenv/lib/python3.8/site-packages/distributed/comm/core.py", line 286, in connect
    comm = await asyncio.wait_for(
  File "/usr/lib/python3.8/asyncio/tasks.py", line 498, in wait_for
    raise exceptions.TimeoutError()
asyncio.exceptions.TimeoutError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "trial.py", line 17, in <module>
    client = Client('tcp://127.0.0.1:8080', timeout=10)
  File "/home/userenv/lib/python3.8/site-packages/distributed/client.py", line 743, in __init__
    self.start(timeout=timeout)
  File "/home/userenv/lib/python3.8/site-packages/distributed/client.py", line 948, in start
    sync(self.loop, self._start, **kwargs)
  File "/home/userenv/lib/python3.8/site-packages/distributed/utils.py", line 340, in sync
    raise exc.with_traceback(tb)
  File "/home/userenv/lib/python3.8/site-packages/distributed/utils.py", line 324, in f
    result[0] = yield future
  File "/home/userenv/lib/python3.8/site-packages/tornado/gen.py", line 762, in run
    value = future.result()
  File "/home/userenv/lib/python3.8/site-packages/distributed/client.py", line 1038, in _start
    await self._ensure_connected(timeout=timeout)
  File "/home/userenv/lib/python3.8/site-packages/distributed/client.py", line 1095, in _ensure_connected
    comm = await connect(
  File "/home/userenv/lib/python3.8/site-packages/distributed/comm/core.py", line 308, in connect
    raise IOError(
OSError: Timed out trying to connect to tcp://127.0.0.1:8080 after 10 s

我的 gke 上的 dask 状态

kubectl get po #显示这个

NAME                                       READY   STATUS              RESTARTS   AGE
my-dask-jupyter-565c5c5659-w4s76           1/1     Running             0          27h
my-dask-scheduler-6bf8bc8bbf-xgj2q         1/1     Running             0          27h
my-dask-worker-68b5b695bd-l2b6m            1/1     Running             0          27h
my-dask-worker-68b5b695bd-xnssz            1/1     Running             0          27h
my-dask-worker-68b5b695bd-z68wt            1/1     Running             0          27h

kubectl get no #shows this

NAME                                          STATUS   ROLES    AGE   VERSION
gke-dask-cluster-default-pool-d3f451b1-gp47   Ready    <none>   27h   v1.17.14-gke.1200
gke-dask-cluster-default-pool-d3f451b1-rk8z   Ready    <none>   27h   v1.17.14-gke.1200

kubectl get svc #shows this

NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)           AGE
kubernetes          ClusterIP   10.83.240.1    <none>        443/TCP           27h
my-dask-jupyter     ClusterIP   10.83.244.84   <none>        80/TCP            27h
my-dask-scheduler   ClusterIP   10.83.244.59   <none>        8786/TCP,80/TCP   27h

我用来设置 dask 的命令(多亏了这个 post https://libinruan.github.io/2019/05/24/Set-up-Kubernetes-clusters-for-Python-ML/

export PROJECTID='mygcp'
export EMAIL="user4098765@gmail.com"
export ZONE='us-central1-c'
export REGION='us-central1' 
export MIN_WORKER_NODES=0
export MAX_WORKER_NODES=100
export CLUSTER_NAME='dask-cluster'
export WORKER_MACHINE_TYPE='n1-standard-2'
export MACHINE_TYPE='n1-standard-2'
NUM_NODES=2
 
gcloud config set project $PROJECTID

gcloud services enable container.googleapis.com

gcloud container clusters create $CLUSTER_NAME --machine-type $MACHINE_TYPE --num-nodes $NUM_NODES --zone $ZONE --cluster-version latest

gcloud container clusters get-credentials $DASK_KUBE_CLUSTER_NAME --zone=$DASK_KUBE_CLUSTER_ZONE --project $DASK_GCLOUD_PROJECT

kubectl config set-cluster $DASK_KUBE_CLUSTER_NAME

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$EMAIL

kubectl create serviceaccount tiller --namespace=kube-system

kubectl create clusterrolebinding tiller --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
helm init --service-account tiller --wait

kubectl --namespace=kube-system patch deployment tiller-deploy --type=json \
--patch='[{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["/tiller", "--listen=localhost:44134"]}]'

gcloud container clusters get-credentials $CLUSTER_NAME --zone=$ZONE --project $PROJECTID

kubectl config set-cluster $DASK_KUBE_CLUSTER_NAME

helm install -n my-dask stable/dask -f dask-worker-spec.yml --set scheduler.serviceType=ClusterIP --set jupyter.serviceType=ClusterIP

我已经成功地重现了问题中描述的相同行为。

我鼓励您检查 dask 的较新版本,该版本在其主页上可用,因为问题中使用的版本 已弃用

TL;DR

使用 dask-scheduler 正在使用的相同 Python 模块(daskdistributed 等)软件版本!


重现问题中使用的设置

  • 创建GKE集群:
    • $ gcloud beta container clusters create "gke-dask" --zone "europe-west3-c" --no-enable-basic-auth --cluster-version "1.17.13-gke.2600" --release-channel "regular" --machine-type "e2-standard-4"

e2-standard-4 = 4 cores and 16GB RAM machine

  • 连接到集群:
    • $ gcloud container clusters get-credentials gke-dask --zone=europe-west3-c
  • 安装Helmv2(如果需要:):
  • 运行 舵图:
    • $ helm install -n my-dask stable/dask --set scheduler.serviceType=ClusterIP --set jupyter.serviceType=ClusterIP

为了确定问题,我 运行 进行了一些测试:

  • $ kubectl port-forward dask-scheduler 到我的机器并使用问题中的示例 Python 代码。我安装了此代码所需的依赖项,但版本不同($ pip install dask[complete]代码失败,并显示与问题中相同的消息。
  • $ kubectl run -it --rm ubuntu -- /bin/bash - 问题中的错误表明它可能是与网络相关的问题。我使用 ubuntu Pod 和相同的 Python 安装来消除潜在的网络连接问题 (port-forward)。 代码失败并显示与问题中相同的消息。
  • $ kubectl exec -it DASK-SCHEDULER-POD-NAME -- /bin/bash - 如果这是网络连接问题,它应该在应该处理此代码的 Pod 上 运行。 代码 运行 成功并返回 1.0

我尝试将 ubuntu Pod 与 Python 一起使用,它的模块与 dask-scheduler 中的版本更接近。 它产生了一个与问题不同的错误。这表明网络没有固有问题,但使用的软件(它的版本)没有问题。我无法完全复制 dask-scheduler 中使用的设置,所以我使用了 dask-scheduler 正在使用的图像并生成了额外的 Pod 来检查它是否可以通过 GKE 网络。 成功了!

Please conisder below example to be a workaround!

从您的机器到 运行 的步骤:

  • $ kubectl port-forward service/my-dask-scheduler --address 0.0.0.0 8786:8786 & - 转发 dask 服务到您的机器
  • $ docker run --rm -ti daskdev/dask:1.1.5 /bin/bash - 运行 一个 Docker 容器在你的机器上 exec 进入它的 bash。此图像与您的 dask-scheduler 相同,以保留 Python 及其模块版本。
  • 在容器内使用以下 Python 代码:
#!/usr/bin/env python3
from dask.distributed 
import Client
import dask.array as da
client = Client('tcp://IP_ADDRESS:8786')
array = da.ones((1000, 1000, 1000))
mn = array.mean().compute() # Should print 1.0
print(mn)

Please put in the "IP_ADDRESS" the IP address of your machine that is accessible from your Docker container!

您应该得到以下输出:

(base) root@81fb5004ea4c:/# python3 script.py 
1.0

您可以检查 Python venv 虚拟环境。

附加参考: