使用 Kubernetes 进行开发
直接在 Kubernetes 上进行开发使我们更有信心最终用户的部署将按预期工作。
本页介绍如何通用地使用 Kubernetes 以及如何在本地 Kubernetes 集群上部署 nv-ingest。
注意: 除非另有说明,否则以下所有命令都应从本仓库的根目录运行。
Kubernetes 集群
首先,你需要一个 Kubernetes 集群。我们建议你使用 kind
,它会创建一个包含 Kubernetes 集群的单个 Docker 容器。
由于 kind
集群需要访问你系统上的 GPU,你需要安装 nvkind
。有关详细信息,请参阅 使用 nvkind 运行带有 GPU 的 kind 集群。nvkind
提供以下好处
- 同一系统上的多个开发者可以拥有隔离的 Kubernetes 集群
- 易于创建和删除集群
从仓库的根目录,运行以下代码为你的集群创建一个配置文件。
mkdir -p ./.tmp
cat <<EOF > ./.tmp/kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: nv-ingest-${USER}
nodes:
- role: control-plane
image: kindest/node:v1.29.2
{{- range $gpu := until numGPUs }}
- role: worker
extraMounts:
# We inject all NVIDIA GPUs using the nvidia-container-runtime.
# This requires 'accept-nvidia-visible-devices-as-volume-mounts = true' be set
# in '/etc/nvidia-container-runtime/config.toml'
- hostPath: /dev/null
containerPath: /var/run/nvidia-container-devices/{{ $gpu }}
{{- end }}
EOF
然后,使用 nvkind
CLI 创建你的集群。
nvkind cluster create \
--config-template ./.tmp/kind-config.yaml
你应该看到如下输出
Creating cluster "jdyer" ...
✓ Ensuring node image (kindest/node:v1.27.11) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-jdyer"
You can now use your cluster with:
kubectl cluster-info --context kind-jdyer
Have a nice day! 👋
你可以使用 kind get clusters
列出系统上的集群。
kind get clusters
# jdyer
你也可以直接使用 docker ps
查看 kind 容器。
docker ps | grep kind
# aaf5216a3cc8 kindest/node:v1.27.11 "/usr/local/bin/entr…" 44 seconds ago Up 42 seconds 127.0.0.1:45099->6443/tcp jdyer-control-plane
kind create cluster
执行以下操作
- 为集群添加上下文到
${HOME}/.kube/config
,这是kubectl
等工具使用的默认配置文件 - 将默认上下文更改为
${HOME}/.kube/config
你应该能够立即使用 kubectl
,并且它应该指向你刚刚创建的集群。
例如,尝试列出节点以验证集群是否已成功设置。
kubectl get nodes
如果成功,你应该看到如下单个节点
NAME STATUS ROLES AGE VERSION
jdyer-control-plane Ready control-plane 63s v1.27.11
注意:并非所有在你的 Kubernetes 集群内部创建的容器在你运行 docker ps
时都会出现,因为其中一些容器嵌套在单独的命名空间中。
如需解决出现的问题,请参阅 故障排除。
Skaffold
现在你已经有了一个 Kubernetes 集群,你可以使用 Skaffold 构建和部署你的开发环境。
在单个命令中,Skaffold 执行以下操作
- 从当前目录构建容器 (通过
docker build
) - 安装 retriever-ingest helm charts (通过
helm install
) - 应用额外的 Kubernetes manifests (通过
kustomize
) - 热重载 - Skaffold 监视你的本地目录中的更改并将它们同步到 Kubernetes 容器中
- 将 ingest 服务端口转发到主机
目录结构
skaffold/sensitive/
包含你想要部署到集群但不想检入 git 的任何 secrets 或 manifests,因为你的本地集群不太可能安装 ESO。如果安装了,请随意使用kind: ExternalSecret
代替。skaffold/components
包含你想要在任何 skaffold 文件中部署的任何 k8s manifests。路径是相对的,可以用于kustomize
或rawYaml
格式
manifests:
rawYaml:
- sensitive/*.yaml
kustomize:
paths:
- components/elasticsearch
- 如果添加新服务,请首先尝试获取 helm 对象。如果不存在,你可能需要将其与你的 k8s manifests 封装在
skaffold/components
中。我们是一家 k8s 公司,因此可能需要不时编写 manifest。
先决条件
添加 Helm 仓库
retriever-ingest 服务的部署需要从第三方来源(例如 Elasticsearch、OpenTelemetry 和 Postgres)拉取其他服务的配置。
首次将此项目部署到本地 Kubernetes 时,你可能需要通过运行类似于以下代码的代码,告诉你的本地 Helm 版本(Kubernetes 配置的包管理器)在哪里可以找到第三方服务。
helm repo add \
nvdp \
https://nvda.org.cn/k8s-device-plugin
helm repo add \
zipkin \
https://zipkin.io/zipkin-helm
helm repo add \
opentelemetry \
https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo add \
nvidia \
https://helm.ngc.nvidia.com/nvidia
helm repo add \
bitnami \
https://charts.bitnami.com/bitnami
有关仓库的完整列表,请参阅 Chart.yaml 文件中的 dependencies
部分。
NVIDIA GPU 支持
为了让 Kubernetes pods 访问 NVIDIA GPU 资源,你必须安装 NVIDIA device plugin for Kubernetes。此插件有很多配置,但要开始开发,只需运行以下代码。
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.15.0/deployments/static/nvidia-device-plugin.yml
创建镜像拉取 Secret
你还需要提供一个 Kubernetes Secret,其中包含用于拉取 NVIDIA 私有 Docker 镜像的凭据。
对于生命周期较短的开发集群,只需使用你自己的个人凭据。
DOCKER_CONFIG_JSON=$(
cat "${HOME}/.docker/config.json" \
| base64 -w 0
)
cat <<EOF > ./skaffold/sensitive/imagepull.yaml
apiVersion: v1
kind: Secret
metadata:
name: nvcrimagepullsecret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: ${DOCKER_CONFIG_JSON}
EOF
你需要一个 NGC 个人 API 密钥才能访问托管在 NGC 上的模型和镜像。首先,生成 API 密钥。接下来,通过运行以下代码将密钥存储在环境变量中。
export NGC_API_KEY="<YOUR_KEY_HERE>"
然后,使用以下命令创建 secret manifest
kubectl create secret generic ngcapisecrets \
--from-literal=ngc_api_key="${NGC_API_KEY}" \
--dry-run=client -o yaml \
> skaffold/sensitive/ngcapi.yaml
部署服务
运行以下命令将 retriever-ingest 部署到你的集群。
skaffold dev \
-v info \
-f ./skaffold/nv-ingest.skaffold.yaml \
--kube-context "kind-nv-ingest-${USER}"
这些标志的解释(点击我)
--v info
= 打印来自 skaffold
及其调用的工具(如 helm
或 kustomize
)的 INFO 级别及以上日志 - -f ./skaffold/nv-ingest.skaffold.yaml
= 使用特定于 retriever-ingest 的配置 - --tail=false
= 不要用已部署容器的所有日志淹没你的控制台 - --kube-context "kind-${USER}"
= 目标是你上面使用 kind
创建的特定 Kubernetes 集群skaffold dev
监视你的本地文件,并在你更改这些文件时自动重新部署应用程序。它还会保持在你运行它的终端中的控制,并在你 Ctrl + C 退出时处理关闭 Kubernetes 中的 pods。
你应该看到类似于这样的输出
Generating tags...
- ...
Checking cache...
- ...
Tags used in deployment:
- ...
Starting deploy...
Loading images into kind cluster nodes...
- ...
Waiting for deployments to stabilize...
Deployments stabilized in 23.08 seconds
Watching for changes...
当你运行此命令时,skaffold dev
会在系统上找到一个随机的开放端口,并将 retriever-ingest 服务暴露在该端口上。有关更多信息,请参阅 端口转发。
你可以在 skaffold 的日志中找到该端口,方法是运行以下代码。
Port forwarding Service/nv-ingest in namespace , remote port http -> http://0.0.0.0:4503
或者,你可以像这样获取它
NV_INGEST_MS_PORT=$(
ps aux \
| grep -E "kind\-${USER} port-forward .*Service/nv-ingest" \
| grep -o -E '[0-9]+:http' \
| cut -d ':' -f1
)
要确认服务已部署并正常工作,请针对你上面设置端口转发的端口发出请求。
API_HOST="https://:${NV_INGEST_MS_PORT}"
curl \
-i \
-X GET \
"${API_HOST}/health"
当你在新终端中运行 skaffold verify
时,Skaffold 会针对该服务运行验证测试。这些是非常轻量级的健康检查,不应与集成测试混淆。有关更多信息,请参阅 验证。
清理
要销毁整个 Kubernetes 集群,请运行以下命令。
kind delete cluster \
--name "${USER}"
故障排除
调试工具
kubectl
是 Kubernetes 的官方 CLI,并支持许多有用的功能。
例如,要在你的部署中获取 nv-ingest-ms-runtime
容器内的 shell,请运行以下命令
NV_INGEST_POD=$(
kubectl get pods \
--context "kind-${USER}" \
--namespace default \
-l 'app.kubernetes.io/instance=nv-ingest-ms-runtime' \
--no-headers \
| awk '{print $1}'
)
kubectl exec \
--context "kind-${USER}" \
--namespace default \
pod/${NV_INGEST_POD} \
-i \
-t \
-- sh
为了获得交互式的、实时更新的体验,请尝试 k9s。要启动它,请运行 k9s
。
k9s
安装 Helm 仓库
你可能会遇到如下错误。这表明你的本地 Helm 安装(Kubernetes 配置的包管理器)不知道如何访问包含 Kubernetes 配置的远程仓库。
Error: no repository definition for https://helm.dask.org. Please add the missing repos via 'helm repo add'
要解决此问题,请使用 URL 和信息性名称运行 help repo add
。
helm repo add \
bitnami \
https://charts.bitnami.com/bitnami
从 Skaffold 获取更多日志
你可能会遇到如下错误
Generating tags...
- retrieval-ms -> retrieval-ms:f181a78-dirty
Checking cache...
- retrieval-ms: Found Locally
Cleaning up...
- No resources found
building helm dependencies: exit status 1
如果你只看到 building helm dependencies
,你可能在安静模式下运行了 skaffold dev
或 skaffold run
。使用 -v info
或 -v debug
重新运行命令以获取有关失败原因的更多信息。