算法部署从docker到K8s

本文最后更新于:2024年4月20日 下午

最近需要做一次面向公司的算法团队的k8s培训,算法的同事对于docker和gpu的使用还是比较熟悉的,随着大模型的发展,很多训练、测试、数据处理的任务都需要在k8s上进行,所以需要对k8s有一个基本的了解,基于这样的背景,我结合docker的使用,对k8s的一些概念进行了类比,希望能够帮助大家更好的理解k8s。

对于熟悉Docker的用户,在迁移到Kubernetes时,将某些概念进行类比可以帮助加快对Kubernetes的理解。本文将通过一个示例,阐述Docker和Kubernetes在容器编排方面的异同。

docekr_k8s

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 # share a volume with the Docker container to avoid downloading weights every run

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:

服务启动也很简单:

1
docker compose up -d # docker-compose up -d for older versions

这非常适合本地开发和小规模部署。但对于复杂环境,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 # requesting 1 GPU
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 对算法服务的抽象封装,算法工程师只需要提供相应的模型文件即可实现算法服务的上线,可以快速的反向运用于数据挖掘和自动化标注等。

kserve

参考


算法部署从docker到K8s
https://yance.wiki/k8s_llm/
作者
Yance Huang
发布于
2023年9月8日
许可协议