K8S
基础
示例
开发
运行带 Pytorch 的 JupyterLab 开发环境

运行带 Pytorch 的 JupyterLab 开发环境

PyTorch 是一个非常流行的深度学习框架,尤其在 GPU 上运行时能显著提高速度,通常与 Jupyter 一起使用进行开发工作。

前提

存储 PVC

利用持久卷可确保文件持久存在,即使当前运行 Pod 的节点失败。在此示例中,分配了持久卷以保留用户数据。

通过 Kubernetes PersistentVolumeClaim 进行持久卷存储的分配,通常称为 PVC,它请求存储大小和要使用的后端存储类型(例如: shared-nvme)。在此示例中,PVC 在 pvc.yaml 文件中定义。

pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jupyter
spec:
  storageClassName: shared-nvme
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Gi

部署 Deployment

在这个例子中,使用一个 Kubernetes manifests 来部署一个包含 Pytorch 的 JupyterLab 开发环境服务。

  • spec.strategy 用于设置 Pod 同时只存在一个
  • metadata.labels 用于为 Pod 设置上标签,selector.matchLabels 用于为 Deployment 选中标签为 name: jupyter 的 Pod 进行控制
  • spec.containers 描述 1 个 Container
    • 一个名字为 jupyter 的 Container 用于提供开发环境
      • --NotebookApp.token 设置固定 Token,否则 Jupyter Lab 生成随机的 Token 需要执行 kubectl logs --tail 100 [pod-name] 获取
      • 申请并限制 10 vCPU, 60Gi 内存和 1 个 GPU
      • 把 pvc 挂在 Container 内的 /workspace/data 目录下存放用户需要持久的数据
  • spec.volumes 描述使用上面创建 pvc 持久卷
  • spec.tolerations 描述容忍 nvidia.com/gpu 污点存在,即可以使用 GPU 节点。通常在 K8S 使用污点以确保 Pod (例如纯 CPU 负载) 不会被调度到不适当节点上。
  • spec.affinity 描述节点亲和性,用于控制偏好或者必须使用那些类型的节点,例如示例必须使用 RTX 3090 节点
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jupyter
spec:
  strategy:
    type: Recreate
  replicas: 1
  selector:
    matchLabels:
      name: jupyter
  template:
    metadata:
      labels:
        name: jupyter
    spec:
      containers:
        - name: jupyter
          image: nvcr.io/nvidia/pytorch:24.01-py3
          command:
          - jupyter
          - lab
          - --allow-root
          - --no-browser
          - --ip=0.0.0.0
          - --NotebookApp.token=gn47wk9tsar2e3bxwwfn7kha2d64jy
          env:
          - name: JUPYTER_PORT
            value: '8888'
          ports:
            - name: http
              containerPort: 8888
              protocol: TCP
          resources:
            limits:
              cpu: 10
              memory: 60Gi
              nvidia.com/gpu: 1
          volumeMounts:
            - name: data
              mountPath: /workspace
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: jupyter
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nvidia.com/gpu
                operator: In
                values:
                  - rtx-3090

服务 Service

提供一个集群内的负载均衡器到 Jupyter 实例。

下面示例是:

  1. 使用 selector 选中标签为 name: jupyter 的 Pod
  2. Pod 端口名字为 targetPort: http (对应 Deployment 中的定义)
  3. 并以 port: 80 及名字 name: http 提供集群内 type: ClusterIP 的负载均衡服务
  4. 另外设置 port: 8080 用于暴露实例内自定义服务
service.yaml
apiVersion: v1
kind: Service
metadata:
  name: jupyter
spec:
  type: ClusterIP
  selector:
    name: jupyter
  ports:
    - port: 80
      name: http
      targetPort: http
      protocol: TCP
    - port: 8080
      name: app
      targetPort: 8080
      protocol: TCP

入口 Ingress

Ingress 用于暴露应用程序到互联网,从而通过 https 协议访问应用程序。

下面示例是:

  1. rules.host: jupyter.c1-389a8e0c7dfc.ing.zw1.paratera.com
  2. 路由 path: /
  3. 到 Service name: jupyterport: 80
  4. 同时开启 spec.tls 并设置自动申请 cert-manager.io/cluster-issuer: zerossl-prod 证书
  5. 额外设置 app.c1-389a8e0c7dfc.ing.zw1.paratera.com 用于暴露实例内监听在 8080 端口的自定义服务
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jupyter
  annotations:
    cert-manager.io/cluster-issuer: zerossl-prod
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - jupyter.c1-389a8e0c7dfc.ing.zw1.paratera.com
        - app.c1-389a8e0c7dfc.ing.zw1.paratera.com
      secretName: jupyter-tls
  rules:
    - host: jupyter.c1-389a8e0c7dfc.ing.zw1.paratera.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: jupyter
                port:
                  number: 80
    - host: app.c1-389a8e0c7dfc.ing.zw1.paratera.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: jupyter
                port:
                  number: 8080

运行示例

  1. 部署

    kubectl apply -f pvc.yaml 
    kubectl apply -f deployment.yaml
    kubectl apply -f service.yaml
    kubectl apply -f ingress.yaml
  2. 查看已创建 Pod

    kubectl get pods

    等待 Pod 进入 Running 状态.

    如果 Pod 一直不能进入 Running,可以通过下面的命令查看 Pod 的详细信息

    kubectl describe pod [pod-name]
  3. 查看 Ingress

    kubectl get ing

    如果 Ingress 准备好,一般在输出 ADDRESS 字段会分配一个 IP 地址

  4. 访问服务

    使用从 Ingress 获取 Hosts 地址,然后在浏览器中访问 (Token 使用 Deployment 预设值)。

    🎉 恭喜!您已在 Kubernetes 上部署一个 JupyterLab 开发环境!