k8s整条链路
整条链路:
curl http://10.0.0.8
→ 本地 nginx (Host: fleet.local)
→ 172.18.0.2:32305 (Kind node NodePort)
→ ingress-nginx controller pod
→ 匹配 Ingress 规则 (fleet.local → fleet-api Service)
→ fleet-api Service (负载均衡)
→ fleet-api pod (任意一个副本)
Nginx把LoadBalancer转发到10.0.0.0/24网段
vim /etc/nginx/sites-available/fleet.local
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://172.18.0.2:32305;
proxy_set_header Host fleet.local;
proxy_set_header X-Real-IP $remote_addr;
}
}
查看Kind配置:
(.venv) will@ubuntu24 ~/fleet-api/app master ± k get nodes -A NAME STATUS ROLES AGE VERSION kind-control-plane Ready control-plane 46h v1.36.1 (.venv) will@ubuntu24 ~/fleet-api/app master ± kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME kind-control-plane Ready control-plane 46h v1.36.1 172.18.0.2 <none> Debian GNU/Linux 13 (trixie) 6.8.0-134-generic (amd64) containerd://2.3.1 (.venv) will@ubuntu24 ~/fleet-api/app master ±
查看ingress配置:
(.venv) ✘ will@ubuntu24 ~ k describe service/ingress-nginx-controller -n ingress-nginx
Name: ingress-nginx-controller
Namespace: ingress-nginx
Labels: app.kubernetes.io/component=controller
app.kubernetes.io/instance=ingress-nginx
app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
app.kubernetes.io/version=1.15.1
Annotations: <none>
Selector: app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.209.119
IPs: 10.96.209.119
Port: http 80/TCP
TargetPort: http/TCP
AppProtocol: http
NodePort: http 32305/TCP
Endpoints: 10.244.0.28:80
Port: https 443/TCP
TargetPort: https/TCP
AppProtocol: https
NodePort: https 32608/TCP
Endpoints: 10.244.0.28:443
Session Affinity: None
External Traffic Policy: Cluster
Internal Traffic Policy: Cluster
Events: <none>
(.venv) will@ubuntu24 ~
ingress对外暴露的IP是10.244.0.28,端口号是32305,对内是80端口
ingress-nginx-controller是一个LoadBalancer,把内部的ingress 80端口转发给32305
(.venv) will@ubuntu24 ~ k get services -A NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE crossplane-system crossplane-apollo-metrics ClusterIP 10.96.238.61 <none> 8085/TCP 45h crossplane-system crossplane-webhooks ClusterIP 10.96.115.220 <none> 9443/TCP 45h crossplane-system provider-azure-management ClusterIP 10.96.122.90 <none> 9443/TCP 45h crossplane-system spaces-apollo ClusterIP 10.96.122.242 <none> 8080/TCP 45h crossplane-system upbound-controller-manager ClusterIP 10.96.6.7 <none> 8082/TCP 45h crossplane-system upbound-provider-family-azure ClusterIP 10.96.33.199 <none> 9443/TCP 45h crossplane-system webui ClusterIP 10.96.80.132 <none> 80/TCP 45h default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 45h fleet fleet-api ClusterIP 10.96.174.44 <none> 80/TCP 11h ingress-nginx ingress-nginx-controller LoadBalancer 10.96.209.119 <pending> 80:32305/TCP,443:32608/TCP 10h ingress-nginx ingress-nginx-controller-admission ClusterIP 10.96.199.180 <none> 443/TCP 10h kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 45h (.venv) will@ubuntu24 ~
对内的80会映射到backends中的某一个8080端口
(.venv) will@ubuntu24 ~ k describe ingress -n fleet
Name: fleet-ingress
Labels: <none>
Namespace: fleet
Address: localhost
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
fleet.local
/ fleet-api:80 (10.244.0.2:8080,10.244.0.5:8080)
Annotations: <none>
Events: <none>
(.venv) will@ubuntu24 ~
到了pods内部,8080端口由container serve
(.venv) ✘ will@ubuntu24 ~ k describe pod/fleet-api-6958d5465d-655t5 -n fleet
Name: fleet-api-6958d5465d-655t5
Namespace: fleet
Priority: 0
Service Account: default
Node: kind-control-plane/172.18.0.2
Start Time: Fri, 21 Aug 2026 02:40:59 +0800
Labels: app=fleet-api
pod-template-hash=6958d5465d
Annotations: <none>
Status: Running
IP: 10.244.0.5
IPs:
IP: 10.244.0.5
Controlled By: ReplicaSet/fleet-api-6958d5465d
Containers:
fleet-api:
Container ID: containerd://df208381beca730d792566791c1b786550a65ccb1a5dac2d7ef5deb5e35a0bb2
Image: fleet-api:v1
Image ID: docker.io/library/import-2026-08-20@sha256:8488112d8e902c9303747cb64cf0eae5a155747bb8062465f11a5b0a2d599de3
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Fri, 21 Aug 2026 03:06:43 +0800
Last State: Terminated
Reason: Unknown
Exit Code: 255
Started: Fri, 21 Aug 2026 02:41:00 +0800
Finished: Fri, 21 Aug 2026 03:06:34 +0800
Ready: True
Restart Count: 1
Limits:
cpu: 200m
memory: 128Mi
Requests:
cpu: 100m
memory: 64Mi
Liveness: http-get http://:8080/health delay=30s timeout=1s period=10s #success=1 #failure=3
Readiness: http-get http://:8080/health delay=10s timeout=1s period=5s #success=1 #failure=3
Environment Variables from:
fleet-config ConfigMap Optional: false
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-52mp9 (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-52mp9:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
Optional: false
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
(.venv) will@ubuntu24 ~
8080端口由这个py文件serve
FROM python:3.11-slim
ARG VERSION=unknown
ENV VERSION=${VERSION}
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
RUN useradd --create-home appuser && chown -R appuser /app
USER appuser
EXPOSE 8080
ENV PYTHONUNBUFFERED=1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
Python文件内容:
import os
import subprocess
from typing import List
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel
def get_git_version() -> str:
version = os.getenv("VERSION")
if version:
return version
try:
repo_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
return subprocess.check_output(
["git", "rev-parse", "--short", "HEAD"], cwd=repo_dir, text=True
).strip()
except Exception:
return "unknown"
class Settings:
def __init__(self) -> None:
self.max_vehicles = int(os.getenv("MAX_VEHICLES", "100"))
self.version = os.getenv("VERSION", "unknown")
class Vehicle(BaseModel):
id: str
battery: int
online: bool
class HealthResponse(BaseModel):
status: str
service: str
version: str
settings = Settings()
if settings.version == "unknown":
settings.version = get_git_version()
app = FastAPI(title="fleet-api", version=settings.version)
@app.get("/health", response_model=HealthResponse)
def health() -> HealthResponse:
return HealthResponse(
status="healthy", service="fleet-api", version=settings.version
)
VEHICLES: List[Vehicle] = [
Vehicle(id="v001", battery=85, online=True),
Vehicle(id="v002", battery=42, online=False),
Vehicle(id="v003", battery=97, online=True),
]
@app.get("/vehicles/{vid}", response_model=Vehicle)
def get_vehicle(vid: str) -> Vehicle:
for vehicle in VEHICLES:
1,1 Top
