惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Forbes - Security
Forbes - Security
人人都是产品经理
人人都是产品经理
N
Netflix TechBlog - Medium
Recent Commits to openclaw:main
Recent Commits to openclaw:main
WordPress大学
WordPress大学
Webroot Blog
Webroot Blog
Jina AI
Jina AI
H
Hacker News: Front Page
Attack and Defense Labs
Attack and Defense Labs
T
Troy Hunt's Blog
TaoSecurity Blog
TaoSecurity Blog
AI
AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Help Net Security
Help Net Security
美团技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 叶小钗
P
Privacy International News Feed
A
Arctic Wolf
IT之家
IT之家
云风的 BLOG
云风的 BLOG
S
Security Affairs
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
博客园 - 司徒正美
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
SecWiki News
SecWiki News
K
Kaspersky official blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
N
News and Events Feed by Topic
S
Schneier on Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
有赞技术团队
有赞技术团队
PCI Perspectives
PCI Perspectives
F
Fortinet All Blogs
T
Tenable Blog
Spread Privacy
Spread Privacy
T
The Blog of Author Tim Ferriss
S
Securelist
L
LangChain Blog
Latest news
Latest news
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Your First LLM API on Kubernetes: From Model to Curl Request
Pawan Kumar · 2026-06-25 · via DEV Community

Series links

So far in this series, we have covered the mental model, tokens, model size, GPU node readiness, and OpenAI's Kubernetes scaling lessons.

Now we should run something.

In this part, we will deploy an actual model on a Kubernetes GPU node, expose it as an OpenAI-compatible API, and call it with curl. The model is:

Qwen/Qwen2.5-1.5B-Instruct

That model is small enough for a first single-GPU walkthrough, but still behaves like a real chat model. If your GPU is very small, try Qwen/Qwen2.5-0.5B-Instruct. If you have more memory and want a bigger test, try Qwen/Qwen2.5-7B-Instruct.

Do not start with the biggest model you can name. Start with a model your node can actually load. The goal here is not benchmark glory. The goal is to get from Kubernetes GPU capacity to a working LLM API request.

What vLLM is doing in this setup

Kubernetes is not serving the model by itself. Kubernetes schedules the pod, gives it networking, mounts the Secret, and asks the NVIDIA device plugin for a GPU. After that, the model server inside the container has to do the LLM-specific work.

vLLM is that model server in this walkthrough. It downloads the model weights, loads them into GPU memory, starts an HTTP server, accepts OpenAI-compatible requests, batches work internally, runs the model, and streams or returns generated tokens.

That distinction matters. The Kubernetes Deployment does not magically become an LLM API because it has nvidia.com/gpu: 1. It becomes an LLM API because the container starts a serving engine that knows how to load a Hugging Face model and expose routes like /v1/chat/completions.

vLLM is a good first serving engine because it hides a lot of ugly details without hiding the shape from you. You still see the model name, GPU request, port, token Secret, logs, Service, and curl request. But you do not have to write your own batching loop, tokenizer path, HTTP server, or OpenAI-compatible API wrapper just to prove the deployment works.

vLLM is the engine. The thing we care about is the model API it serves.

Prerequisites

I am assuming you already completed the GPU node setup from Part 4. That means the NVIDIA driver stack, container runtime, GPU Operator or NVIDIA device plugin, labels, and basic GPU checks are already working.

We are not reinstalling the GPU Operator here. Before deploying the model, confirm Kubernetes can see GPU capacity:

kubectl get nodes -o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu

A useful output looks like this:

NAME            GPU
gpu-worker-01   1

If the GPU column is empty, <none>, or missing, stop here. Kubernetes cannot schedule this workload until the node advertises nvidia.com/gpu.

Create a Hugging Face token first

Even though Qwen/Qwen2.5-1.5B-Instruct is public, we will still use a Hugging Face token. That is intentional.

Real teams often start with a public model and later swap to a gated model, private model, licensed model, or organization repository. If the token path is already part of the Deployment, that swap is much less annoying.

Create a token first:

  1. Open the official Hugging Face token docs: https://huggingface.co/docs/hub/security-tokens
  2. Create a token with read access.
  3. Copy the token value and keep it ready.

From this point onward, I will assume you have the token value. Do not paste it into Git. Do not put it directly in a Deployment manifest. Put it in a Kubernetes Secret.

Create the namespace and Secret

Keep the first LLM workload out of the default namespace:

kubectl create namespace llm-demo

Set the token in your shell:

export HF_TOKEN="hf_your_token_here"

Create the Secret:

kubectl create secret generic hf-token \
  -n llm-demo \
  --from-literal=HF_TOKEN="${HF_TOKEN}"

Check that it exists:

kubectl get secret hf-token -n llm-demo

Expected shape:

NAME       TYPE     DATA   AGE
hf-token   Opaque   1      10s

Existence is enough. Do not print the token back unless you have a specific reason.

Deploy the model API

vLLM gives us the model server and the OpenAI-compatible HTTP API. The Kubernetes pattern is documented in the vLLM Kubernetes docs, and the API shape is documented in the vLLM OpenAI-compatible server docs.

Create qwen-vllm.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: qwen-vllm
  namespace: llm-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qwen-vllm
  template:
    metadata:
      labels:
        app: qwen-vllm
    spec:
      containers:
        - name: vllm
          image: vllm/vllm-openai:latest
          imagePullPolicy: IfNotPresent
          command:
            - vllm
            - serve
            - Qwen/Qwen2.5-1.5B-Instruct
          args:
            - --host
            - 0.0.0.0
            - --port
            - "8000"
          ports:
            - containerPort: 8000
              name: http
          env:
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-token
                  key: HF_TOKEN
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-token
                  key: HF_TOKEN
          resources:
            limits:
              nvidia.com/gpu: 1
          volumeMounts:
            - name: shm
              mountPath: /dev/shm
      volumes:
        - name: shm
          emptyDir:
            medium: Memory
            sizeLimit: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: qwen-vllm
  namespace: llm-demo
spec:
  selector:
    app: qwen-vllm
  ports:
    - name: http
      port: 8000
      targetPort: 8000

A few details matter.

The pod requests one GPU with nvidia.com/gpu: 1. That is what makes this schedulable as a GPU workload. The token appears as both HF_TOKEN and HUGGING_FACE_HUB_TOKEN because different libraries and examples use different names. Both point to the same Secret value.

The /dev/shm mount is there because model servers often use shared memory heavily. Tiny default shared memory limits inside containers can create strange failures. A memory-backed emptyDir keeps the first deployment boring.

When this pod starts, vLLM does roughly five things. It reads the model name from the command, uses the Hugging Face token to access the repository, downloads or reuses the model files, initializes the tokenizer and model runtime, then starts the API server on port 8000. Only after that finishes is the API useful.

For production, pin the vllm/vllm-openai image version instead of using latest. For this walkthrough, latest keeps the example readable.

Apply it:

kubectl apply -f qwen-vllm.yaml

Expected output:

deployment.apps/qwen-vllm created
service/qwen-vllm created

Watch startup properly

Watch the pod:

kubectl get pods -n llm-demo -w

You may see:

NAME                         READY   STATUS              RESTARTS   AGE
qwen-vllm-6c9f7d8c9d-x9v2m   0/1     Pending             0          3s
qwen-vllm-6c9f7d8c9d-x9v2m   0/1     ContainerCreating   0          15s
qwen-vllm-6c9f7d8c9d-x9v2m   1/1     Running             0          2m

Do not celebrate too early.

Running is not the same as ready. The container can be running while the image is still settling, the model is downloading, CUDA is initializing, weights are loading, or vLLM is preparing the serving engine. The first start is usually slower because the model has to be pulled.

Follow the logs:

kubectl logs -n llm-demo -f deployment/qwen-vllm

You are looking for the server to finish loading the model and listen on port 8000. The exact log lines vary by vLLM version. If logs are still busy, wait. If they show a clear error, jump to the troubleshooting table below.

Port-forward the Service

For the first test, do not create public ingress. Do not add DNS. Do not put it behind an internet-facing load balancer.

Use port-forward:

kubectl port-forward -n llm-demo svc/qwen-vllm 8000:8000

Keep that command running. You should see:

Forwarding from 127.0.0.1:8000 -> 8000
Forwarding from [::1]:8000 -> 8000

Now local port 8000 forwards to the Kubernetes Service, which forwards to the vLLM pod.

Send the first curl request

In another terminal, call the OpenAI-compatible chat endpoint:

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-1.5B-Instruct",
    "messages": [
      {
        "role": "system",
        "content": "You are a concise Kubernetes assistant."
      },
      {
        "role": "user",
        "content": "Explain what a Kubernetes Service does in two sentences."
      }
    ],
    "max_tokens": 120,
    "temperature": 0.2
  }'

Why does the curl request include the model name again?

This part looks redundant at first:

"model": "Qwen/Qwen2.5-1.5B-Instruct"

We already gave the model name to vllm serve in the Deployment. That tells the server which model to load into memory. The model field in the curl request is part of the OpenAI-compatible API contract. Clients send it so the server knows which served model the request is targeting.

In this article, the server has only one model, so the value feels repetitive. In real systems, the same API style may sit behind routers, gateways, aliases, multiple deployments, or clients that can switch between models. Keeping the field means curl, OpenAI SDK code, and later gateway setup all follow the same shape.

For the first run, keep the value identical to the model passed to vllm serve. Later, vLLM can expose a different client-facing name with a served model name alias, but that is extra complexity we do not need yet.

A successful response will be JSON. The exact wording will differ, but the shape should look familiar:

{
  "object": "chat.completion",
  "model": "Qwen/Qwen2.5-1.5B-Instruct",
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "A Kubernetes Service provides a stable network endpoint for a set of Pods, even as those Pods are created, deleted, or replaced. It selects Pods using labels and forwards traffic to the matching backends."
      }
    }
  ]
}

That is the moment the deployment becomes real. The request reached your model server, vLLM handled the OpenAI-compatible route, the model generated text, and the response came back through Kubernetes. Not a diagram, not a promise. A model answered through an API running inside the cluster.

Swapping the model

To try the smaller model, change the served model:

command:
  - vllm
  - serve
  - Qwen/Qwen2.5-0.5B-Instruct

Then change the curl body too:

"model": "Qwen/Qwen2.5-0.5B-Instruct"

For a larger test, use Qwen/Qwen2.5-7B-Instruct in both places.

For a first run, keep the model name in the request identical to the model name served by vLLM. You can configure aliases later. Today, remove avoidable debugging.

What happened

Kubernetes scheduled a pod onto a node that advertises nvidia.com/gpu. The NVIDIA device plugin made the GPU available to the container. The Hugging Face token let the container pull the model. vLLM loaded the model onto the GPU and started an HTTP server on port 8000. The Service gave the pod a stable in-cluster endpoint. Port-forward gave us a safe local path. Curl proved the API could answer through /v1/chat/completions.

That is the basic loop every LLM platform needs before it becomes fancy:

  1. Can Kubernetes schedule the workload onto a GPU?
  2. Can the container see the GPU?
  3. Can the model server download and load the model?
  4. Can the API route accept a request?
  5. Can the model generate a response?
  6. Can you observe failures when any of those steps break?

If this loop is unreliable, autoscaling and gateways will not save you. They will only hide the problem for a while.

Troubleshooting

Symptom What it usually means What to check
Pod stuck in Pending Kubernetes cannot find a matching node Run kubectl describe pod -n llm-demo <pod-name> and read scheduler events. Confirm GPU capacity exists.
nvidia.com/gpu missing GPU Operator or device plugin path is broken Re-run the GPU visibility command and go back to Part 4 before continuing.
Hugging Face download fails Token is missing, wrong, expired, or lacks model access Recreate the token, update the Secret, then run kubectl rollout restart deployment/qwen-vllm -n llm-demo.
CUDA initialization error Driver, runtime, image, or node stack mismatch Check pod logs, GPU Operator status, driver version, and a simple CUDA test pod.
Pod crashes with OOM Model or runtime needs more memory Try Qwen/Qwen2.5-0.5B-Instruct, use a larger GPU, or tune model/runtime settings later.
curl: connection refused Server is not ready or port-forward is not running Check logs, keep port-forward running, and verify kubectl get svc -n llm-demo.
Model name mismatch Request model differs from served model Make the curl model value match the vllm serve model.

The most common mistake is treating Running as the finish line. It is not. For model serving, readiness is tied to download, GPU initialization, model loading, and server startup. Watch logs, not just pod phase.

Clean up

If this was only a test, delete the namespace:

kubectl delete namespace llm-demo

That removes the Deployment, Service, and Secret. If you keep experimenting, remember that a GPU pod can hold expensive capacity even when nobody is sending requests.

What we are not covering yet

This article stops at the first working API call. We are not covering public ingress, authentication, autoscaling, multi-GPU serving, quantization, production monitoring, or cost optimization yet.

Those are not tiny details. Public ingress brings TLS, routing, limits, and abuse controls. Authentication decides who can call the model. Autoscaling needs LLM-specific signals, not only CPU. Multi-GPU serving changes scheduling and failure behavior. Quantization changes memory and quality tradeoffs. Monitoring needs token, latency, GPU, queue, and model-server metrics.

But all of that comes after this basic path works.

A Kubernetes LLM platform starts becoming real when a model can load, serve, and answer through an API that other systems can call. Today we got there with one Deployment, one Service, one Secret, and one curl request.

In the next parts, we can make this less like a demo and more like a platform: readiness, observability, routing, auth, scaling, and the failure paths that show up once real users start sending prompts.

If you are following the series, subscribe and keep the manifest from this article handy. It is a good checklist for the first LLM-on-Kubernetes question: can we actually serve a model and call it?