本文最后更新于:2024年7月6日 早上
最近需要做一次面向公司的算法团队的k8s培训,算法的同事对于docker和gpu的使用还是比较熟悉的,随着大模型的发展,很多训练、测试、数据处理的任务都需要在k8s上进行,所以需要对k8s有一个基本的了解,基于这样的背景,我结合docker的使用,对k8s的一些概念进行了类比,希望能够帮助大家更好的理解k8s。
对于熟悉Docker的用户,在迁移到Kubernetes时,将某些概念进行类比可以帮助加快对Kubernetes的理解。本文将通过一个示例,阐述Docker和Kubernetes在容器编排方面的异同。
Docekr
Docker 是一个群众们喜闻乐见的容器技术,在过去10年中,它对传统的软件部署方式进行了革命式的颠覆(ps:截止 2023 年,Docker公司在K8s抛弃了Docekr的同时,对其仅有的护城河 Docker hub采取了一系列的收费政策,标志着昔日的屠龙少年,已经成为了一条暮年的巨龙)。言归正传,我们这里直接用时下热门的text-generation-inference大模型推理容器做个 docker 的例子。
1 2 3 4
| model=tiiuae/falcon-7b-instruct volume=$PWD/data
docker run --gpus all --shm-size 1g -p 8080:80 -v $volume:/data ghcr.io/huggingface/text-generation-inference:1.0.1 --model-id $model
|
大道至简,上面的命令已经完成了一个PPT大模型部署演示最低要求🤣🤣🤣
Docker Compose 编排
当然事情远没有这么简单,一个相对完整的最小化大模型应用,需要包含以下几个部分:
- 负责对话的web UI界面——HTML+CSS+JS ON NGINX
- 用户对话的后端服务——FastAPI
- 模型推理的后端服务——Text Generation Inference
- 数据库服务——MySQL
Docker Compose允许在一个文件中声明多个服务的容器化部署,使用docker-compose up可以方便地启动这些服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| version: '3' services:
nginx: image: nginx:latest ports: - "80:80" depends_on: - web
web: image: python:3.7-alpine command: uvicorn main:app --host 0.0.0.0 --port 5000 ports: - "5000:5000" depends_on: - db - tgi tgi: image: ghcr.io/huggingface/text-generation-inference:0.9.4 ports: - "8080:8080" command: --model-id meta-llama/Llama-2-70b-hf volumes: - models_data:/data deploy: resources: reservations: devices: - driver: nvidia count: 8 capabilities: [gpu] // 声明需要使用的GPU数量
db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: appdb ports: - "3306:3306"
volumes: db_data: models_data:
|
服务启动也很简单:
这非常适合本地开发和小规模部署。但对于复杂环境,Compose的功能有限。这需要一个更强大的编排平台,比如Kubernetes,来解决一些我们会关注的问题:
- gpu资源的分配
- 推理服务的负载均衡
- 模型的版本管理
- 模型弹性伸缩
Kubernetes编排
Kubernetes提供了比Docker Compose更广泛的编排功能。我们可以参考类似的概念,编写Kubernetes配置来部署这个应用:
- Pod vs 容器:Pod可以包含一个或多个紧耦合的容器。
- Deployment vs Compose:用于部署无状态应用的规范。
- Service vs 网络:提供服务发现和负载均衡的抽象。
- Volume vs 数据卷:用于存储抽象,可以通过PVC和PV实现。
- ConfigMap vs 环境变量:配置应用参数。
- HPA类似Docker的自动扩缩容,可以根据指标自动增加或减少Pod数量。
- Kubectl类似Docker Compose命令,用于部署和管理Kubernetes应用资源。
- Kubernetes也有镜像管理、密钥管理、日志查询等类似Docker的功能。
等等。这些概念对熟悉Docker的用户来说很亲切。组合使用这些资源,我们可以编排这个应用:
deployment.yaml 用用于部署应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| apiVersion: apps/v1 kind: Deployment metadata: annotations: kompose.cmd: kompose convert -f docekr-compose.yml kompose.version: 1.30.0 (9d8dcb518) creationTimestamp: null labels: io.kompose.service: tgi name: tgi namespace: default spec: replicas: 1 selector: matchLabels: io.kompose.service: tgi strategy: type: Recreate template: metadata: annotations: kompose.cmd: kompose convert -f docekr-compose.yml kompose.version: 1.30.0 (9d8dcb518) creationTimestamp: null labels: io.kompose.network/compose-k8s-default: "true" io.kompose.service: tgi spec: containers: - args: - --model-id - meta-llama/Llama-2-70b-hf image: ghcr.io/huggingface/text-generation-inference:0.9.4 name: tgi ports: - containerPort: 8080 hostPort: 8080 protocol: TCP resources: limits: nvidia.com/gpu: 1 volumeMounts: - mountPath: /data name: models-data restartPolicy: Always volumes: - name: models-data persistentVolumeClaim: claimName: models-data status: {}
|
PV和PVC的配置文件,用于存储模型数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: v1 kind: PersistentVolumeClaim metadata: creationTimestamp: null labels: io.kompose.service: models-data name: models-data namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 100Mi status: {}
|
service.yaml 用于暴露服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| apiVersion: v1 kind: Service metadata: annotations: kompose.cmd: kompose convert -f docekr-compose.yml kompose.version: 1.30.0 (9d8dcb518) creationTimestamp: null labels: io.kompose.service: tgi name: tgi namespace: default spec: ports: - name: "8080" port: 8080 targetPort: 8080 selector: io.kompose.service: tgi status: loadBalancer: {}
|
访问应用
可以通过NodePort或者更推荐的Ingress来访问部署的应用。Ingress提供负载均衡、SSL终止等高级功能。
展望
Docker Compose非常适合本地和小规模容器编排。对于大规模生产,Kubernetes提供了更丰富的功能,类比Docker概念可以帮助理解。组合使用两者可以发挥它们各自的优势。
在后续的实际应用的中我们会采用基于kserve的模型服务框架,基于kserve 对算法服务的抽象封装,算法工程师只需要提供相应的模型文件即可实现算法服务的上线,可以快速的反向运用于数据挖掘和自动化标注等。
参考