Kubernetes 基础
问题
Kubernetes(K8s)是什么?前端工程师为什么需要了解 Kubernetes?它的核心概念和架构是怎样的?如何将前端项目部署到 K8s 集群中?
答案
Kubernetes(简称 K8s)是 Google 开源的容器编排平台,用于自动化容器化应用的部署、扩缩和管理。随着云原生和 DevOps 的普及,前端工程师越来越多地参与到 CI/CD 流水线和部署环节中,掌握 K8s 基础知识已经成为前端工程化能力的重要组成部分。
为什么前端工程师需要了解 K8s
- CI/CD 流水线:前端项目的构建、测试、部署往往在 K8s 集群中运行
- 微前端架构:不同子应用可能作为独立的 K8s 服务部署
- SSR/BFF 服务:Next.js、Nuxt.js 等 SSR 应用本质上是 Node.js 服务,需要容器化部署
- 环境管理:开发、测试、预发、生产环境通过 K8s Namespace 隔离
- 故障排查:了解 K8s 有助于快速定位线上问题(Pod 崩溃、服务不可达等)
K8s 核心概念
Pod -- 最小部署单元
Pod 是 K8s 中最小的可部署单元,一个 Pod 可以包含一个或多个紧密关联的容器。Pod 中的容器共享网络命名空间(同一个 IP 地址)和存储卷。
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 部署。
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 之间做负载均衡。
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。它是前端项目对外暴露的关键组件。
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 提供了集群级别的资源隔离,常用于隔离不同环境或不同团队的资源。
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-apiserver | K8s 的"前端入口",所有操作都通过它 | 类似于 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)来优化前端镜像体积:
# 第一阶段:构建
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 路由:
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 组合在一起:
# --- 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 在流量波动时非常有用。
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 nodes 和 kubectl top pods 来验证 Metrics Server 是否正常运行。
ConfigMap 和 Secret 管理配置
前端项目经常需要根据环境切换 API 地址、Feature Flag 等配置。K8s 的 ConfigMap 和 Secret 提供了配置与代码分离的能力。
ConfigMap -- 非敏感配置
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 -- 敏感配置
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 Secrets、External Secrets Operator 或云厂商的密钥管理服务来安全管理敏感数据。
在 Deployment 中使用配置
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 脚本读取环境变量并生成运行时配置文件:
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
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 -- 可配置参数
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"
模板文件示例
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 Compose | Kubernetes |
|---|---|---|
| 定位 | 本地开发与测试 | 生产级容器编排 |
| 规模 | 单机 | 多节点集群 |
| 服务发现 | 基于 DNS(容器名) | Service + DNS(CoreDNS) |
| 负载均衡 | 无内建支持 | Service 内建 L4 负载均衡 |
| 自动扩缩 | 不支持 | HPA 水平自动扩缩 |
| 滚动更新 | 不支持零停机 | 内建滚动更新 |
| 自动恢复 | 仅 restart policy | 自动重启 + 重新调度 |
| 配置管理 | .env 文件 | ConfigMap + Secret |
| 存储管理 | volumes | PV + PVC + StorageClass |
| 网络策略 | 简单网络模型 | NetworkPolicy 精细控制 |
| 包管理 | 无 | Helm Chart |
| 配置文件 | docker-compose.yml | 多个 YAML / Helm Chart |
| 学习成本 | 低 | 中高 |
| 适用场景 | 开发、测试、小型项目 | 生产、大型项目、微服务 |
一个典型的等价对比:
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 中,可以添加便捷脚本:
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 关联
- 固定的 Cluster IP 和 DNS 名称(如
简单类比: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 | 创建新 Pod | K8s 创建一个新版本 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 Compose | Kubernetes |
|---|---|---|
| 运行环境 | 单台机器 | 多节点集群 |
| 高可用 | 无,单机故障即服务中断 | 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。