云原生的专业内核不是"把应用塞进容器",而是声明式交付、资源契约、弹性伸缩、故障自愈、全链路可观测、GitOps闭环。下面按生产级落地拆解,每环给可运行代码。
镜像不是能跑就行。多阶段构建压体积,非root降攻击面,探针让K8s知道何时接流量、何时重启。
# Dockerfile
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app ./cmd/server
FROM gcr.io/distroless/static:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]# deployment.yaml 关键片段
containers:
- name: api
image: registry.example.com/api:v1.2.0 # 禁止 latest
resources:
requests: {cpu: "100m", memory: "128Mi"}
limits: {cpu: "500m", memory: "256Mi"}
readinessProbe:
httpGet: {path: /readyz, port: 8080}
periodSeconds: 5
livenessProbe:
httpGet: {path: /healthz, port: 8080}
periodSeconds: 10
failureThreshold: 3
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false工程约束:requests必须设,否则调度器瞎排、HPA算不准;limits必须设,否则一个Pod OOM拖垮节点;readinessProbe失败摘流量,livenessProbe失败重启,两者路径不能混用。
CPU弹性对IO密集型服务无效。用Prometheus Adapter暴露QPS/队列深度等业务指标,HPA按业务指标扩缩。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: {name: api-hpa}
spec:
scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: api}
minReplicas: 2
maxReplicas: 20
metrics:
- type: Pods
pods:
metric: {name: http_requests_per_second}
target: {type: AverageValue, averageValue: "100"}
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 防抖动工程约束:minReplicas≥2保证高可用;stabilizationWindowSeconds防指标毛刺导致反复扩缩;HPA依赖requests,requests虚低会导致扩容后仍过载。
滚动更新和节点驱逐时,必须保证可用副本数,且副本跨可用区。
spec:
replicas: 4
template:
spec:
terminationGracePeriodSeconds: 30
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector: {matchLabels: {app: api}}
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: {name: api-pdb}
spec:
minAvailable: 3
selector: {matchLabels: {app: api}}// 优雅停机:先摘流量,再停服务
srv := &http.Server{Addr: ":8080", Handler: mux}
go srv.ListenAndServe()
sig := make(chan os.Signal, 1); signal.Notify(sig, syscall.SIGTERM)
<-sig
ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
defer cancel()
srv.Shutdown(ctx) // 处理完存量请求再退出工程约束:terminationGracePeriodSeconds必须大于应用最大请求耗时;preStop里可加sleep 5等endpoint同步;PDB防运维误操作把副本驱逐光。
不要kubectl apply手工改集群。所有 manifests 进Git,ArgoCD持续比对、自动同步,漂移可回滚。
# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: {name: api-prod, namespace: argocd}
spec:
project: default
source:
repoURL: https://git.example.com/platform.git
targetRevision: main
path: apps/api/overlays/prod # Kustomize overlay
destination:
server: https://kubernetes.default.svc
namespace: prod
syncPolicy:
automated: {prune: true, selfHeal: true} # 自动纠偏
syncOptions: [CreateNamespace=true]工程约束:selfHeal: true让手工改动被自动还原;prune: true清理Git中已删资源;生产环境用SyncWindow限制发布时段。
// OpenTelemetry 接入,trace + metrics 一次埋点
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func initTracer() {
exp, _ := otlptracegrpc.New(context.Background())
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exp))
otel.SetTracerProvider(tp)
}
// 业务代码
ctx, span := otel.Tracer("api").Start(ctx, "handleOrder")
defer span.End()工程约束:traceID要透传到日志和下游调用;指标带service、version、pod标签;日志统一JSON结构化,禁止打印敏感字段。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: api-allow-ingress}
spec:
podSelector: {matchLabels: {app: api}}
ingress:
- from: [{podSelector: {matchLabels: {app: gateway}}}]
ports: [{protocol: TCP, port: 8080}]
---
apiVersion: v1
kind: ResourceQuota
metadata: {name: prod-quota, namespace: prod}
spec:
hard: {requests.cpu: "20", requests.memory: 40Gi, pods: "50"}工程约束:默认拒绝入站,按需放行;ResourceQuota防单命名空间吃光集群;CI里加Trivy镜像扫描,高危漏洞阻断发布。
总结:云原生的专业度不在"会kubectl",而在多阶段非root镜像、requests/limits与双探针、业务指标HPA、PDB与拓扑分布、优雅停机、GitOps自动纠偏、OTel三件套、网络策略与配额这八件事。能给别人讲清楚"为什么HPA只看CPU会翻车""为什么手工改集群是事故源头",你就站稳了云原生工程。觉得有用点赞收藏,需要完整工程目录留言。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。