跳到主要内容

Kubernetes 基础

问题

Kubernetes(K8s)是什么?前端工程师为什么需要了解 Kubernetes?它的核心概念和架构是怎样的?如何将前端项目部署到 K8s 集群中?

答案

Kubernetes(简称 K8s)是 Google 开源的容器编排平台,用于自动化容器化应用的部署、扩缩和管理。随着云原生和 DevOps 的普及,前端工程师越来越多地参与到 CI/CD 流水线和部署环节中,掌握 K8s 基础知识已经成为前端工程化能力的重要组成部分。

为什么前端工程师需要了解 K8s

  1. CI/CD 流水线:前端项目的构建、测试、部署往往在 K8s 集群中运行
  2. 微前端架构:不同子应用可能作为独立的 K8s 服务部署
  3. SSR/BFF 服务:Next.js、Nuxt.js 等 SSR 应用本质上是 Node.js 服务,需要容器化部署
  4. 环境管理:开发、测试、预发、生产环境通过 K8s Namespace 隔离
  5. 故障排查:了解 K8s 有助于快速定位线上问题(Pod 崩溃、服务不可达等)

K8s 核心概念

Pod -- 最小部署单元

Pod 是 K8s 中最小的可部署单元,一个 Pod 可以包含一个或多个紧密关联的容器。Pod 中的容器共享网络命名空间(同一个 IP 地址)和存储卷。

pod-example.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend-pod
labels:
app: frontend
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
要点

在实际生产中,我们几乎不会直接创建 Pod,而是通过 Deployment 等更高层的控制器来管理 Pod。直接创建的 Pod 如果崩溃,不会被自动恢复。

Deployment -- 无状态应用管理

Deployment 是管理 Pod 副本的控制器,提供声明式更新、滚动升级和回滚能力。前端应用(Nginx 托管的静态资源、SSR 服务等)通常使用 Deployment 部署。

deployment-example.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-app
labels:
app: frontend
spec:
replicas: 3 # 运行 3 个 Pod 副本
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: registry.example.com/frontend:v1.2.0
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
# 就绪探针:确保容器准备好接收流量
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
# 存活探针:检测容器是否健康
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 30

Deployment 的核心能力:

  • 副本管理:保证始终有指定数量的 Pod 在运行
  • 滚动更新:逐步替换旧版本 Pod,实现零停机发布
  • 自动恢复:Pod 崩溃后自动重新创建
  • 回滚:支持一键回滚到历史版本

Service -- 服务发现与负载均衡

Service 为一组 Pod 提供稳定的网络访问入口。Pod 的 IP 是动态变化的,Service 提供固定的 Cluster IP 或 DNS 名称,并在多个 Pod 之间做负载均衡。

service-example.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend # 选择标签为 app=frontend 的 Pod
type: ClusterIP # 默认类型,仅集群内部可访问
ports:
- protocol: TCP
port: 80 # Service 暴露的端口
targetPort: 80 # Pod 的端口
name: http

常见的 Service 类型:

类型说明使用场景
ClusterIP默认类型,仅集群内部可访问内部微服务通信
NodePort在每个节点上开放端口(30000-32767)开发测试环境
LoadBalancer创建云厂商负载均衡器生产环境对外暴露服务
ExternalName将 Service 映射到外部 DNS访问集群外部服务

Ingress -- HTTP 路由与域名管理

Ingress 是 K8s 中管理 HTTP/HTTPS 路由的资源,可以根据域名和路径将流量转发到不同的 Service。它是前端项目对外暴露的关键组件。

ingress-example.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: frontend-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 3000
补充

Ingress 本身只是一种资源定义,需要配合 Ingress Controller(如 Nginx Ingress Controller、Traefik 等)才能生效。Ingress Controller 负责监听 Ingress 资源的变化并更新路由规则。

Namespace -- 资源隔离

Namespace 提供了集群级别的资源隔离,常用于隔离不同环境或不同团队的资源。

namespace-example.yaml
apiVersion: v1
kind: Namespace
metadata:
name: frontend-staging
labels:
env: staging

典型的 Namespace 划分:

# 按环境划分
kubectl get namespaces
# NAME STATUS AGE
# default Active 30d
# frontend-dev Active 25d
# frontend-staging Active 20d
# frontend-prod Active 15d
# kube-system Active 30d

K8s 架构

Kubernetes 采用 Master-Node(控制平面-工作节点)架构。理解这个架构有助于排查部署问题。

控制平面(Control Plane)组件

组件职责类比理解
kube-apiserverK8s 的"前端入口",所有操作都通过它类似于 API Gateway
etcd分布式键值存储,保存集群所有状态数据类似于数据库
kube-scheduler决定 Pod 在哪个 Node 上运行类似于负载均衡调度器
kube-controller-manager运行各种控制器(Deployment、ReplicaSet 等)类似于后台任务管理器

工作节点(Node)组件

组件职责类比理解
kubelet管理节点上的 Pod 生命周期类似于 PM2 进程管理器
kube-proxy维护网络规则,实现 Service 的负载均衡类似于 Nginx 反向代理
容器运行时实际运行容器(containerd、CRI-O)类似于 Docker Engine
注意

从 K8s 1.24 开始,Docker 不再作为默认的容器运行时,取而代之的是 containerd。但这不影响使用 Docker 构建镜像,K8s 仍然能运行 Docker 格式的镜像。


前端项目部署到 K8s

一个完整的前端项目部署到 K8s 通常包括以下步骤:

第一步:编写 Dockerfile

使用多阶段构建(Multi-stage Build)来优化前端镜像体积:

Dockerfile
# 第一阶段:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

# 第二阶段:运行
FROM nginx:1.25-alpine
# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 从构建阶段复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

对应的 Nginx 配置,支持 SPA 路由:

nginx.conf
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;

# SPA 路由 - 所有路径都返回 index.html
location / {
try_files $uri $uri/ /index.html;
}

# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

# gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1024;
}

第二步:编写完整的 K8s 部署文件

将 Deployment、Service、Ingress 组合在一起:

k8s/frontend-deployment.yaml
# --- Deployment ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-app
namespace: frontend-prod
labels:
app: frontend
version: v1.2.0
spec:
replicas: 3
selector:
matchLabels:
app: frontend
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多多创建 1 个 Pod
maxUnavailable: 0 # 滚动更新时不允许有 Pod 不可用
template:
metadata:
labels:
app: frontend
version: v1.2.0
spec:
containers:
- name: frontend
image: registry.example.com/frontend:v1.2.0
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 30
---
# --- Service ---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
namespace: frontend-prod
spec:
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 80
---
# --- Ingress ---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend-ingress
namespace: frontend-prod
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: frontend-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80

第三步:部署与验证

# 应用所有 K8s 资源
kubectl apply -f k8s/frontend-deployment.yaml

# 查看 Deployment 状态
kubectl get deployment frontend-app -n frontend-prod

# 查看 Pod 状态
kubectl get pods -n frontend-prod -l app=frontend

# 查看 Service
kubectl get svc frontend-service -n frontend-prod

# 查看 Ingress
kubectl get ingress frontend-ingress -n frontend-prod

滚动更新与回滚

滚动更新

滚动更新(Rolling Update)是 K8s 默认的部署策略,会逐步用新版本 Pod 替换旧版本 Pod,实现零停机发布

执行更新的两种方式:

# 方式一:直接修改镜像版本
kubectl set image deployment/frontend-app \
frontend=registry.example.com/frontend:v1.3.0 \
-n frontend-prod

# 方式二:修改 YAML 文件后 apply(推荐,可追踪变更)
kubectl apply -f k8s/frontend-deployment.yaml

# 查看更新状态
kubectl rollout status deployment/frontend-app -n frontend-prod

# 查看更新历史
kubectl rollout history deployment/frontend-app -n frontend-prod

回滚

当新版本出现问题时,可以快速回滚到上一个版本:

# 回滚到上一个版本
kubectl rollout undo deployment/frontend-app -n frontend-prod

# 回滚到指定版本
kubectl rollout undo deployment/frontend-app --to-revision=2 -n frontend-prod

# 查看指定版本的详细信息
kubectl rollout history deployment/frontend-app --revision=2 -n frontend-prod
要点

在 CI/CD 流水线中,建议使用 kubectl apply 配合 Git 版本控制来管理部署,这样可以通过 Git 历史追踪每次变更,并且可以用 git revert + kubectl apply 的方式实现回滚,做到 GitOps


水平自动扩缩(HPA)

HPA(Horizontal Pod Autoscaler)根据 CPU、内存等指标自动调整 Pod 副本数。对于前端 SSR 服务或 BFF 层,HPA 在流量波动时非常有用。

hpa-example.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend-hpa
namespace: frontend-prod
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend-app
minReplicas: 2 # 最少 2 个 Pod
maxReplicas: 10 # 最多 10 个 Pod
metrics:
# 基于 CPU 使用率
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 平均使用率达到 70% 时扩容
# 基于内存使用率
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60 # 扩容后稳定 60 秒再评估
policies:
- type: Pods
value: 2 # 每次最多增加 2 个 Pod
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300 # 缩容后稳定 5 分钟再评估
policies:
- type: Pods
value: 1 # 每次最多减少 1 个 Pod
periodSeconds: 120
# 查看 HPA 状态
kubectl get hpa frontend-hpa -n frontend-prod

# 输出示例:
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# frontend-hpa Deployment/frontend 45%/70%, 30%/80% 2 10 3
补充

HPA 依赖 Metrics Server 收集资源指标。如果集群中没有安装 Metrics Server,HPA 将无法工作。可以通过 kubectl top nodeskubectl top pods 来验证 Metrics Server 是否正常运行。


ConfigMap 和 Secret 管理配置

前端项目经常需要根据环境切换 API 地址、Feature Flag 等配置。K8s 的 ConfigMapSecret 提供了配置与代码分离的能力。

ConfigMap -- 非敏感配置

configmap-example.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-config
namespace: frontend-prod
data:
API_BASE_URL: "https://api.example.com"
CDN_URL: "https://cdn.example.com"
FEATURE_NEW_DASHBOARD: "true"
# 也可以存储整个配置文件
nginx.conf: |
server {
listen 80;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}

Secret -- 敏感配置

secret-example.yaml
apiVersion: v1
kind: Secret
metadata:
name: frontend-secret
namespace: frontend-prod
type: Opaque
data:
# 值需要 Base64 编码
SENTRY_DSN: aHR0cHM6Ly9leGFtcGxlQHNlbnRyeS5pby8xMjM=
API_KEY: c2VjcmV0LWFwaS1rZXk=
注意

K8s Secret 默认只是 Base64 编码,并非加密。在生产环境中,建议结合 Sealed SecretsExternal Secrets Operator 或云厂商的密钥管理服务来安全管理敏感数据。

在 Deployment 中使用配置

deployment-with-config.yaml
spec:
containers:
- name: frontend
image: registry.example.com/frontend:v1.2.0
ports:
- containerPort: 80
# 方式一:注入为环境变量
env:
- name: API_BASE_URL
valueFrom:
configMapKeyRef:
name: frontend-config
key: API_BASE_URL
- name: SENTRY_DSN
valueFrom:
secretKeyRef:
name: frontend-secret
key: SENTRY_DSN
# 方式二:挂载为文件
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: frontend-config
items:
- key: nginx.conf
path: nginx.conf

在前端构建阶段,可以通过 TypeScript 脚本读取环境变量并生成运行时配置文件:

scripts/generate-config.ts
import { writeFileSync } from 'node:fs';

interface RuntimeConfig {
apiBaseUrl: string;
cdnUrl: string;
sentryDsn: string;
features: Record<string, boolean>;
}

// 从环境变量读取配置
const config: RuntimeConfig = {
apiBaseUrl: process.env.API_BASE_URL ?? 'http://localhost:3000',
cdnUrl: process.env.CDN_URL ?? '',
sentryDsn: process.env.SENTRY_DSN ?? '',
features: {
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
},
};

// 写入 JSON 文件供前端运行时加载
writeFileSync(
'./public/config.json',
JSON.stringify(config, null, 2),
);

console.log('Runtime config generated:', config);

Helm Chart 包管理

Helm 是 K8s 的包管理器,类似于前端的 npm/pnpm。它将一组 K8s 资源打包成 Chart,支持模板化、版本管理和依赖管理。

Helm Chart 目录结构

frontend-chart/
Chart.yaml # Chart 元信息(名称、版本等)
values.yaml # 默认配置值
values-staging.yaml # staging 环境配置覆盖
values-prod.yaml # 生产环境配置覆盖
templates/ # K8s 资源模板
deployment.yaml
service.yaml
ingress.yaml
hpa.yaml
configmap.yaml
_helpers.tpl # 模板辅助函数

Chart.yaml

frontend-chart/Chart.yaml
apiVersion: v2
name: frontend-app
description: A Helm chart for frontend application
type: application
version: 0.1.0 # Chart 版本
appVersion: "1.2.0" # 应用版本

values.yaml -- 可配置参数

frontend-chart/values.yaml
replicaCount: 2

image:
repository: registry.example.com/frontend
tag: "latest"
pullPolicy: IfNotPresent

service:
type: ClusterIP
port: 80

ingress:
enabled: true
className: nginx
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: frontend-tls
hosts:
- app.example.com

resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi

autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70

config:
apiBaseUrl: "https://api.example.com"
cdnUrl: "https://cdn.example.com"

模板文件示例

frontend-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "frontend-app.fullname" . }}
labels:
{{- include "frontend-app.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "frontend-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "frontend-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 80
resources:
{{- toYaml .Values.resources | nindent 12 }}

Helm 常用命令

# 安装 Chart
helm install frontend ./frontend-chart -n frontend-prod

# 使用指定环境配置安装
helm install frontend ./frontend-chart \
-f frontend-chart/values-prod.yaml \
-n frontend-prod

# 升级
helm upgrade frontend ./frontend-chart \
--set image.tag=v1.3.0 \
-n frontend-prod

# 回滚
helm rollback frontend 1 -n frontend-prod

# 卸载
helm uninstall frontend -n frontend-prod

# 查看已安装的 Release
helm list -n frontend-prod

# 模板渲染预览(不实际部署)
helm template frontend ./frontend-chart -f values-prod.yaml
要点

在 CI/CD 中,Helm 是最常用的部署方式。通过不同的 values.yaml 文件区分环境配置,用 helm upgrade --install 实现幂等部署(不存在则安装,已存在则升级)。


K8s vs Docker Compose 对比

前端工程师在本地开发时通常使用 Docker Compose,而在生产环境使用 K8s。两者的定位和能力差异很大:

特性Docker ComposeKubernetes
定位本地开发与测试生产级容器编排
规模单机多节点集群
服务发现基于 DNS(容器名)Service + DNS(CoreDNS)
负载均衡无内建支持Service 内建 L4 负载均衡
自动扩缩不支持HPA 水平自动扩缩
滚动更新不支持零停机内建滚动更新
自动恢复仅 restart policy自动重启 + 重新调度
配置管理.env 文件ConfigMap + Secret
存储管理volumesPV + PVC + StorageClass
网络策略简单网络模型NetworkPolicy 精细控制
包管理Helm Chart
配置文件docker-compose.yml多个 YAML / Helm Chart
学习成本中高
适用场景开发、测试、小型项目生产、大型项目、微服务

一个典型的等价对比:

docker-compose.yml(本地开发)
version: '3.8'
services:
frontend:
build: .
ports:
- "3000:80"
environment:
- API_BASE_URL=http://api:3001
depends_on:
- api

api:
image: backend-api:latest
ports:
- "3001:3001"
environment:
- DATABASE_URL=postgresql://db:5432/myapp

db:
image: postgres:16-alpine
environment:
- POSTGRES_PASSWORD=devpassword
volumes:
- pgdata:/var/lib/postgresql/data

volumes:
pgdata:

对应的 K8s 部署需要 Deployment + Service + Ingress + ConfigMap + Secret 多个资源文件,但获得了生产级别的高可用、自动扩缩和滚动更新能力。


前端工程师需要了解的 K8s 知识边界

作为前端工程师,不需要成为 K8s 运维专家,但需要掌握以下知识边界:

必须掌握

  • Dockerfile 编写:多阶段构建、镜像优化
  • 基本概念:Pod、Deployment、Service、Ingress、Namespace
  • kubectl 基本操作:查看资源状态、查看日志、进入容器调试
  • CI/CD 流程:理解从代码提交到服务上线的全流程
  • 环境变量与配置:ConfigMap、Secret 的使用

了解即可

  • HPA 自动扩缩:知道原理,能看懂配置
  • Helm Chart:能使用现有 Chart,能修改 values.yaml
  • 滚动更新与回滚:知道命令,理解流程
  • 资源限制:requests、limits 的含义
  • 健康检查:readinessProbe、livenessProbe 的作用

交给运维/SRE

  • 集群搭建与升级
  • 网络策略(NetworkPolicy)配置
  • 存储方案(PV/PVC/StorageClass)
  • RBAC 权限管理
  • 集群监控告警(Prometheus、Grafana)
  • Service Mesh(Istio)

常用 kubectl 命令

# ============ 查看资源 ============
# 查看 Pod 列表
kubectl get pods -n frontend-prod
# 查看 Pod 详细信息(排查问题必备)
kubectl describe pod <pod-name> -n frontend-prod
# 查看所有资源
kubectl get all -n frontend-prod

# ============ 日志 ============
# 查看 Pod 日志
kubectl logs <pod-name> -n frontend-prod
# 实时追踪日志(类似 tail -f)
kubectl logs -f <pod-name> -n frontend-prod
# 查看前一个容器的日志(容器重启后查看崩溃原因)
kubectl logs <pod-name> --previous -n frontend-prod

# ============ 调试 ============
# 进入容器(类似 docker exec)
kubectl exec -it <pod-name> -n frontend-prod -- /bin/sh
# 端口转发到本地(调试服务)
kubectl port-forward svc/frontend-service 8080:80 -n frontend-prod
# 在浏览器访问 http://localhost:8080 即可查看

# ============ 部署操作 ============
# 应用配置
kubectl apply -f k8s/
# 删除资源
kubectl delete -f k8s/
# 扩缩容
kubectl scale deployment frontend-app --replicas=5 -n frontend-prod

# ============ 上下文管理 ============
# 查看当前上下文(连接的集群)
kubectl config current-context
# 切换上下文
kubectl config use-context production-cluster
# 设置默认 Namespace
kubectl config set-context --current --namespace=frontend-prod

在前端项目的 package.json 中,可以添加便捷脚本:

scripts/k8s-helpers.ts
import { execSync } from 'node:child_process';

interface K8sConfig {
namespace: string;
deployment: string;
registry: string;
imageName: string;
}

const config: K8sConfig = {
namespace: 'frontend-prod',
deployment: 'frontend-app',
registry: 'registry.example.com',
imageName: 'frontend',
};

function getVersion(): string {
// 从 package.json 读取版本号作为镜像 tag
const pkg = JSON.parse(
execSync('cat package.json').toString()
);
return pkg.version as string;
}

function deploy(): void {
const version = getVersion();
const image = `${config.registry}/${config.imageName}:v${version}`;

console.log(`Deploying ${image} to ${config.namespace}...`);

// 构建并推送镜像
execSync(`docker build -t ${image} .`, { stdio: 'inherit' });
execSync(`docker push ${image}`, { stdio: 'inherit' });

// 更新 K8s Deployment 镜像
execSync(
`kubectl set image deployment/${config.deployment} ` +
`frontend=${image} -n ${config.namespace}`,
{ stdio: 'inherit' }
);

// 等待部署完成
execSync(
`kubectl rollout status deployment/${config.deployment} -n ${config.namespace}`,
{ stdio: 'inherit' }
);

console.log(`Successfully deployed ${image}`);
}

function rollback(): void {
execSync(
`kubectl rollout undo deployment/${config.deployment} -n ${config.namespace}`,
{ stdio: 'inherit' }
);
console.log('Rollback completed');
}

// 命令行参数处理
const command = process.argv[2];
if (command === 'deploy') {
deploy();
} else if (command === 'rollback') {
rollback();
} else {
console.log('Usage: npx tsx scripts/k8s-helpers.ts [deploy|rollback]');
}

常见面试问题

Q1: K8s 中 Pod、Deployment、Service 之间的关系是什么?

答案

这三者的关系是层层递进、各司其职的:

  • Pod 是最小部署单元,包含一个或多个容器,直接运行应用。Pod 的 IP 是临时的,重启后会变化。
  • Deployment 是 Pod 的控制器,负责:
    • 维护指定数量的 Pod 副本
    • 滚动更新:逐步替换旧版本 Pod
    • 自动恢复:Pod 异常时自动创建新的
    • 版本回滚:支持回退到历史版本
  • Service 为 Deployment 管理的一组 Pod 提供稳定的访问入口:
    • 固定的 Cluster IP 和 DNS 名称(如 frontend-service.frontend-prod.svc.cluster.local
    • 在多个 Pod 之间做负载均衡
    • 通过 selector 标签与 Pod 关联

简单类比:Deployment 是"部门主管"管理团队(Pod),Service 是"前台接待"统一接收请求并分配给团队成员。

关键配置对应关系:

# Deployment 通过 template.metadata.labels 给 Pod 打标签
Deployment.spec.template.metadata.labels:
app: frontend

# Service 通过 selector 选择标签匹配的 Pod
Service.spec.selector:
app: frontend # 与 Pod 标签一致

Q2: 前端项目如何实现零停机部署?

答案

零停机部署依赖 K8s 的滚动更新机制和健康检查配合工作:

1. 配置滚动更新策略:

零停机部署关键配置
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新时最多多创建 1 个新 Pod
maxUnavailable: 0 # 不允许有 Pod 不可用(关键!)
template:
spec:
containers:
- name: frontend
image: registry.example.com/frontend:v1.3.0
# 就绪探针:新 Pod 通过检查后才接收流量
readinessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 5
periodSeconds: 5
# 存活探针:持续检测容器健康状态
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 30
# 优雅终止:给旧 Pod 时间处理完已有请求
terminationGracePeriodSeconds: 30

2. 零停机的完整流程:

步骤行为说明
1创建新 PodK8s 创建一个新版本 Pod
2就绪检查readinessProbe 检测新 Pod 是否就绪
3加入 Service新 Pod 通过检查后,Service 将流量导入
4停止旧 Pod旧 Pod 从 Service 中移除,不再接收新请求
5优雅终止旧 Pod 在 terminationGracePeriodSeconds 内处理完已有请求
6循环替换重复以上步骤直到所有旧 Pod 被替换

3. 关键要素总结:

  • maxUnavailable: 0 确保始终有足够的 Pod 处理请求
  • readinessProbe 确保新 Pod 完全就绪后才接收流量
  • terminationGracePeriodSeconds 确保旧 Pod 优雅退出
  • 前端静态资源带 hash 指纹避免缓存问题(如 app.abc123.js

Q3: K8s 和 Docker Compose 的核心区别是什么?什么场景用哪个?

答案

两者定位完全不同,Docker Compose 面向单机开发环境,K8s 面向生产级容器编排

维度Docker ComposeKubernetes
运行环境单台机器多节点集群
高可用无,单机故障即服务中断Pod 自动重启 + 重新调度到其他节点
负载均衡无内建支持Service 内建 L4 负载均衡
自动扩缩HPA 根据 CPU/内存自动扩缩
滚动更新需停机重启零停机滚动更新
服务发现容器名 DNS 解析Service DNS + CoreDNS
配置管理.env 文件ConfigMap + Secret(支持热更新)
部署复杂度低,一个 YAML 文件高,多个资源文件或 Helm Chart

使用场景建议:

选择策略
type Environment = 'local-dev' | 'ci-test' | 'staging' | 'production';

function chooseOrchestration(env: Environment): string {
switch (env) {
case 'local-dev':
// 本地开发:Docker Compose 启动前后端 + 数据库
return 'Docker Compose';
case 'ci-test':
// CI 中运行集成测试:Docker Compose 快速启动依赖
return 'Docker Compose';
case 'staging':
// 预发环境:与生产保持一致用 K8s
return 'Kubernetes';
case 'production':
// 生产环境:K8s 提供高可用、自动扩缩
return 'Kubernetes';
}
}

核心总结:Docker Compose 解决的是"如何方便地在本地启动多个服务",K8s 解决的是"如何在生产环境可靠地运行和管理大量容器"。两者互补而非竞争 -- 开发用 Compose,部署用 K8s。


相关链接