k8sp/k8s-tensorflow

k8s 运行分布式 tensorflow 实验

Closed this issue · 9 comments

k8s 运行分布式 tensorflow 实验

实验基于 @wangkuiyi 给出的 GitHub 地址 https://github.com/amygdala/tensorflow-workshop/tree/master/workshop_sections/distributed_tensorflow

我们目标需要在 k8s 上运行 tensorflow + ceph, 先通过这个实验流程来熟悉 tensorflow 在 k8s 上可行性和流程, 后续使用 ceph 存储来代替 NFS. 下面会记录实验流程和注意事项.

准备工作

  • kubectl 能够正确连接 k8s 集群
  • Clone 这个仓库(amygdala/tensorflow-workshop) 到本地

Step1: 运行 nfs_server 在 k8s 上

项目文档中需要我们先创建一个 GCE Persistent Disk, 这里我们使用 k8s 集群的 Node 空间作为 NFS Server 的磁盘

# 测试 kubectl 和 k8s 集群连接正常
kubectl get node
kubectl get pod --namespace=kube-system

# 进入下面指定目录, 我克隆仓库在 /opt 
cd /opt/tensorflow-workshop-master/workshop_sections/distributed_tensorflow/k8s-configs

# 编辑 nfs-server-local.yaml, 删除 PersistentVolume 和 PersistentVolumeClaim 配置块, 因为我们没有使用 GCE 的磁盘
vim nfs-server-local.yaml
--------
kind: Service
apiVersion: v1
metadata:
  name: tf-nfs
spec:
  ports:
    - name: nfs
      port: 2049
    - name: mountd
      port: 20048
    - name: rpcbind
      port: 111
  selector:
    role: tf-nfs

---
apiVersion: v1
kind: ReplicationController
metadata:
  name: tf-nfs
spec:
  replicas: 1
  selector:
    role: tf-nfs
  template:
    metadata:
      labels:
        role: tf-nfs
    spec:
      containers:
      - name: tf-nfs
        image: gcr.io/google-samples/nfs-server:1.1
        ports:
          - name: nfs
            containerPort: 2049
          - name: mountd
            containerPort: 20048
          - name: rpcbind
            containerPort: 111
        securityContext:
          privileged: true
        volumeMounts:
          - mountPath: /exports
            name: mypvc
      volumes:
        - name: mypvc
          hostPath:
            path: /var/nfs-server
--------
# 创建 nfs-server
kubectl create -f nfs-server-local.yaml
# 查看 pod 创建过程日志, 如有报错, 会在里边输出
kubectl describe pod tf-nfs

Step2: 创建 nfs-pvc(PersistentVolumeClaim)

持久卷(PersistentVolumeClaim)持久化的存储(诸如gcePersistentiscsi卷)而且还无须知道特定云环境的细节,在pod中使用persistentVolumeClaim就可以挂载。

关于PersistentVolumeClaim的细节https://github.com/kubernetes/kubernetes/blob/release-1.0/docs/user-guide/persistent-volumes.md

创建 nfs 的持久卷

# 获得上面 tf-nfs 的 cluster ip 地址
kubectl get service tf-nfs
# 修改 nfs-pvc.yaml 中 server 地址为 上面的获得 
vim nfs-pvc.yaml
--------
server: 10.3.0.37
# 创建 pv 和 pvc
kubectl create -f nfs-pvc.yaml

注意: 使用 NFS, 需要为集群中 Node 装上 nfs client, 如果是 coreos , 打开 rpc-statd.service 服务即可.

Step3: 执行导入数据 Job

按部就班, 确保前面的流程都没有问题

kubectl create -f k8s-configs/load_data.yaml

Step4: 创建 Tensorboard Server

kubectl create -f k8s-configs/tensorboard.yaml
# 可以通过集群中任意 Node IP 加下面 NodePort 登录到 WEBUI(如: 10.10.10.203:31175)
kubectl describe services tensorboard
Name:           tensorboard
Namespace:      default
Labels:         <none>
Selector:       tensorflow=tensorboard
Type:           LoadBalancer
IP:         10.3.0.92
Port:           <unset> 80/TCP
NodePort:       <unset> 31175/TCP
Endpoints:      10.1.62.2:6006
Session Affinity:   None
No events.

Step5: 启动 Tensorflow Job

任务会拉取 gcr.io/google-samples/tf-worker-example:latest 这个镜像(740MB), 每个 Node 都会拉取, 速度很慢会导致任务失败.

这边解决方法是上传到 163 的 docker hub 上, 得到 hub.c.163.com/vienlee/tf-worker-example:latest , 替换 tf-cluster.yaml 中的 gcr.io/google-samples/tf-worker-example:latest 地址为hub.c.163.com/vienlee/tf-worker-example:latest 即可.

之所以没有用私有仓库, 因为当前没有搭建可用的私有仓库, 而且还需要支持 https(否则需要修改每个 Node 的 docker 配置增加私有仓库地址)

kubectl create -f tf-cluster.yaml
# 查看每个 pod 的状态
kubectl get pod
# 查看 pod 创建日志是否正常
kubectl describe pod <podname>

等待所有 Pod 创建成功, 状态为 Runing.

总结

通过实验证明 tensorflow 可以正常在 k8s 上运行, 后续流程我们可以提前创建 pv(使用 cephfs 存储) 和 pvc, 把训练数据导入到 pv 中. 然后编译我们自己的任务镜像, 编排 tf-cluster.yaml 执行任务.

kubectl create -f nfs-server 应该是kubectl create -f nfs-server-local.yaml,别的没问题

已修正问题.

  • tf-cluster.yaml 里面都写了什么信息?
  • gcr.io/google-samples/tf-worker-example:latest 这个能看到里面的运行脚本的内容吗,做了什么事情,或者有没有介绍?
  • https://github.com/amygdala/tensorflow-workshop/blob/master/workshop_sections/distributed_tensorflow 这里面有个CNN的例子,有Dockerfile,可以build image 和 tf-cluster.yaml 配合就能跑起来,熟悉使用 tensorboard 查看任务状态和信息 #10
    ,需要GPU 的cluster 先跑起来 #7
    ,和我们自己的dockerhub #9
    ,方便image存储

回答相关问题

  1. nfs-server-local.yaml 中 mountPath: /exports 和 path: /var/nfs-server 分别代表什么意思?

    path: /var/nfs-server 代表 node 对应的路径
    mountPath: /exports 代表挂载在容器中的路径

  2. https://github.com/amygdala/tensorflow-workshop/blob/master/workshop_sections/distributed_tensorflow/k8s-configs/ 中 nfs-server-local.yaml 和 nfs-server.yaml 什么区别

    nfs-server-local.yaml 和 nfs-server.yaml 区别就是是否使用挂载 gcePersistentDisk 的 PersistentVolumeClaim 卷

  3. 能把用的的yaml文件放到 git 里吗?

    没有明白问题描述的意思.

  4. 关于PersistentVolumeClaim的细节https://github.com/kubernetes/kubernetes/blob/release-1.0/docs/user-guide/persistent-volumes.md ,PersistentVolume 和 PersistentVolumeClaim 的使用方法, 一个 pod 通过 PersistentVolumeClaim 使用 PersistentVolume, 这个 PersistentVolume 会挂载在pod里,不需要挂载在 node 上吧?

    在 pod 的 yaml 的 volumes 中 persistentVolumeClaim 指定对应的持久卷名即可. 类似于集群的公共逻辑卷, 配置好配额和读写模式后就可以被 POD 挂载.

  5. tf-cluster.yaml 里面都写了什么信息?

    没有深入研究

  6. gcr.io/google-samples/tf-worker-example:latest 这个能看到里面的运行脚本的内容吗,做了什么事情,或者有没有介绍?

    没有找到对应 dockerfile, 推测应该和 https://github.com/amygdala/tensorflow-workshop/tree/master/workshop_sections/distributed_tensorflow/tf-worker 类似

k8s 使用 cephfs 创建 PersistentVolume

实验基于:

下面是流程描述和注意事项

准备工作

正常运行的 ceph 集群:

  • monitors: 10.10.10.204:6789, 10.10.10.205:6789, 10.10.10.206:6789
  • ceph.admin.key: AQBpza1XInniFRAAeHHDtf7oZkqvB8dXjP71/g==

创建 ceph 的 PersistentVolume 和 PersistentVolumeClaim

创建 ceph-pvc.yaml, 添加下面内容, 需要替换

  • key: 使用 Base64 加密过的字符串(使用命令 echo -n "AQBpza1XInniFRAAeHHDtf7oZkqvB8dXjP71/g==" | base64)
  • monitors: 替换 ceph 集群中的 monitors 信息
  • path: 设置挂载 cephfs 中的 /exports 目录为根(ceph 中 /exports 需要提前创建)
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
data:
  key: QVFCcHphMVhJbm5pRlJBQWVISER0ZjdvWmtxdkI4ZFhqUDcxL2c9PQ==
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: tf-ceph
  namespace: default
spec:
    capacity:
        storage: 100Gi
    accessModes:
        - ReadWriteMany
    cephfs:
      monitors:
      - 10.10.10.204:6789
      - 10.10.10.205:6789
      - 10.10.10.206:6789
      user: admin
      path: /exports
      secretRef:
        name: ceph-secret
      readOnly: false
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: tf-ceph
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Gi

开始创建名为 tf-ceph 的 PersistentVolume 和 PersistentVolumeClaim

# 创建 ceph-pvc
kubectl create -f ceph-pvc.yaml
# 查看持久卷状态
kubectl get pv,pvc

使用持久卷

创建 load_data.yaml 文件

apiVersion: batch/v1
kind: Job
metadata:
  name: load-data
spec:
  template:
    metadata:
      name: load-data
    spec:
      restartPolicy: Never
      containers:
        - name: loader
          image: gcr.io/google-samples/tf-workshop:v2
          command:
              - "/bin/sh"
              - "-c"
          args:
            - "curl https://storage.googleapis.com/oscon-tf-workshop-materials/processed_reddit_data/news_aww/prepared_data.tar.gz | tar xzv -C /var/tensorflow/"
          volumeMounts:
            - name: tf-ceph
              mountPath: /var/tensorflow
      volumes:
        - name: tf-ceph
          persistentVolumeClaim:
            claimName: tf-ceph

执行 load_data.yaml 任务

kubectl create -f load_data.yaml
# 查看任务状态, 是否有报错, 直到正常运行
kubectl describe pod load-data

通过上面的流程跑通了使用 cephfs 创建 PersistentVolume 和 PersistentVolumeClaim, 并能正确导入数据, 完成了 ceph 和 k8s 结合. tensorflow 或其他的 pod 只需要加入下面配置块, 就能正常挂载 ceph 了.

  • mountPath: 挂载到容器中的路径
          volumeMounts:
            - name: tf-ceph
              mountPath: /var/tensorflow
      volumes:
        - name: tf-ceph
          persistentVolumeClaim:
            claimName: tf-ceph

@vienlee 测试开启 Cephx 认证的 Ceph 与 k8s 结合,测试通过。

@ali8zake it was deleted by the author, which only can be visited from history commit now:
https://github.com/amygdala/tensorflow-workshop/tree/086d5a9f6ae2b4e76c5099b4a18acf3cb125fb9e/workshop_sections