一键部署 GPU Kind 集群,体验 vLLM 极速推理
随着 Kubernetes 在大模型训练和推理领域的广泛应用,越来越多的开发者需要在本地环境中搭建支持 GPU 的 Kubernetes 集群,以便进行测试和开发。大家都知道,本地搭建 Kubernetes 集群通常可以使用 Kind(Kubernetes IN Docker),它轻量、快速且易于使用。但是,如果要搭建一个可以使用 GPU 的 Kind 集群,就需要进行一些额外的工作。比如,需要安装 GPU 驱动、配置 NVIDIA Container Toolkit、设置 NVIDIA Container Runtime 等等。此外,如果你希望在多个 Kind 节点之间均匀分配 GPU 资源,模拟一个多节点的 Kind GPU 集群,传统的 Kind 配置可能无法满足需求。
在这篇博客中,我们将介绍如何使用一键脚本快速搭建一个支持 GPU 的 Kind 集群。通过 nvkind,我们可以轻松地将 GPU 资源均匀分配到不同的 Kind 节点,从而模拟一个多节点的 Kind GPU 集群。
最后我们还会在 Kind 集群中部署一个 vLLM 大模型,来验证 Kind GPU 集群是否正常工作。
前提条件
完整的脚本可以在这里找到:https://github.com/cr7258/hands-on-lab/tree/main/ai/gpu/setup ,该脚本基于 Ubuntu 操作系统编写。
- 具有 NVIDIA GPU 的机器
- 管理员权限(sudo 访问权限)
- 稳定的互联网连接
如果你在本地没有 GPU 服务器,也可以考虑在云服务提供商购买,比如阿里云、AWS、Azure 等。我个人觉得在阿里云上购买 GPU 实例的价格相对更实惠,不同地域的价格也有所差异,例如美国区域通常会更便宜一些。如果选择抢占式实例,价格还能进一步降低,非常适合用于开发测试等对稳定性要求不高的场景。
此外,阿里云的 ECS 实例在不使用时可以开启“节省停机”功能,这样可以保留磁盘数据,方便下次继续使用,同时还能节省 CPU、内存、GPU 等计算资源的费用。考虑到大模型通常占用较大的存储空间,建议在创建实例时将存储空间配置得稍微大一些,比如 100GB,以避免频繁扩容带来的麻烦。
执行脚本
只需执行以下命令,脚本会自动完成所有准备工作并创建一个支持 GPU 的 Kind 集群。
bash install.sh
脚本详解
接下来分别介绍脚本中的各个部分。
安装命令行工具
首先安装一些必要的命令行工具,包括 Docker、kubectl、Helm、Kind 和 nvkind。
sudo apt update
sudo apt install -y docker.io
sudo snap install kubectl --classic
# Add kubectl completion to bashrc
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source ~/.bashrc
sudo snap install helm --classic# Install kind
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.25.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind# Install nvkind
curl -L -o ~/nvkind-linux-amd64.tar.gz https://github.com/Jeffwan/kind-with-gpus-examples/releases/download/v0.1.0/nvkind-linux-amd64.tar.gz
tar -xzvf ~/nvkind-linux-amd64.tar.gz
mv nvkind-linux-amd64 /usr/local/bin/nvkind
安装 NVIDIA GPU 驱动程序
为了使用 GPU,我们需要安装 NVIDIA 驱动程序,这里使用的是 NVIDIA 驱动程序版本是 565.57.01。
wget https://cn.download.nvidia.com/tesla/565.57.01/NVIDIA-Linux-x86_64-565.57.01.run
sh NVIDIA-Linux-x86_64-565.57.01.run --silent
安装和配置 NVIDIA Container Toolkit
NVIDIA Container Toolkit 的主要作用是将 NVIDIA GPU 设备挂载到容器中。
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.listsed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
然后配置 NVIDIA Container Runtime:
- 第一条命令用于确保 Docker 已正确配置以配合 NVIDIA Toolkit 使用,并将
nvidia
runtime 设置为默认值。 - 第二条命令启用了 Toolkit 的一个功能标志,借助这一特性,我们可以将 GPU 支持注入到每个 Kind 的 worker 节点中。
sudo nvidia-ctk runtime configure --runtime=docker --set-as-default --cdi.enabled
sudo nvidia-ctk config --set accept-nvidia-visible-devices-as-volume-mounts=true --in-place
sudo systemctl restart docker
验证 GPU 可用性
通过多种方式验证 GPU 是否可用:
- 运行
nvidia-smi
以检查 GPU 是否可用。 - 使用 NVIDIA runtime 运行一个 Docker 容器,验证是否能识别 GPU。
- 确保容器内能够访问 GPU 设备。
# Run nvidia-smi to list GPU devices
nvidia-smi -L
if [ $? -ne 0 ]; thenecho "nvidia-smi failed to execute."exit 1
fi# Run a Docker container with NVIDIA runtime to list GPU devices
docker run --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all ubuntu:20.04 nvidia-smi -L
if [ $? -ne 0 ]; thenecho "Docker command with NVIDIA runtime failed to execute."exit 1
fi# Run a Docker container with mounted /dev/null to check GPU accessibility
docker run -v /dev/null:/var/run/nvidia-container-devices/all ubuntu:20.04 nvidia-smi -L
if [ $? -ne 0 ]; thenecho "Docker command with mounted /dev/null failed to execute."exit 1
fi
创建 Kind GPU 集群
首先生成一个 nvkind 配置文件,根据服务器上的 GPU 数量创建对应数量的 worker 节点,然后执行 nvkind 命令创建支持 GPU 的 Kind 集群。
cat << 'EOF' > one-worker-per-gpu.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
{{- range $gpu := until numGPUs }}
- role: workerextraMounts:# 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/nullcontainerPath: /var/run/nvidia-container-devices/{{ $gpu }}
{{- end }}
EOFnvkind cluster create --name gpu-cluster --config-template=one-worker-per-gpu.yaml
安装 GPU Operator
GPU Operator 是 NVIDIA 提供的一个 Kubernetes Operator,它简化了在 Kubernetes 集群中使用 GPU 的过程,通过自动化的方式处理 GPU 驱动程序安装、NVIDIA Device Plugin、DCGM Exporter 等组件。
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install --wait --generate-name \-n gpu-operator --create-namespace \nvidia/gpu-operator \# 我们之前已经安装了 NVIDIA 驱动程序,所以在 GPU Operator 中禁用驱动安装--set driver.enabled=false
安装 Cloud Provider Kind
最后脚本安装了 Cloud Provider Kind,允许以 LoadBalancer 的模式暴露服务,方便从 Kind 集群外部进行访问。
curl -L ${KIND_CLOUD_PROVIDER_URL} -o cloud-provider-kind.tar.gz
tar -xvzf cloud-provider-kind.tar.gz
chmod +x cloud-provider-kind
sudo mv cloud-provider-kind /usr/local/bin/# Run cloud-provider-kind in the background and forward logs
echo "Starting cloud-provider-kind in the background..."
LOG_FILE="/tmp/cloud-provider-kind.log"nohup cloud-provider-kind > ${LOG_FILE} 2>&1 &# Save the process ID
echo $! > /tmp/cloud-provider-kind.pid
echo "Cloud Provider Kind is running in the background. Logs are being written to ${LOG_FILE}."echo "Setup complete. All components have been installed successfully."
通过 vLLM 运行大模型
接下来我们通过 vLLM 来运行 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
模型来测试 Kind GPU 集群是否正常工作。vLLM 是一个快速且易于使用的库,用于 LLM 推理和服务,可以和 HuggingFace 无缝集成。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: deepseek-r1-distill-qwen-1-5bnamespace: default
spec:accessModes:- ReadWriteOnceresources:requests:storage: 20GivolumeMode: Filesystem
---
apiVersion: apps/v1
kind: Deployment
metadata:name: deepseek-r1-distill-qwen-1-5bnamespace: defaultlabels:app: deepseek-r1-distill-qwen-1-5b
spec:replicas: 1selector:matchLabels:app: deepseek-r1-distill-qwen-1-5btemplate:metadata:labels:app: deepseek-r1-distill-qwen-1-5bspec:volumes:- name: cache-volumepersistentVolumeClaim:claimName: deepseek-r1-distill-qwen-1-5bcontainers:- name: deepseek-r1-distill-qwen-1-5bimage: vllm/vllm-openai:latestcommand: ["/bin/sh", "-c"]args: ["vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --trust-remote-code --enable-chunked-prefill --max_num_batched_tokens 1024"]ports:- containerPort: 8000resources:limits:nvidia.com/gpu: "1"requests:nvidia.com/gpu: "1"readinessProbe:httpGet:path: /healthport: 8000initialDelaySeconds: 60periodSeconds: 5volumeMounts:- mountPath: /root/.cache/huggingfacename: cache-volume
---
apiVersion: v1
kind: Service
metadata:name: deepseek-r1-distill-qwen-1-5bnamespace: default
spec:ports:- name: deepseek-r1-distill-qwen-1-5bport: 80protocol: TCPtargetPort: 8000selector:app: deepseek-r1-distill-qwen-1-5btype: LoadBalancer
vllm/vllm-openai:latest 的镜像大概有 8GB,需要一些时间来下载,另外 vLLM 启动以后还需要去 HuggingFace 下载模型权重。首次启动 Pod 时,下载模型权重花费了 508 秒。由于模型权重被缓存在 PVC 中,并挂载到 /root/.cache/huggingface
目录,后续 Pod 重启时将无需重新下载权重,能够显著加快启动速度。
> kubectl logs deepseek-r1-distill-qwen-1-5b-66dc67d4dc-86b2v -f
INFO 03-22 12:14:52 [__init__.py:256] Automatically detected platform cuda.
INFO 03-22 12:14:56 [api_server.py:977] vLLM API server version 0.8.1
INFO 03-22 12:14:56 [api_server.py:978] args: Namespace(subparser='serve', model_tag='deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B', config='', host=None, port=8000, uvicorn_log_level='info', allow_credentials=False, allowed_origins=['*'], allowed_methods=['*'], allowed_headers=['*'], api_key=None, lora_modules=None, prompt_adapters=None, chat_template=None, chat_template_content_format='auto', response_role='assistant', ssl_keyfile=None, ssl_certfile=None, ssl_ca_certs=None, enable_ssl_refresh=False, ssl_cert_reqs=0, root_path=None, middleware=[], return_tokens_as_token_ids=False, disable_frontend_multiprocessing=False, enable_request_id_headers=False, enable_auto_tool_choice=False, tool_call_parser=None, tool_parser_plugin='', model='deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B', task='auto', tokenizer=None, hf_config_path=None, skip_tokenizer_init=False, revision=None, code_revision=None, tokenizer_revision=None, tokenizer_mode='auto', trust_remote_code=True, allowed_local_media_path=None, download_dir=None, load_format='auto', config_format=<ConfigFormat.AUTO: 'auto'>, dtype='auto', kv_cache_dtype='auto', max_model_len=None, guided_decoding_backend='xgrammar', logits_processor_pattern=None, model_impl='auto', distributed_executor_backend=None, pipeline_parallel_size=1, tensor_parallel_size=1, enable_expert_parallel=False, max_parallel_loading_workers=None, ray_workers_use_nsight=False, block_size=None, enable_prefix_caching=None, disable_sliding_window=False, use_v2_block_manager=True, num_lookahead_slots=0, seed=None, swap_space=4, cpu_offload_gb=0, gpu_memory_utilization=0.9, num_gpu_blocks_override=None, max_num_batched_tokens=1024, max_num_partial_prefills=1, max_long_partial_prefills=1, long_prefill_token_threshold=0, max_num_seqs=None, max_logprobs=20, disable_log_stats=False, quantization=None, rope_scaling=None, rope_theta=None, hf_overrides=None, enforce_eager=False, max_seq_len_to_capture=8192, disable_custom_all_reduce=False, tokenizer_pool_size=0, tokenizer_pool_type='ray', tokenizer_pool_extra_config=None, limit_mm_per_prompt=None, mm_processor_kwargs=None, disable_mm_preprocessor_cache=False, enable_lora=False, enable_lora_bias=False, max_loras=1, max_lora_rank=16, lora_extra_vocab_size=256, lora_dtype='auto', long_lora_scaling_factors=None, max_cpu_loras=None, fully_sharded_loras=False, enable_prompt_adapter=False, max_prompt_adapters=1, max_prompt_adapter_token=0, device='auto', num_scheduler_steps=1, use_tqdm_on_load=True, multi_step_stream_outputs=True, scheduler_delay_factor=0.0, enable_chunked_prefill=True, speculative_model=None, speculative_model_quantization=None, num_speculative_tokens=None, speculative_disable_mqa_scorer=False, speculative_draft_tensor_parallel_size=None, speculative_max_model_len=None, speculative_disable_by_batch_size=None, ngram_prompt_lookup_max=None, ngram_prompt_lookup_min=None, spec_decoding_acceptance_method='rejection_sampler', typical_acceptance_sampler_posterior_threshold=None, typical_acceptance_sampler_posterior_alpha=None, disable_logprobs_during_spec_decoding=None, model_loader_extra_config=None, ignore_patterns=[], preemption_mode=None, served_model_name=None, qlora_adapter_name_or_path=None, show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, disable_async_output_proc=False, scheduling_policy='fcfs', scheduler_cls='vllm.core.scheduler.Scheduler', override_neuron_config=None, override_pooler_config=None, compilation_config=None, kv_transfer_config=None, worker_cls='auto', worker_extension_cls='', generation_config='auto', override_generation_config=None, enable_sleep_mode=False, calculate_kv_scales=False, additional_config=None, enable_reasoning=False, reasoning_parser=None, disable_log_requests=False, max_log_len=None, disable_fastapi_docs=False, enable_prompt_tokens_details=False, enable_server_load_tracking=False, dispatch_function=<function ServeSubcommand.cmd at 0x701e1ce19a80>)
INFO 03-22 12:15:09 [config.py:583] This model supports multiple tasks: {'score', 'embed', 'reward', 'generate', 'classify'}. Defaulting to 'generate'.
INFO 03-22 12:15:09 [config.py:1693] Chunked prefill is enabled with max_num_batched_tokens=1024.
INFO 03-22 12:15:16 [__init__.py:256] Automatically detected platform cuda.
INFO 03-22 12:15:18 [core.py:53] Initializing a V1 LLM engine (v0.8.1) with config: model='deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B', speculative_config=None, tokenizer='deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, override_neuron_config=None, tokenizer_revision=None, trust_remote_code=True, dtype=torch.bfloat16, max_seq_len=131072, download_dir=None, load_format=LoadFormat.AUTO, tensor_parallel_size=1, pipeline_parallel_size=1, disable_custom_all_reduce=False, quantization=None, enforce_eager=False, kv_cache_dtype=auto, device_config=cuda, decoding_config=DecodingConfig(guided_decoding_backend='xgrammar', reasoning_backend=None), observability_config=ObservabilityConfig(show_hidden_metrics=False, otlp_traces_endpoint=None, collect_model_forward_time=False, collect_model_execute_time=False), seed=None, served_model_name=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B, num_scheduler_steps=1, multi_step_stream_outputs=True, enable_prefix_caching=True, chunked_prefill_enabled=True, use_async_output_proc=True, disable_mm_preprocessor_cache=False, mm_processor_kwargs=None, pooler_config=None, compilation_config={"level":3,"custom_ops":["none"],"splitting_ops":["vllm.unified_attention","vllm.unified_attention_with_output"],"use_inductor":true,"compile_sizes":[],"use_cudagraph":true,"cudagraph_num_of_warmups":1,"cudagraph_capture_sizes":[512,504,496,488,480,472,464,456,448,440,432,424,416,408,400,392,384,376,368,360,352,344,336,328,320,312,304,296,288,280,272,264,256,248,240,232,224,216,208,200,192,184,176,168,160,152,144,136,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,4,2,1],"max_capture_size":512}
WARNING 03-22 12:15:20 [utils.py:2282] Methods determine_num_available_blocks,device_config,get_cache_block_size_bytes,initialize_cache not implemented in <vllm.v1.worker.gpu_worker.Worker object at 0x741a9f769130>
INFO 03-22 12:15:20 [parallel_state.py:967] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, TP rank 0
INFO 03-22 12:15:20 [cuda.py:215] Using Flash Attention backend on V1 engine.
INFO 03-22 12:15:20 [gpu_model_runner.py:1164] Starting to load model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B...
INFO 03-22 12:15:21 [topk_topp_sampler.py:53] Using FlashInfer for top-p & top-k sampling.
INFO 03-22 12:15:21 [weight_utils.py:257] Using model weights format ['*.safetensors']# 下载模型权重花费 508 秒
INFO 03-22 12:23:49 [weight_utils.py:273] Time spent downloading weights for deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B: 508.576789 seconds
INFO 03-22 12:23:49 [weight_utils.py:307] No model.safetensors.index.json found in remote.
Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00<?, ?it/s]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:00<00:00, 2.02it/s]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:00<00:00, 2.02it/s]INFO 03-22 12:23:50 [loader.py:429] Loading weights took 0.56 seconds
INFO 03-22 12:23:50 [gpu_model_runner.py:1176] Model loading took 3.3465 GB and 509.679959 seconds
INFO 03-22 12:23:56 [backends.py:409] Using cache directory: /root/.cache/vllm/torch_compile_cache/b4fe10a8ad/rank_0_0 for vLLM's torch.compile
INFO 03-22 12:23:56 [backends.py:419] Dynamo bytecode transform time: 6.04 s
INFO 03-22 12:23:59 [backends.py:132] Cache the graph of shape None for later use
INFO 03-22 12:24:19 [backends.py:144] Compiling a graph for general shape takes 22.07 s
INFO 03-22 12:24:27 [monitor.py:33] torch.compile takes 28.11 s in total
INFO 03-22 12:24:28 [kv_cache_utils.py:537] GPU KV cache size: 525,520 tokens
INFO 03-22 12:24:28 [kv_cache_utils.py:540] Maximum concurrency for 131,072 tokens per request: 4.01x
INFO 03-22 12:24:49 [gpu_model_runner.py:1499] Graph capturing finished in 21 secs, took 0.45 GiB
INFO 03-22 12:24:50 [core.py:138] init engine (profile, create kv cache, warmup model) took 59.57 seconds
INFO 03-22 12:24:50 [serving_chat.py:115] Using default chat sampling params from model: {'temperature': 0.6, 'top_p': 0.95}
INFO 03-22 12:24:50 [serving_completion.py:61] Using default completion sampling params from model: {'temperature': 0.6, 'top_p': 0.95}
INFO 03-22 12:24:50 [api_server.py:1024] Starting vLLM API server on http://0.0.0.0:8000
INFO 03-22 12:24:50 [launcher.py:26] Available routes are:
INFO 03-22 12:24:50 [launcher.py:34] Route: /openapi.json, Methods: GET, HEAD
INFO 03-22 12:24:50 [launcher.py:34] Route: /docs, Methods: GET, HEAD
INFO 03-22 12:24:50 [launcher.py:34] Route: /docs/oauth2-redirect, Methods: GET, HEAD
INFO 03-22 12:24:50 [launcher.py:34] Route: /redoc, Methods: GET, HEAD
INFO 03-22 12:24:50 [launcher.py:34] Route: /health, Methods: GET
INFO 03-22 12:24:50 [launcher.py:34] Route: /load, Methods: GET
INFO 03-22 12:24:50 [launcher.py:34] Route: /ping, Methods: GET, POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /tokenize, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /detokenize, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/models, Methods: GET
INFO 03-22 12:24:50 [launcher.py:34] Route: /version, Methods: GET
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/chat/completions, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/completions, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/embeddings, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /pooling, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /score, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/score, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/audio/transcriptions, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /rerank, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v1/rerank, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /v2/rerank, Methods: POST
INFO 03-22 12:24:50 [launcher.py:34] Route: /invocations, Methods: POST
INFO: Started server process [7]
INFO: Waiting for application startup.
INFO: Application startup complete.
确认 Pod 状态已经 Ready。
> kubectl get pod
NAME READY STATUS RESTARTS AGE
deepseek-r1-distill-qwen-1-5b-66dc67d4dc-86b2v 1/1 Running 0 26m> kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
deepseek-r1-distill-qwen-1-5b LoadBalancer 10.96.11.243 172.18.0.4 80:31629/TCP 26m
通过 LoadBalancer 暴露的 EXTERNAL-IP 来访问大模型。
curl --location 'http://172.18.0.4/v1/chat/completions' \
--header 'Content-Type: application/json' \
--data '{"model":"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B","messages": [{"role": "user","content": "你是谁?"}]
}'
响应结果如下,可以看到大模型成功处理了我们的请求。
{"id": "chatcmpl-06fde7b60b5642b5a2100b6146d351fa","object": "chat.completion","created": 1742646615,"model": "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B","choices": [{"index": 0,"message": {"role": "assistant","reasoning_content": null,"content": "我是DeepSeek-R1,一个由深度求索公司开发的智能助手,我擅长通过思考来帮您解答复杂的数学,代码和逻辑推理等理工类问题。\n</think>\n\n我是DeepSeek-R1,一个由深度求索公司开发的智能助手,我擅长通过思考来帮您解答复杂的数学,代码和逻辑推理等理工类问题。","tool_calls": []},"logprobs": null,"finish_reason": "stop","stop_reason": null}],"usage": {"prompt_tokens": 8,"total_tokens": 85,"completion_tokens": 77,"prompt_tokens_details": null},"prompt_logprobs": null
}
如果我们重启 Pod,这次会发现加载模型权重仅用了 0.55 秒,说明模型权重已经缓存起来了。
INFO 03-22 12:51:31 [weight_utils.py:257] Using model weights format ['*.safetensors']
INFO 03-22 12:51:31 [weight_utils.py:307] No model.safetensors.index.json found in remote.
Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00<?, ?it/s]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:00<00:00, 2.06it/s]
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:00<00:00, 2.06it/s]INFO 03-22 12:51:31 [loader.py:429] Loading weights took 0.55 seconds
INFO 03-22 12:51:31 [gpu_model_runner.py:1176] Model loading took 3.3465 GB and 0.912167 seconds
INFO 03-22 12:51:37 [backends.py:409] Using cache directory: /root/.cache/vllm/torch_compile_cache/b4fe10a8ad/rank_0_0 for vLLM's torch.compile
INFO 03-22 12:51:37 [backends.py:419] Dynamo bytecode transform time: 5.92 s
INFO 03-22 12:51:40 [backends.py:132] Cache the graph of shape None for later use
INFO 03-22 12:52:00 [backends.py:144] Compiling a graph for general shape takes 22.21 s
INFO 03-22 12:52:09 [monitor.py:33] torch.compile takes 28.13 s in total
INFO 03-22 12:52:10 [kv_cache_utils.py:537] GPU KV cache size: 525,520 tokens
INFO 03-22 12:52:10 [kv_cache_utils.py:540] Maximum concurrency for 131,072 tokens per request: 4.01x
INFO 03-22 12:52:31 [gpu_model_runner.py:1499] Graph capturing finished in 21 secs, took 0.45 GiB
INFO 03-22 12:52:31 [core.py:138] init engine (profile, create kv cache, warmup model) took 59.32 seconds
INFO 03-22 12:52:31 [serving_chat.py:115] Using default chat sampling params from model: {'temperature': 0.6, 'top_p': 0.95}
INFO 03-22 12:52:31 [serving_completion.py:61] Using default completion sampling params from model: {'temperature': 0.6, 'top_p': 0.95}
INFO 03-22 12:52:31 [api_server.py:1024] Starting vLLM API server on http://0.0.0.0:8000
清理
完成测试后,如果你想删除集群,可以执行以下命令:
bash cleanup.sh
总结
本文介绍了如何通过一键脚本在本地快速搭建支持 GPU 的 Kind 集群,适用于大模型的开发与测试场景。利用 nvkind 工具,可以轻松实现多节点 GPU 资源分配,并结合 vLLM 成功部署了 deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
模型。
欢迎关注
相关文章:
一键部署 GPU Kind 集群,体验 vLLM 极速推理
随着 Kubernetes 在大模型训练和推理领域的广泛应用,越来越多的开发者需要在本地环境中搭建支持 GPU 的 Kubernetes 集群,以便进行测试和开发。大家都知道,本地搭建 Kubernetes 集群通常可以使用 Kind(Kubernetes IN Docker&#…...
C/C++蓝桥杯算法真题打卡(Day6)
一、P8615 [蓝桥杯 2014 国 C] 拼接平方数 - 洛谷 方法一:算法代码(字符串分割法) #include<bits/stdc.h> // 包含标准库中的所有头文件,方便编程 using namespace std; // 使用标准命名空间,避免每次调用…...
【C++】入门
1.命名空间 1.1 namespace的价值 在C/C中,变量,函数和后面要学到的类都是大量存在的,这些变量,函数和类的名称将存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,…...
CUDA 学习(2)——CUDA 介绍
GeForce 256 是英伟达 1999 年开发的第一个 GPU,最初用作显示器上渲染高端图形,只用于像素计算。 在早期,OpenGL 和 DirectX 等图形 API 是与 GPU 唯一的交互方式。后来,人们意识到 GPU 除了用于渲染图形图像外,还可以…...
构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据
构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据 概述 本文将指导开发者构建一个MCP(Model Control Protocol)天气服务器,通过暴露get-alerts和get-forecast工具,为Claude for Desktop等客户端提供实时天气数据支持。该方案解决了传统LLM无法直接获取天气…...
[Lc_2 二叉树dfs] 布尔二叉树的值 | 根节点到叶节点数字之和 | 二叉树剪枝
目录 1.计算布尔二叉树的值 题解 2.求根节点到叶节点数字之和 3. 二叉树剪枝 题解 1.计算布尔二叉树的值 链接:2331. 计算布尔二叉树的值 给你一棵 完整二叉树 的根,这棵树有以下特征: 叶子节点 要么值为 0 要么值为 1 ,其…...
搜广推校招面经五十六
字节推荐算法 一、Attention的复杂度是多少? 见【搜广推校招面经三十八】 二、如何对普适性强的物品(如新华字典)设计指标进行降权 2.1. 问题背景 普适性强的物品(如新华字典)在推荐系统或搜索排序中可能频繁出现…...
ZYNQ的cache原理与一致性操作
在Xilinx Zynq SoC中,Cache管理是确保处理器与外部设备(如FPGA逻辑、DMA控制器)之间数据一致性的关键。Zynq的ARM Cortex-A9处理器包含L1 Cache(指令/数据)和L2 Cache,其刷新(Flush/Invalidate&…...
安装React开发者工具
我们在说组件之前,需要先安装一下React官方推出的开发者工具,首先我们分享在线安装方式 首先打开谷歌网上应用商店(针对谷歌浏览器),在输入框内搜索react,安装如下插件: 注意安装提供方为Facebook的插件,这…...
多层感知机
多层感知机(Multilayer Perceptron,简称 MLP)是一种基于前馈神经网络(Feedforward Neural Network)的深度学习模型,由多个神经元层组成,每一层与前一层全连接。它包括至少一个隐藏层(…...
2025年渗透测试面试题总结- PingCAP安全工程师(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 PingCAP安全工程师 一、SQL注入判断数据库类型技术分析 1. 常规判断方法 2. 盲注场景下的判断 3. 补…...
CAD模型导入Geant4
CADMesh是一个开源项目,专门用于将STL格式的CAD模型导入Geant4。以下是使用CADMesh操作STL模型的步骤: 准备工作 下载CADMesh开源代码:可以从GitHub或Gitee下载CADMesh的开源代码。 将CAD模型转换为STL格式:在CAD软件中创建几何…...
DeepSORT 目标追踪算法详解
DeepSORT(Deep Simple Online and Realtime Tracking)是 多目标追踪(MOT) 领域的经典算法,通过结合目标检测、运动预测和外观特征匹配,实现了高效、稳定的实时追踪。其核心思想是通过 检测驱动追踪…...
mne溯源后的数据初步处理方法
文章目录 导入库 Yeo2011_7Networks_N1000绘制一些圆球来代表区域大小和强度 单网络绘制和扩展的方式AI补充一下背景知识📚 **背景与研究来源**🧠 **7 个功能网络的定义**📂 **标签数据获取**🔍 **标签文件内容解析**🛠…...
基于STM32进行FFT滤波并计算插值DA输出
文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话五、项目联想与扩展1. 倍频2. 降频3. 插值3.1 线性插值3.2 样条插值 一、前言背景 STM32 对 AD 采样信号进行快…...
【用 Trace读源码】PlanAgent 执行流程
前提条件 在 Trae 中打开 OpenManus 工程,使用 build 模式,模型选择 claude-sonnet-3.7 提示词 分析 agent/planning.py 中 main 方法及相关类的执行流程,以流程图的方式展示PlanningAgent 执行流程图 以下流程图展示了 PlanningAgent 类…...
AI代码编辑器:Cursor和Trae
Cursor 定义:Cursor 是一款基于AI的代码编辑器,它继承了VS Code的核心功能,并在此基础上增加了深度AI支持。它支持代码生成、优化、重构以及调试等功能,提供直观的Diff视图和自动补全功能,是一款功能强大的编程工具。…...
LSM-Tree(Log-Structured Merge-Tree)详解
1. 什么是 LSM-Tree? LSM-Tree(Log-Structured Merge-Tree)是一种 针对写优化的存储结构,广泛用于 NoSQL 数据库(如 LevelDB、RocksDB、HBase、Cassandra)等系统。 它的核心思想是: 写入时只追加写(Append-Only),将数据先写入内存缓冲区(MemTable)。内存数据满后…...
介绍一个测试boostrap表格插件的好网站!
最近在开发一个物业管理系统。用到bootstrap的表格插件bootstrap table,官方地址: https://bootstrap-table.com/ 因为是英文界面,对国人不是很友好。后来发现了IT小书童网站 IT小书童 - 为程序员提供优质教程和文档 网站: IT…...
虚拟路由与单页应用(SPA):详解
在单页应用(SPA,Single Page Application)中,虚拟路由(也称为前端路由)是一种关键的技术,用于管理页面导航和状态变化,而无需重新加载整个页面。为了帮助你更好地理解这一概念&#…...
基于树莓派3B+的人脸识别实践:Python与C联合开发
基于树莓派3B的人脸识别实践:Python与C联合开发 引言 树莓派因其小巧的体积和丰富的扩展性,成为嵌入式开发的理想平台。本文将分享如何通过Python与C语言联合开发,在树莓派3B上实现从硬件控制、摄像头拍照到百度API人脸比对的完整流程。项目…...
尝试使用Tauri2+Django+React项目(2)
前言 尝试使用tauri2DjangoReact的项目-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146403103在前面笔者不知道怎么做,搞了半天 笔者看到官网,原来可以使用二进制文件,好好好 嵌入外部二进制文件 | Taurihttps://v2.taur…...
Qt桌面客户端跨平台开发实例
在Windows平台上,桌面客户端软件通常使用C/C语言和Qt跨平台开发框架进行开发。因此,大部分代码可以运行于不同平台环境,但是程序运行依赖的三方库以及代码中一些平台相关的头文件和接口需要进行平台兼容。本文以windows桌面端应用迁移到Linux…...
c++进阶之------红黑树
一、概念 红黑树(Red-Black Tree)是一种自平衡二叉查找树,它在计算机科学的许多领域中都有广泛应用,比如Java中的TreeMap和C中的set/map等数据结构的底层实现。红黑树通过在每个节点上增加一个颜色属性(红色或黑色&am…...
政安晨【超级AI工作流】—— 使用Dify通过工作流对接ComfyUI实现多工作流协同
政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! 目录 一、准备工作 Dify跑起来 ollama局域网化配置 Dify配置并验证 启动ComfyUI 二、…...
javaweb开发以及部署
先说一个阿里云学生无门槛免费领一年2核4g服务器的方法: 阿里云服务器学生无门槛免费领一年2核4g_阿里云学生认证免费服务器-CSDN博客 Java Web开发是使用Java编程语言开发Web应用程序的过程,通常涵盖了使用Java EE(Java Enterprise Edition…...
树莓派5介绍与系统安装
简介 Raspberry Pi 5采用运行频率为2.4GHz的64位四核Arm Cortex-A76处理器,与Raspberry Pi 4相比, CPU性能提高了2至3倍。此外,它还配备了一个800MHz的VideoCore VII GPU,可以提供大幅度的图形 性能提升,通过HDMI实现…...
菜鸟之路Day25一一前端工程化(二)
菜鸟之路Day25一一前端工程化(二) 作者:blue 时间:2025.3.19 文章目录 菜鸟之路Day25一一前端工程化(二)1.概述2.Element快速入门3.综合案例一.布局二.组件三.Axios异步加载数据1. 生命周期钩子概述2. mo…...
vue如何获取 sessionStorage的值,获取token
// 使用Axios发送请求并处理下载 import axios from axios;const handleDownload () > {const params {warehouseId: selectedWarehouseId.value};const apiUrl /api/materials/wmMatCheck/export-wmMatCheckDetail;axios.get(apiUrl, {params,responseType: blob, // 接…...
图解AUTOSAR_CP_DiagnosticLogAndTrace
AUTOSAR 诊断日志和跟踪(DLT)模块详解 AUTOSAR 经典平台中的诊断和调试关键组件 目录 1. 概述2. DLT模块架构 2.1 模块位置2.2 内部组件2.3 接口定义 3. DLT操作流程 3.1 初始化流程3.2 日志和跟踪消息处理3.3 控制命令处理 4. 数据结构与配置模型 4.1 配置类4.2 消息格式4.3 …...
微调实战 - 使用 Unsloth 微调 QwQ 32B 4bit (单卡4090)
本文参考视频教程:赋范课堂 – 只需20G显存,QwQ-32B高效微调实战!4大微调工具精讲!知识灌注问答风格微调,DeepSeek R1类推理模型微调Cot数据集创建实战打造定制大模型! https://www.bilibili.com/video/BV1…...
金仓KESV8R6任务调度
基本概念 • 程序(program) 程序对象描述调度器要运行的内容。 • 调度计划(schedule) 调度计划对象指定作业何时运行以及运行多少次。调度计划可以被多个作业共享。 • 作业(job) 作业就是用户定义的…...
Maven常见问题汇总
Maven刷新,本地仓库无法更新 现象 This failure was cached in the local repository and resolution is not reattempted until the update interval of aliyunmaven has elapsed or updates are forced原因 因为上一次尝试下载,发现对应的仓库没有这个maven配置…...
颠覆者的困局:解构周鸿祎商业哲学中的“永恒战争”
引言:被误解的破坏者 在北京海淀区知春路银谷大厦的某间会议室里,周鸿祎用马克笔在白板上画出一个巨大的爆炸图案——这是2010年360与腾讯开战前夜的战术推演场景。这个充满硝烟味的瞬间,恰是《颠覆者》精神内核的完美隐喻:在中国…...
基于ChatGPT、GIS与Python机器学习的地质灾害风险评估、易发性分析、信息化建库及灾后重建高级实践
第一章、ChatGPT、DeepSeek大语言模型提示词与地质灾害基础及平台介绍【基础实践篇】 1、什么是大模型? 大模型(Large Language Model, LLM)是一种基于深度学习技术的大规模自然语言处理模型。 代表性大模型:GPT-4、BERT、T5、Ch…...
如何实现单点登录?
单点登录(Single Sign-On, SSO)是一种身份验证机制,允许用户在多个应用系统中只登录一次,就能够访问所有受保护的系统或服务,而无需重复登录。SSO通过集中式认证来简化用户的登录体验,提高安全性,并减少管理复杂性。 一、原理 SSO的核心原理是通过一个认证中心(Ident…...
01 Overview
版本pytorch 0.4,应用期的技术 学习的前提 线性代数和概率分布,高数 内容 穷举、贪心、分治算法、动态规划 花书是经典中的经典 机器学习历史 1 基于规则的 2 经典的机器学习方法 3 深度学习 深度学习竞赛识别率超过了人类 神经网络是数学和工…...
第二天 开始Unity Shader的学习之旅之熟悉顶点着色器和片元着色器
Shader初学者的学习笔记 第二天 开始Unity Shader的学习之旅之熟悉顶点着色器和片元着色器 文章目录 Shader初学者的学习笔记前言一、顶点/片元着色器的基本结构① Shader "Unity Shaders Book/Chapter 5/ Simple Shader"② SubShader③ CGPROGRAM和ENDCG④ 指明顶点…...
moveit2基础教程上手-使用xarm6演示
0、前置信息 开发环境:wsl。 ros版本:jazzy,ubuntu版本:24.04 xarm-ros2地址 1、启动Rviz,加载 Motion Planning Plugin,实现演示功能 Getting Started — MoveIt Documentation: Rolling documentation…...
头部姿态估计(Head Pose Estimation)领域,有许多开源工具和库可供选择,一些常用的工具及其特点
在头部姿态估计(Head Pose Estimation)领域,有许多开源工具和库可供选择。以下是一些常用的工具及其特点比较: 1. OpenCV 特点: OpenCV 是一个广泛使用的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。虽然 O…...
Qt调用Miniconda的python方法
1、 Win 64环境下载及安装 Miniconda 首先下载Windows 版Miniconda,https://docs.conda.io/en/latest/miniconda.html或 https://repo.anaconda.com/miniconda/ 安装界面及选择如下图所示: 安装完python3.12版报错如下。 说明:python3.11版…...
【Linux 下的 bash 无法正常解析, Windows 的 CRLF 换行符问题导致的】
文章目录 报错原因:解决办法:方法一:用 dos2unix 修复方法二:手动转换换行符方法三:VSCode 或其他编辑器手动改 总结 这个错误很常见,原因是你的 wait_for_gpu.sh 脚本 文件格式不对,具体来说…...
DSP数字信号处理
数字信号处理(Digital Signal Processing,简称DSP)是一门研究如何通过数字技术对信号进行分析、修改和合成的学科。DSP在现代电子系统中无处不在,广泛应用于音频处理、视频处理、通信、雷达、医学成像等领域。 什么是数字信号处理…...
vue3 获取当前路由信息失败问题
刷新浏览器时获取当前路由信息失败:undefined import { ref, reactive, onMounted } from vue; import { useRoute } from vue-router; const route useRoute();onMounted(()>{// 打印当前路由信息console.log(当前route, route ); // 这里的打印有值console.…...
数据驱动进化:AI Agent如何重构手机交互范式?
如果说AIGC拉开了内容生成的序幕,那么AI Agent则标志着AI从“工具”向“助手”的跨越式进化。它不再是简单的问答机器,而是一个能够感知环境、规划任务并自主执行的智能体,更像是虚拟世界中的“全能员工”。 正如行业所热议的:“大…...
汽车芯片成本控制:挑战、策略与未来趋势
一、引言 随着汽车行业的快速发展,汽车芯片在车辆中的应用越来越广泛。从简单的发动机控制单元到复杂的自动驾驶系统,芯片已成为汽车智能化、电动化的核心部件。然而,汽车芯片的高成本一直是制约汽车行业发展的重要因素之一。本文将深入探讨…...
RIP实验
RIP实验 一、实验背景 RIP协议: RIP协议(Routing Information Protocol,路由信息协议)是一种基于距离矢量的内部网关协议,即根据跳数来度量路由开销,进行路由选择。相比于其它路由协议(如OSPF、…...
NAT 实验:多私网环境下 NAPT、Easy IP 配置及 FTP 服务公网映射
NAT基本概念 定义:网络地址转换(Network Address Translation,NAT)是一种将私有(保留)地址转化为合法公网 IP 地址的转换技术,它被广泛应用于各种类型 Internet 接入方式和各种类型的网络中。作…...
电力和冷却管理:如何让数据中心“高效降温”同时节能增效
电力和冷却管理:如何让数据中心“高效降温”同时节能增效 数据中心作为现代信息技术基础设施的核心,承担着处理、存储和传输海量数据的重任。然而,这些庞大的服务器和存储设备在高速运转时,不仅需要大量电力供应,还产生了大量热量。如何平衡电力消耗与有效冷却,成为了数…...
LangChain Chat Model学习笔记
Prompt templates: Few shot、Example selector 一、Few shot(少量示例) 创建少量示例的格式化程序 创建一个简单的提示模板,用于在生成时向模型提供示例输入和输出。向LLM提供少量这样的示例被称为少量示例,这是一种简单但强大的指导生成的方式&…...