Docker镜像构建规范与多阶段构建优化
DevOps实践的核心在于将应用部署、扩缩容、故障恢复全流程自动化。Kubernetes容器编排已成为这一领域的事实标准,从Docker镜像构建到K8s集群运维,每个环节都需要精确配置。本文以一个Java Spring Boot微服务项目为例,覆盖完整的CI/CD流水线和监控告警体系搭建。
Docker镜像质量直接影响Kubernetes容器编排的部署效率和运行稳定性。生产环境的镜像构建需要遵循几个原则:镜像体积最小化、分层缓存利用最大化、构建过程可重复。多阶段构建是控制镜像体积最有效的手段。
多阶段Dockerfile示例:
# ---- 编译阶段 ----
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
# ---- 运行阶段 ----
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /build/target/app.jar /app/app.jar
RUN addgroup -S appgrp && adduser -S appuser -G appgrp
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/actuator/health | grep -q UP || exit 1
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "/app/app.jar"]
编译阶段用完整的Maven镜像,运行阶段只装JRE,最终镜像体积从800MB压缩到约180MB。COPY pom.xml单独放一层是为了利用Docker分层缓存——pom不变时依赖下载层直接命中缓存,不会重复执行。
Kubernetes集群初始化与网络插件配置
集群搭建以kubeadm方式为例,测试环境使用3台机器(1 master + 2 worker)。所有节点前置配置:
# 关闭swap
swapoff -a && sed -i '/swap/d' /etc/fstab
# 内核参数调整
cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
# 安装容器运行时(containerd)
yum install -y containerd.io
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl enable containerd --now
# 安装kubeadm、kubelet、kubectl
cat > /etc/yum.repos.d/kubernetes.repo << 'EOF'
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm/
enabled=1
gpgcheck=0
EOF
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet
Master节点初始化:
kubeadm init \
--apiserver-advertise-address=192.168.30.10 \
--pod-network-cidr=10.244.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.30.0
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
安装Calico网络插件:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/custom-resources.yaml
# 等待Calico Pod就绪
kubectl get pods -n calico-system -w
Worker节点加入集群:
# 在master上获取加入命令
kubeadm token create --print-join-command
# 在worker节点执行返回的kubeadm join命令
kubeadm join 192.168.30.10:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx
Deployment与Service部署配置
应用部署YAML(deployment.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
labels:
app: order-service
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:v2.1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: JAVA_OPTS
value: "-XX:MaxRAMPercentage=75.0 -XX:+UseG1GC"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
failureThreshold: 3
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 15"]
terminationGracePeriodSeconds: 60
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: production
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
几个关键配置项的实战要点:
滚动更新策略:maxUnavailable: 1和maxSurge: 1的组合意味着更新过程中始终保持至少2个可用Pod,同时最多多出1个Pod。这个配置在3副本场景下既保证可用性又控制资源消耗。
优雅停机:preStop钩子中的sleep 15配合terminationGracePeriodSeconds: 60。Kubernetes停止Pod时先发SIGTERM信号,但Service的endpoint更新有传播延迟。sleep 15让Pod在收到SIGTERM后继续服务15秒,等endpoint更新传播完毕,避免请求打到正在关闭的Pod上。
探针配置:livenessProbe判断容器是否需要重启,readinessProbe判断容器是否可以接收流量。两者路径分开——liveness检查应用进程存活,readiness检查依赖是否ready。
CI/CD流水线自动化部署
以GitLab CI为例,配置从代码提交到自动部署的流水线(.gitlab-ci.yml):
stages:
- build
- test
- package
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
build:
stage: build
image: maven:3.9-eclipse-temurin-17
script:
- mvn package -DskipTests -B
artifacts:
paths:
- target/*.jar
expire_in: 1 hour
test:
stage: test
image: maven:3.9-eclipse-temurin-17
script:
- mvn test -B
only:
- main
- develop
package:
stage: package
image: docker:24
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
- docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
deploy_staging:
stage: deploy
image: bitnami/kubectl:1.30
script:
- kubectl config use-context staging
- kubectl set image deployment/order-service
order-service=$IMAGE_TAG -n staging
- kubectl rollout status deployment/order-service -n staging
environment:
name: staging
only:
- main
流水线拆分为build、test、package、deploy四个阶段,每个阶段在独立容器中执行。package阶段使用Docker-in-Docker构建镜像并推送到Registry。deploy阶段通过kubectl set image触发Kubernetes滚动更新,rollout status命令阻塞直到更新完成或超时。
监控告警体系搭建
监控告警是SRE稳定性工程的基础设施。推荐使用Prometheus + Grafana + AlertManager组合:
# 监控命名空间
kubectl create namespace monitoring
# 通过Helm部署Prometheus Stack
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
-n monitoring \
--set grafana.service.type=NodePort \
--set grafana.service.nodePort=30300 \
--set prometheus.prometheusSpec.retention=15d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=standard \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi
关键告警规则(PrometheusRule):
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: app-alerts
namespace: monitoring
spec:
groups:
- name: application.rules
rules:
- alert: PodCrashLooping
expr: increase(kube_pod_container_status_restarts_total[1h]) > 5
for: 10m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} 频繁重启"
description: "命名空间 {{ $labels.namespace }} 中的 Pod {{ $labels.pod }} 在1小时内重启超过5次"
- alert: HighCPUUsage
expr: |
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace) /
sum(kube_pod_container_resource_limits{resource="cpu"}) by (pod, namespace) > 0.85
for: 10m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.pod }} CPU使用率超过85%"
- alert: HighMemoryUsage
expr: |
sum(container_memory_working_set_bytes{container!=""}) by (pod, namespace) /
sum(kube_pod_container_resource_limits{resource="memory"}) by (pod, namespace) > 0.90
for: 5m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} 内存使用率超过90%"
- alert: ServiceUnavailable
expr: kube_endpoint_address_available / kube_endpoint_address_not_available < 1
for: 2m
labels:
severity: critical
annotations:
summary: "Service {{ $labels.service }} 有端点不可用"
故障应急响应与混沌工程实践
日志分析是故障应急的第一信息源。在Kubernetes环境中,集中化日志收集方案用Fluent Bit + Elasticsearch + Kibana:
# Fluent Bit DaemonSet部署,收集所有节点容器日志
kubectl apply -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/output/elasticsearch/fluent-bit-configmap.yaml
kubectl apply -f https://raw.githubusercontent.com/fluent/fluent-bit-kubernetes-logging/master/output/elasticsearch/fluent-bit-ds.yaml
混沌工程用于主动验证高可用能力。使用Chaos Mesh向集群注入故障:
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: kill-random-pod
namespace: chaos-testing
spec:
action: pod-kill
mode: one
selector:
namespaces:
- production
labelSelectors:
"app": "order-service"
scheduler:
cron: "@every 30m"
这个配置每30分钟随机杀死一个order-service Pod,验证Kubernetes的自愈机制和业务降级逻辑是否生效。混沌工程实验的目的是在故障真实发生前暴露系统弱点,而不是制造混乱。每次实验需要明确假设、可控范围和回退方案。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-rong-qi-bian-pai-bu-shu-shi-zhan-cong-ji-qun-chu/