Deploying the DeepSeek-V3 Model (full version) in Amazon EKS Using vLLM and LWS
This guide provides a streamlined process to deploy the full 671B parameter DeepSeek-V3 MoE model on Amazon EKS using vLLM and LeaderWorkerSet API
Who is this Guide for?
This guide assumes you:
- Have intermediate Kubernetes experience (kubectl, Helm)
- Are familiar with AWS CLI and EKS
- Understand basic GPU concepts
This guide provides a streamlined process to deploy the 671B parameter DeepSeek-V3 MoE model on Amazon EKS using vLLM a nd LeaderWorkerSet API ( LWS ). We will be deploying on Amazon EC2 G6e instances as they are a bit more accessible/available and we want to see how to load models across multiple nodes.
The main idea here is to peel the onion to see how exactly folks are deploying these large models with a practical demonstration to understand all the pieces and how they fit together.
The latest versions of the files are available here:
https://github.com/dims/skunkworks/tree/main/v3
Prerequisites
- AWS CLI: For managing AWS resources.
- eksctl/eksdemo: To create and manage EKS clusters.
- kubectl: The command-line tool for Kubernetes.
- helm: Kubernetes’ package manager.
- jq: For parsing JSON.
- Docker: For building container images.
- Hugging Face Hub access: You’ll need a token to download the model.
Creating a suitable EKS Cluster
We will use an AWS account with sufficient quota for four g6e.48xlarge instances (192 vCPUs, 1536GB RAM, 8x L40S Tensor Core GPUs that come with 48 GB of memory per GPU).
shell
eksdemo create cluster deepseek-v3-cluster-001 \--os AmazonLinux2023 \--instance g6e.48xlarge \--max 4 --nodes 4 \--volume-size 2048 \--enable-efa \--addons eks-pod-identity-agent \--no-taints \--timeout 120m
if you want to use eksctl instead, run the same above command with
--dry-run to get the equivalent command and configuration yaml.Essentially, ensure you have enough GPU nodes, allocate a large volume size per node, and enable EFA. You can use any tool of your choice, but remember you will have to adjust say for taints in the deployment yaml as needed.
🔍 Why EFA? Elastic Fabric Adapter accelerates inter-node communication, critical for multi-GPU inference.
A container image with EFA
Ideally you would just use a public image from the vllm folks:
plaintext
docker.io/vllm/vllm-openai:latest
However, we want to use EFA because Elastic Fabric Adapter (EFA) enhances inter-node communication for high-performance computing and machine learning applications within Amazon EKS clusters.
In the following Dockerfile, we start by grabbing a powerful CUDA base image, then go on an installation spree, pulling in EFA, NCCL, and AWS-OFI-NCCL, while instructing apt to hang onto its downloaded packages. Once everything’s compiled, we carefully graft these freshly built libraries onto the vLLM image above.
🛠 GPU Compatibility: The COMPUTE_CAPABILITY_VERSION=90 setting is specific to L40S GPUs. Adjust this for your hardware.
dockerfile
# syntax=docker/dockerfile:1ARG CUDA_VERSION=12.4.1FROM nvidia/cuda:${CUDA_VERSION}-devel-ubuntu20.04 AS efa-buildARG COMPUTE_CAPABILITY_VERSION=90ARG AWS_OFI_NCCL_VERSION=1.13.2-awsARG EFA_INSTALLER_VERSION=1.38.0ARG NCCL_VERSION=2.24.3RUN <<EOTrm -f /etc/apt/apt.conf.d/docker-cleanecho 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cacheecho 'APT::Install-Suggests "0";' >> /etc/apt/apt.conf.d/00-dockerecho 'APT::Install-Recommends "0";' >> /etc/apt/apt.conf.d/00-dockerecho 'tzdata tzdata/Areas select America' | debconf-set-selectionsecho 'tzdata tzdata/Zones/America select Chicago' | debconf-set-selectionsEOTRUN <<EOTapt updateapt install -y \curl \git \libhwloc-dev \pciutils \python3# EFA installercd /tmpcurl -sL https://efa-installer.amazonaws.com/aws-efa-installer-${EFA_INSTALLER_VERSION}.tar.gz | tar xvzcd aws-efa-installer./efa_installer.sh --yes --skip-kmod --skip-limit-conf --no-verify --mpi openmpi5echo "/opt/amazon/openmpi5/lib" > /etc/ld.so.conf.d/openmpi.confldconfig# NCCLcd /tmpgit clone https://github.com/NVIDIA/nccl.git -b v${NCCL_VERSION}-1cd ncclrm /opt/nccl/lib/*.amake -j $(nproc) src.build \BUILDDIR=/opt/nccl \CUDA_HOME=/usr/local/cuda \NVCC_GENCODE="-gencode=arch=compute_${COMPUTE_CAPABILITY_VERSION},code=sm_${COMPUTE_CAPABILITY_VERSION} -gencode=arch=compute_${COMPUTE_CAPABILITY_VERSION},code=sm_${COMPUTE_CAPABILITY_VERSION}"echo "/opt/nccl/lib" > /etc/ld.so.conf.d/000_nccl.confldconfig# AWS-OFI-NCCL plugincd /tmpcurl -sL https://github.com/aws/aws-ofi-nccl/releases/download/v${AWS_OFI_NCCL_VERSION}/aws-ofi-nccl-${AWS_OFI_NCCL_VERSION}.tar.gz | tar xvzcd aws-ofi-nccl-${AWS_OFI_NCCL_VERSION}./configure --prefix=/opt/aws-ofi-nccl/install \--with-mpi=/opt/amazon/openmpi5 \--with-libfabric=/opt/amazon/efa \--with-cuda=/usr/local/cuda \--enable-tests=no \--enable-platform-awsmake -j $(nproc)make installecho "/opt/aws-ofi-nccl/install/lib" > /etc/ld.so.conf.d/000-aws-ofi-nccl.confldconfigEOT################################################################FROM docker.io/vllm/vllm-openai:latestCOPY --from=efa-build /usr/lib/x86_64-linux-gnu/libhwloc.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libltdl.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libefa.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libhns.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libmana.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libmlx4.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libmlx5.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libibverbs.* /usr/lib/x86_64-linux-gnu/COPY --from=efa-build /usr/lib/x86_64-linux-gnu/libibverbs /usr/lib/x86_64-linux-gnu/libibverbsCOPY --from=efa-build /opt/amazon /opt/amazonCOPY --from=efa-build /opt/aws-ofi-nccl /opt/aws-ofi-ncclCOPY --from=efa-build /opt/nccl/lib /opt/nccl/libCOPY --from=efa-build /etc/ld.so.conf.d /etc/ld.so.conf.dENV LD_PRELOAD=/opt/nccl/lib/libnccl.soCOPY ./ray_init.sh /ray_init.shRUN <<EOTchmod +x /ray_init.shpip install huggingface_hub[hf_transfer]pip install -U "ray[default]" "ray[cgraph]"EOT
Note we also install
hugging_hub with the high speed hf_transfer component and update the ray package. There is a ray_init.sh which helps us start vllm and ray in the leader and worker nodes brought up by LWS.shell
#!/bin/bashsubcommand=$1shiftray_port=6379ray_init_timeout=300declare -a start_paramscase "$subcommand" inworker)ray_address=""while [ $# -gt 0 ]; docase "$1" in--ray_address=*)ray_address="${1#*=}";;--ray_port=*)ray_port="${1#*=}";;--ray_init_timeout=*)ray_init_timeout="${1#*=}";;*)start_params+=("$1")esacshiftdoneif [ -z "$ray_address" ]; thenecho "Error: Missing argument --ray_address"exit 1fiuntil ray status --address $ray_address:$ray_port; doecho "Waiting until the ray status is active for leader..."sleep 5s;donefor (( i=0; i < $ray_init_timeout; i+=5 )); doray start --address=$ray_address:$ray_port --block "${start_params[@]}"if [ $? -eq 0 ]; thenecho "Worker: Ray runtime started with head address $ray_address:$ray_port"exit 0fiecho "Waiting until the ray worker is active..."sleep 5s;doneecho "Ray worker starts timeout, head address: $ray_address:$ray_port"exit 1;;leader)ray_cluster_size=""while [ $# -gt 0 ]; docase "$1" in--ray_port=*)ray_port="${1#*=}";;--ray_cluster_size=*)ray_cluster_size="${1#*=}";;--ray_init_timeout=*)ray_init_timeout="${1#*=}";;*)start_params+=("$1")esacshiftdoneif [ -z "$ray_cluster_size" ]; thenecho "Error: Missing argument --ray_cluster_size"exit 1fi# start the ray daemonray start --head --include-dashboard=true --port=$ray_port "${start_params[@]}"# wait until all workers are activefor (( i=0; i < $ray_init_timeout; i+=5 )); doactive_nodes=`python3 -c 'import ray; ray.init(); print(sum(node["Alive"] for node in ray.nodes()))'`if [ $active_nodes -eq $ray_cluster_size ]; thenecho "All ray workers are active and the ray cluster is initialized successfully."exit 0fiecho "Wait for all ray workers to be active. $active_nodes/$ray_cluster_size is active"sleep 5s;doneecho "Waiting for all ray workers to be active timed out."exit 1;;*)echo "unknown subcommand: $subcommand"exit 1;;esac
Verify the cluster
Step 1: Check Daemonsets
Check if the Nvidia and EFA daemonsets are running using
shell
kubectl get daemonsets -A | grep -E 'nvidia|efa'
plaintext
kube-system aws-efa-k8s-device-plugin 1 1 1 1 1 <none> 11mkube-system nvidia-device-plugin-daemonset 1 1 1 1 1 <none> 11m
Step 2: Verify Node Resources
Check if the nodes are correctly annotated with the GPU count and EFA capacity
shell
kubectl get nodes -o json | jq -r '["NODE", "NVIDIA_GPU", "EFA_CAPACITY"],(.items[] |[.metadata.name,(.status.capacity."nvidia.com/gpu" // "0"),(.status.capacity."vpc.amazonaws.com/efa" // "0")]) | @tsv' | column -t -s $'\t'
plaintext
NODE NVIDIA_GPU EFA_CAPACITYi-08982f78fb3e2b7d7.us-west-2.compute.internal 8 4
Step 3: Inspect Hardware
Install the
node-shell kubectl/krew plugin to peek into the nodes (will be handy for later) using kubectl krew install node-shell Now check if the devices are correctly present in each node
shell
kubectl get nodes -o name | cut -d/ -f2 | \xargs -I{} sh -c 'echo "=== {} ==="; kubectl node-shell {} -- sh -c "lspci | grep -iE \"nvidia|amazon.*(efa)\"";'
plaintext
=== i-08982f78fb3e2b7d7.us-west-2.compute.internal ===spawning "nsenter-k9hss5" on "i-08982f78fb3e2b7d7.us-west-2.compute.internal"9b:00.0 Ethernet controller: Amazon.com, Inc. Elastic Fabric Adapter (EFA)9c:00.0 Ethernet controller: Amazon.com, Inc. Elastic Fabric Adapter (EFA)9e:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)a0:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)a2:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)a4:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)bc:00.0 Ethernet controller: Amazon.com, Inc. Elastic Fabric Adapter (EFA)bd:00.0 Ethernet controller: Amazon.com, Inc. Elastic Fabric Adapter (EFA)c6:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)c8:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)ca:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)cc:00.0 3D controller: NVIDIA Corporation AD102GL [L40S] (rev a1)pod "nsenter-k9hss5" deleted
Run the deepseek-v3 workload
Install LWS Controller
Use helm to install LWS:
shell
helm install lws oci://registry.k8s.io/lws/charts/lws \--version=0.6.1 \--namespace lws-system \--create-namespace \--wait --timeout 300s
Check if the LWS pods are running using
kubectl get pods -n lws-system plaintext
NAME READY STATUS RESTARTS AGElws-controller-manager-696b448fb9-fxxs8 1/1 Running 0 88s
Edit
deepseek-lws.yaml to insert your hugging face token (ensure it's base64 encoded):YAML
apiVersion: leaderworkerset.x-k8s.io/v1kind: LeaderWorkerSetmetadata:name: vllmspec:replicas: 1leaderWorkerTemplate:size: 4restartPolicy: RecreateGroupOnPodRestartleaderTemplate:metadata:labels:role: leaderspec:containers:- name: vllm-leaderimage: ghcr.io/dims/skunkworks/vllm-v3:89-775754b81f110d1d5c3165ef277e5571b18e5da4securityContext:privileged: truecapabilities:add: ["IPC_LOCK"]env:- name: NCCL_DEBUGvalue: "TRACE"- name: NCCL_DEBUG_SUBSYSvalue: "ALL"- name: NCCL_IB_DISABLEvalue: "1"- name: NCCL_P2P_DISABLEvalue: "1"- name: NCCL_NET_GDR_LEVELvalue: "0"- name: NCCL_SHM_DISABLEvalue: "1"- name: PYTORCH_CUDA_ALLOC_CONFvalue: "max_split_size_mb:512,expandable_segments:True"- name: CUDA_MEMORY_FRACTIONvalue: "0.95"- name: FI_EFA_USE_DEVICE_RDMAvalue: "1"- name: FI_PROVIDERvalue: "efa"- name: FI_EFA_FORK_SAFEvalue: "1"- name: HF_HUB_ENABLE_HF_TRANSFERvalue: "1"- name: HF_HOMEvalue: "/local/huggingface"- name: HF_HUB_VERBOSITYvalue: "debug"- name: HF_TOKENvalueFrom:secretKeyRef:name: hf-token-secretkey: token- name: MODEL_REPOvalue: "deepseek-ai/DeepSeek-V3"command: ["/bin/bash"]args:- "-c"- |set -x# start ray leader/ray_init.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE);sleep 30ray status# download and install modelhuggingface-cli download ${MODEL_REPO}# start vllm servervllm serve ${MODEL_REPO} \--host 0.0.0.0 \--port 8000 \--tensor-parallel-size 8 \--pipeline-parallel-size 4 \--disable-log-requests \--uvicorn-log-level error \--max-model-len 32768 \--trust-remote-code \--device cuda \--gpu-memory-utilization 0.8resources:limits:nvidia.com/gpu: "8"cpu: "96"memory: 384Givpc.amazonaws.com/efa: 4requests:nvidia.com/gpu: "8"cpu: "96"memory: 384Givpc.amazonaws.com/efa: 4ports:- containerPort: 8000readinessProbe:tcpSocket:port: 8000initialDelaySeconds: 15periodSeconds: 10volumeMounts:- name: local-storagemountPath: /local- name: shmmountPath: /dev/shmvolumes:- name: local-storagehostPath:path: /root/localtype: DirectoryOrCreate- name: shmemptyDir:medium: MemorysizeLimit: "512Gi"workerTemplate:spec:containers:- name: vllm-workerimage: ghcr.io/dims/skunkworks/vllm-v3:89-775754b81f110d1d5c3165ef277e5571b18e5da4securityContext:privileged: truecapabilities:add: ["IPC_LOCK"]env:- name: HF_HUB_ENABLE_HF_TRANSFERvalue: "1"- name: HF_HOMEvalue: "/local/huggingface"- name: HF_HUB_VERBOSITYvalue: "debug"- name: HF_TOKENvalueFrom:secretKeyRef:name: hf-token-secretkey: token- name: NCCL_DEBUGvalue: "TRACE"command: ["/bin/bash"]args:- "-c"- |set -x# start ray worker/ray_init.sh worker --ray_address=$(LWS_LEADER_ADDRESS)resources:limits:nvidia.com/gpu: "8"cpu: "96"memory: 384Givpc.amazonaws.com/efa: 4requests:nvidia.com/gpu: "8"cpu: "96"memory: 384Givpc.amazonaws.com/efa: 4volumeMounts:- name: local-storagemountPath: /local- name: shmmountPath: /dev/shmvolumes:- name: local-storagehostPath:path: /root/localtype: DirectoryOrCreate- name: shmemptyDir:medium: MemorysizeLimit: "512Gi"---apiVersion: v1kind: Servicemetadata:name: vllm-leaderspec:ports:- name: port-8000port: 8000targetPort: 8000- name: port-8265port: 8265targetPort: 8265type: ClusterIPselector:leaderworkerset.sigs.k8s.io/name: vllmrole: leader---apiVersion: v1kind: Secretmetadata:name: hf-token-secrettype: Opaquedata:token: "PASTE_BASE_64_VERSION_OF_YOUR_HF_TOKEN_HERE"
Important: Replace "PASTE_BASE_64_VERSION_OF_YOUR_HF_TOKEN_HERE" with the base64 encoded version of your Hugging Face token. To base64 encode it, you can use something like
echo -n 'your_token' | base64 A couple of other things to point out, if you see the
vllm command line you will noticeshell
--tensor-parallel-size 8 \--pipeline-parallel-size 4 \
Across the 4 notes we have 32 GPUs, we are splitting these into 8 way tensor-parallel and 4 pipeline stages for a total of 32 (read about these params here ).
Apply the yaml using kubectl:
shell
kubectl apply -f deepseek-lws.yaml
plaintext
leaderworkerset.leaderworkerset.x-k8s.io/vllm createdservice/vllm-leader unchangedsecret/hf-token-secret unchanged
Check on the vllm pods
shell
kubectl get pods
plaintext
NAME READY STATUS RESTARTS AGEvllm-0 0/1 Running 0 50svllm-0-1 1/1 Running 0 50svllm-0-2 1/1 Running 0 50svllm-0-3 1/1 Running 0 50s
You will need to wait until
vllm-0 gets to 1/1 . You can check in on what is happening inside the main pod usingshell
kubectl logs vllm-0 -f
In the
deepseek-lws.yaml , you will notice that we have turned up all the logging way up high so you get an idea of all the things happening (or not!) in the system. Once you get familiar, you can turn down the settings to as much as you wish.You will see the model being downloaded:
plaintext
(RayWorkerWrapper pid=444, ip=192.168.130.178) Downloading 'model-00118-of-000163.safetensors' to '/local/huggingface/hub/models--deepseek-ai--DeepSeek-V3/blobs/72680742383e3ac1d20bc8abef7c730f880310b88a07e72d5a6ee47bc38613e9.incomplete'(RayWorkerWrapper pid=444, ip=192.168.130.178) Downloading 'model-00119-of-000163.safetensors' to '/local/huggingface/hub/models--deepseek-ai--DeepSeek-V3/blobs/a7f04447b66d432a8800d6fb40788f980bd74d679716cb3ea6ed4ef328c73b43.incomplete'(RayWorkerWrapper pid=444, ip=192.168.130.178) Downloading 'model-00120-of-000163.safetensors' to '/local/huggingface/hub/models--deepseek-ai--DeepSeek-V3/blobs/a540ce2f0766c50c12a7af78f41b3f5b6b64ebe8cdc804ee0ff8ff81a90248cc.incomplete'
If you inspect the deepseek-lws.yaml, you will see that
/root/local directory on the host is used to store the model. So even if the pods fail for some reason, the next pod will pick up downloading from where the previous pod failed.After a while you will see the following:
plaintext
Loading safetensors checkpoint shards: 94% Completed | 153/163 [00:13<00:00, 23.11it/s]Loading safetensors checkpoint shards: 96% Completed | 156/163 [00:13<00:00, 22.98it/s]Loading safetensors checkpoint shards: 98% Completed | 159/163 [00:13<00:00, 22.92it/s]Loading safetensors checkpoint shards: 100% Completed | 163/163 [00:13<00:00, 12.10it/s]
Once you see the following, the vllm openapi endpoint is ready!
plaintext
INFO 04-19 18:04:54 [launcher.py:26] Available routes are:INFO 04-19 18:04:54 [launcher.py:34] Route: /openapi.json, Methods: HEAD, GETINFO 04-19 18:04:54 [launcher.py:34] Route: /docs, Methods: HEAD, GETINFO 04-19 18:04:54 [launcher.py:34] Route: /docs/oauth2-redirect, Methods: HEAD, GETINFO 04-19 18:04:54 [launcher.py:34] Route: /redoc, Methods: HEAD, GETINFO 04-19 18:04:54 [launcher.py:34] Route: /health, Methods: GETINFO 04-19 18:04:54 [launcher.py:34] Route: /load, Methods: GETINFO 04-19 18:04:54 [launcher.py:34] Route: /ping, Methods: POST, GETINFO 04-19 18:04:54 [launcher.py:34] Route: /tokenize, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /detokenize, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/models, Methods: GETINFO 04-19 18:04:54 [launcher.py:34] Route: /version, Methods: GETINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/chat/completions, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/completions, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/embeddings, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /pooling, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /score, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/score, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/audio/transcriptions, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /rerank, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v1/rerank, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /v2/rerank, Methods: POSTINFO 04-19 18:04:54 [launcher.py:34] Route: /invocations, Methods: POST
Take it for a spin!
Access the API
To access the DeepSeek-V3 model using your localhost, use the following command:
shell
kubectl port-forward svc/vllm-leader 8000:8000 8265:8265
To check if the model is registered using the openapi spec, use the following command:
plaintext
curl -X GET "http://127.0.0.1:8000/v1/models" | jq
To test the deployment use the following command:
shell
curl -X POST "http://127.0.0.1:8000/v1/chat/completions" \-H "Content-Type: application/json" \-d '{"model": "deepseek-ai/DeepSeek-V3","messages": [{"role": "user","content": "What is Kubernetes?"}]}' | jq
you will see something like:
JSON
{"id": "chatcmpl-f0447f97931d49bab156dfd266055de0","object": "chat.completion","created": 1745112232,"model": "deepseek-ai/DeepSeek-V3","choices": [{"index": 0,"message": {"role": "assistant","reasoning_content": null,"content": "Kubernetes, often abbreviated as K8s, is an open-source platform designed to automate deploying, scaling, and operating application containers. It was originally developed by Google and is now maintained by the Cloud Native Computing Foundation (CNCF).\n\nHere are some key features and components of Kubernetes:\n\n1. **Container Orchestration**: Kubernetes manages containerized applications across a cluster of machines. It ensures that the desired number of containers are running and can automatically replace any that fail.\n\n2. **Scaling**: Kubernetes can automatically scale applications up or down based on demand, ensuring optimal resource utilization.\n\n3. **Service Discovery and Load Balancing**: Kubernetes can expose a container using a DNS name or its own IP address. If traffic to a container is high, Kubernetes can load balance and distribute the network traffic to stabilize the deployment.\n\n4. **Storage Orchestration**: Kubernetes allows you to automatically mount a storage system of your choice, whether local storage, public cloud providers, or network storage systems.\n\n5. **Self-Healing**: Kubernetes can restart containers that fail, replace containers, kill containers that don't respond to your user-defined health check, and advertise them to clients only when they are ready to serve.\n\n6. **Automated Rollouts and Rollbacks**: Kubernetes allows you to describe the desired state for your deployed containers and can change the actual state to the desired state at a controlled rate. If something goes wrong, Kubernetes can roll back the change.\n\n7. **Configurations and Secrets**: Kubernetes manages configurations and secrets, ensuring sensitive information is securely handled and configurations are consistent across environments.\n\n8. **Portability**: Kubernetes can run on various platforms, including on-premises, public cloud, and hybrid environments, making it highly flexible.\n\nKubernetes uses a declarative model to define the desired state of the system, and it continuously works to maintain that state. It is widely used in the industry for managing containerized applications in production environments.","tool_calls": []},"logprobs": null,"finish_reason": "stop","stop_reason": null}],"usage": {"prompt_tokens": 7,"total_tokens": 397,"completion_tokens": 390,"prompt_tokens_details": null},"prompt_logprobs": null}
Now feel free to tweak the
deepseek-lws.yaml and re-apply the changes using:shell
kubectl apply -f deepseek-lws.yaml
Just to be sure, you can clean up using
kubectl delete -f deepseek-lws.yaml and use kubectl get pods to make sure all the pods are gone before you run kubectl apply .Happy Hacking!!
Bonus
If you were a keen observer and noticed that we forwarded port
8265 as well, point your browser to look at the Ray dashboard!You can see the GPU usage specifically when you are running an inference.
Thanks
This post is based on Bryant Biggs 's work in various repositories, thanks Bryant. Also thanks to Arush Sharma for a quick review and suggestions. Kudos to the folks in the Ray, vLLM, LWS, and Kubernetes communities for making it easier to compose these complex scenarios.
Things to try
As mentioned earlier we are relying here on a host node directory to persist model downloads across pod restarts. There are other options you can try as well, see the mozilla.ai link below that uses Persistent Volumes for example. Yet another option to store/load the model is using The FSx for Lustre Container Storage Interface (CSI) driver .
Links
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article