资讯动态

微服务容器化实战:Docker与Kubernetes部署全攻略

发布时间:2026/10/19 10:16:10 来源:尧图企业网站定制
微服务容器化改造进行到一半的时候我就明显感觉到Docker加Kubernetes这套组合已经不是可选项而是必选项。刚开始团队还在用手工脚本部署服务环境一多就乱套测试环境跑得好好的生产上就是起不来折腾半天发现是基础镜像版本不一样。后来我花了两周时间把订单域的几个服务全部容器化再迁到Kubernetes上统一调度交付节奏才真正稳定下来。这篇文章就围绕这次实战把Docker和Kubernetes的落地过程拆开讲清楚从镜像构建、本地编排、集群部署到线上稳定性每一步都给配置、给命令、给排查思路适合正在做微服务改造的开发者、运维和架构师参考。1. 微服务容器化的整体设计与思路拆解1.1 为什么微服务必须走容器化这条路单体应用时代部署就是打一个包丢到一台机器上环境问题虽然烦但可控。一旦拆成微服务问题就变了订单服务用Java 11用户服务用Node 18商品服务还需要特定版本的Redis客户端依赖这些服务要跑在同一套测试环境里光环境冲突就够喝一壶。容器化最大的价值不是“跑起来”而是把运行环境、依赖、配置和代码一起打包成镜像让每个服务在任意机器上都能以完全相同的方式运行。我见过太多人把容器和虚拟机混为一谈。虚拟机虚拟的是硬件容器虚拟的是操作系统进程容器共享宿主机内核所以启动速度快、资源开销小。更重要的是镜像的分层机制基础层、依赖层、应用层可以复用和缓存构建一次后面几乎秒推。这种“一次构建、处处运行”的特性正好补上微服务交付链路里最薄弱的一环环境一致性。当然容器不是银弹。它解决了运行环境的一致性却没有解决服务怎么调度、怎么扩容、怎么自愈的问题。这就要交给Kubernetes来做。当时我把订单服务容器化之后测试环境倒是能跑了但是三个副本想滚动更新就得手动操作好几步而且新版本启动失败还会影响线上流量这时候才开始体会到容器化和云原生部署是两件事必须一起考虑。1.2 参考架构某商城订单域的服务拆分这次实战我拿一个模拟的电商系统来举例场景是某商城的订单域包含五个核心微服务和一个统一入口。服务拆分如图表所示每个服务独立部署、独立演进通过接口通信。服务名称主要职责技术栈暴露端口依赖组件gateway统一流量入口、路由、鉴权Spring Cloud Gateway8080Redisuser-service用户信息查询与校验Spring Boot8081MySQLproduct-service商品库存查询与扣减Spring Boot8082MySQLorder-service订单创建、查询与状态流转Spring Boot8083MySQL、Redispayment-service支付回调与订单支付状态同步Spring Boot8084MySQLmessage-service异步消息推送与事件通知Node.js8085Kafka这个拆分不是一步到位的。最开始我们尝试把所有服务塞进一台虚拟机里结果用户服务发版要重启整个环境其他服务全部跟着抖。后来把每个服务装进独立容器端口冲突解决了但新的问题又来了六个服务之间要互相找到对方的地址订单服务调用支付服务到底该连哪个IP服务扩容之后旧节点下线调用方还在往旧地址发请求。这个时候再往后走就必须引入Kubernetes的服务发现和负载均衡能力。从这个架构也能看出容器化的一个关键原则每个服务都应该是一个独立、无状态、可替换的容器副本。状态数据交给MySQL、Redis、Kafka这类中间件承载服务本身保持无状态这样才能任意伸缩。后面配置管理、滚动更新、自动扩缩容全都依赖这个前提。1.3 云原生部署到底要解决什么核心问题云原生部署的核心思路是把基础设施的操作从“手动命令”变成“声明式配置”。Kubernetes里你只需要告诉它“我想要3个订单服务副本镜像版本是1.0.0”集群会自动去创建Pod、调度节点、维护副本数、处理网络转发。它不会一直保持某个状态而是持续对比“期望状态”和“实际状态”出现偏差就自动纠正。这套机制解决了我前面踩过的几个坑服务发现不用再手工维护IP列表Service对象会给一组Pod一个稳定的虚拟IP滚动更新时Kubernetes会先启动新版本Pod等它通过健康检查后再摘掉旧Pod最大限度降低对线上请求的影响Pod挂了会自动重建节点崩溃会把上面的Pod调度到别的节点这些都不需要运维半夜起来操作。Kubernetes的学习曲线不低但它的核心模型其实就几类工作负载、服务、配置、存储。把这几类掌握好日常部署已经够用。很多初学者一上来就去啃一大堆CRD和Operator反而容易迷失。我的建议是先抛开那些花哨的东西把Deployment、Service、Ingress、ConfigMap、Secret这几个基础对象搞透彻等真实项目跑起来之后再去慢慢接触更复杂的控制器。2. Docker 实战镜像构建与本地编排2.1 Makefile? 不是Dockerfile多阶段构建Docker实战里第一个绕不开的就是Dockerfile怎么写。很多新人喜欢一条FROM搞定比如直接用带Maven的镜像把服务跑起来镜像体积动辄800MB还不安全。我在这次订单服务上采用多阶段构建第一阶段编译第二阶段只保留最小运行时。# 第一阶段编译打包 FROM maven:3.8.6-eclipse-temurin-11 AS build WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn package -DskipTests # 第二阶段运行 FROM eclipse-temurin:11-jre WORKDIR /app COPY --frombuild /build/target/order-service.jar ./app.jar EXPOSE 8083 ENTRYPOINT [java, -jar, /app/app.jar]多阶段构建的好处一是在最终镜像里没有Maven、没有源码、没有编译产生的临时文件体积能少一大截二是阶段隔离第一阶段的构建过程出错不会污染最终产物。我第一次优化之后订单服务镜像从780MB降到了210MB左右部署传输和启动速度都明显改善。这里有个细节容易被忽略尽量把pom.xml单独COPY进来先执行依赖拉取再COPY源码。Docker构建是分层的每一条指令都会产生一层缓存如果源码变了但pom.xml没变依赖层还能直接命中缓存构建时间能从几分钟缩到几十秒。先把变化频率低的文件放前面是把构建缓存用到极致的核心技巧。2.2 镜像瘦身与构建规范体积小、可追溯、没坑镜像瘦身不只是为了省磁盘还直接影响拉取速度和攻击面。除了多阶段构建还要注意几件事。第一.dockerignore一定要写把target、.git、node_modules这类目录排除在外不然随便一点文件变动都会让缓存失效还会把不该进镜像的内容一并打包。target/ .git/ .idea/ *.log第二基础镜像tag不能漂移。如果写FROM maven:latest镜像更新之后再来构建很可能环境不一致昨天构建成功今天失败。锁定具体版本才能保证“可复现”。第三不要在镜像里安装多余工具比如vim、curl、bash调试类组件这些在运行时镜像里都不该出现排查问题有kubectl和logs命令就够了不需要进容器折腾。还有一个技巧是合并RUN命令。Dockerfile里每个RUN都会产生一层过多层会增加镜像层数有些层可能还带着中间缓存比如apt-get install之后如果不在同一层里清理/var/lib/apt/lists那些临时文件就会永久留在这层里。建议同类操作合并成一条RUN然后用连接最后清理缓存。2.3 本地联调Docker Compose的正确姿势Kubernetes部署之前本地联调离不开Docker Compose。我常用Compose把订单服务依赖的MySQL和Redis先起一张网服务在容器里启动直接通过服务名访问中间件。这种方式贴近生产环境又比堆K8s环境轻量得多。version: 3.8 services: mysql: image: mysql:8.0 container_name: order-mysql environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: order_db ports: - 3306:3306 volumes: - mysql_data:/var/lib/mysql healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 5s timeout: 3s retries: 12 redis: image: redis:7.0-alpine ports: - 6379:6379 order-service: build: ./order-service ports: - 8083:8080 environment: SPRING_PROFILES_ACTIVE: dev MYSQL_HOST: mysql REDIS_HOST: redis depends_on: mysql: condition: service_healthy redis: condition: service_started volumes: mysql_data:这里最容易踩的坑是depends_on。Compose的depends_on只能控制容器启动顺序不能保证依赖服务“可用”。默认情况下MySQL启动成功不等于能接受连接如果order-service一启动就去连数据库会连不上然后退出。解决方法是给MySQL配置healthcheck再在depends_on里加condition: service_healthy等服务探活通过之后才启动业务容器。Compose环境里有些习惯要尽早纠正。比如Dockerfile里把数据库地址写死换环境就得改镜像这是非常坏的做法。配置一定要通过环境变量或者配置文件注入Compose里用environment覆盖Kubernetes里用ConfigMap和Secret管理同一个镜像才能在不同环境里复用。3. Kubernetes集群规划与应用部署实战3.1 集群规划从零到可用的最小配置本地用Docker Compose跑通服务之后就要考虑上Kubernetes。集群的搭建方式有很多生产环境大多用托管集群省去etcd和Master的运维成本但如果要自己部署或者需要离线环境、自建机房就得理解节点规划。这次我以一套模拟项目的测试集群为例总共三个节点加一台存储机配置不算高但足够跑微服务。节点角色数量规格建议部署组件Master/控制面14C8Gkube-apiserver、scheduler、controller-manager、etcdWorker节点24C8Gkubelet、kube-proxy、容器运行时存储节点12C4G 500G磁盘NFS或其他共享存储生产环境Master至少要三台组成高可用etcd最好独立部署但模拟项目里一台Master跑通流程就够了。强调一点Worker节点的规格设计不能只看当前负载要预留未来扩容的空间尤其是CPU和内存压力节点一旦跑满调度就会非常惊险。部署完成之后第一件事就是验证集群组件状态用kubectl get nodes查看节点是否Ready用kubectl get pods -n kube-system确认核心组件都正常。如果Node是NotReady大概率是容器运行时没有装对或者kubelet没有拉到镜像这时候直接看节点描述信息kubectl describe node比瞎猜有效得多。3.2 三个核心资源对象Deployment、Service、IngressKubernetes里和业务部署最相关的就是Deployment、Service、Ingress三个对象。Deployment负责管理Pod副本Service负责提供稳定的访问入口Ingress负责把外部HTTP流量路由到Service。三者的关系可以理解成Deployment是你餐厅里的厨师团队Service是餐厅前台固定的接待电话Ingress是大门口按菜单指示方向的路牌。以order-service为例我先写DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: production spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: containers: - name: order-service image: registry.example.com/order-service:1.0.0 ports: - containerPort: 8080 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1 memory: 1Gi readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 20 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 15 envFrom: - configMapRef: name: order-config - secretRef: name: order-secret strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1这个文件里藏着大量细节。requests和limits不是随便写的requests给调度器看决定Pod被分到哪台节点limits给运行时看限制容器资源上限防止一个服务占满机器。两者必须同时配置只写limits不写requests会产生调度错乱只写requests不写limits可能失控。探针也很重要readinessProbe决定Pod是否接收流量livenessProbe决定是否重启容器两者的作用完全不同后面专门讲。接着是Service。Service的selector会匹配Deployment里定义的labelsPod的IP会发生变化但Service的虚拟IP和DNS名字保持稳定这样订单服务调用支付服务时只需要访问固定的服务名不需要关心后端Pod在哪里。apiVersion: v1 kind: Service metadata: name: order-service namespace: production spec: selector: app: order-service ports: - port: 80 targetPort: 8080 type: ClusterIPIngress则把外部访问统一收口。没有Ingress的集群里外部要访问服务只能把Service改成NodePort或者LoadBalancer每个服务一个端口难记且不安全。Ingress通过域名和路径把流量转发给后端Service让我能用一条规则管理所有微服务的对外入口。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gateway-ingress namespace: production spec: rules: - host: api.example.dev http: paths: - path: /orders pathType: Prefix backend: service: name: order-service port: number: 803.3 上线全流程从构建镜像到集群访问验证这部分是整条部署链路的实操记录。我从本地把镜像构建好推到内部镜像仓库然后部署到集群最后通过Ingress验证访问。整个过程用到的命令不算多但每一步都有讲究。# 构建并推送镜像 docker build -t registry.example.com/order-service:1.0.0 . docker push registry.example.com/order-service:1.0.0 # 创建命名空间并部署 kubectl create namespace production kubectl apply -n production -f deployment.yaml -f service.yaml -f ingress.yaml # 查看部署状态 kubectl get pods -n production kubectl get svc -n production kubectl get ingress -n production # 查看Pod日志 kubectl logs -n production -l apporder-service # 查看Ingress入口节点访问 curl -H Host: api.example.dev http://ingress节点IP/orders/12345如果本地要模拟域名访问可以在测试机器的hosts里把api.example.dev指向Ingress控制器所在的节点IP然后直接通过域名访问。不过真实生产环境通常有DNS解析和HTTPS证书这里只是演示最基本的路由方式。部署时我习惯先看Pod状态再去看日志。如果Pod一直是ContainerCreating先看描述信息里的事件比如镜像拉取失败、存储挂载失败、端口占用都能在这里直接看到如果Pod进入了Running但服务不通再用curl和logs逐层排查。不要盲目去看日志先确定故障在哪一层推导起来更快。3.4 滚动更新、版本回滚与发布参数调优服务不可能永远不更新Kubernetes发布最常用的就是滚动更新策略。使用kubectl set image就可以触发一次滚动更新集群会按照Deployment里定义的strategy逐步替换Pod。# 触发滚动更新 kubectl set image deployment/order-service order-serviceregistry.example.com/order-service:1.0.1 -n production # 查看更新状态 kubectl rollout status deployment/order-service -n production # 查看历史版本 kubectl rollout history deployment/order-service -n production # 回滚到上一个版本 kubectl rollout undo deployment/order-service -n production # 回滚到指定版本 kubectl rollout undo deployment/order-service -n production --to-revision2滚动更新的关键参数是maxUnavailable和maxSurge。我上面配置的是maxUnavailable: 0maxSurge: 1意味着更新过程中一个旧Pod都不会先停而是先创建一个新Pod等它成功启动并通过readiness探针之后再下线一个旧Pod循环往复保证整个发布过程中始终有足够的服务实例承接流量。这个配置适合流量较稳定的业务如果希望快速发版可以允许maxUnavailable为25%但可能出现短暂的容量下降。回滚可不是简单的“换个镜像再发布一次”它会把Deployment恢复到你选中的那个revision版本包括副本数、资源、探针等所有配置。这也是为什么发布前一定要提交完整的YAML而不是只改个镜像tag。只记录镜像tag不记录YAML变更回滚时很容易把环境配置也带偏。4. 线上稳定性配置管理、自动伸缩与健康检查4.1 ConfigMap与Secret配置不该跟着镜像走镜像要可复用配置就绝不能写死在镜像里。订单服务里数据库地址、Redis地址、告警阈值这些非敏感信息放在ConfigMap里数据库密码、第三方支付密钥这些敏感信息放在Secret里。Deployment通过envFrom或者volume挂载来引用它们做到配置与镜像分离。apiVersion: v1 kind: ConfigMap metadata: name: order-config namespace: production data: SPRING_PROFILES_ACTIVE: production MYSQL_HOST: mysql.middleware.svc.cluster.local REDIS_HOST: redis.middleware.svc.cluster.local ORDER_TIMEOUT_MS: 3000 --- apiVersion: v1 kind: Secret metadata: name: order-secret namespace: production type: Opaque data: MYSQL_PASSWORD: c2VjdXJlLXBhc3N3b3Jk关于Secret必须说明一点Secret默认只是Base64编码不是加密任何能看到集群etcd数据或者有相关RBAC权限的人都能解码出来。真正的敏感数据需要配合外部密钥管理服务或者K8s提供的加密选项生产环境不要直接裸存密码。很多团队在测试环境图省事把密码直接铺在明文环境变量里严格来说这是安全隐患规范的做法至少要做Base64编解码并限制Secret的访问权限。配置变更之后需要滚动重启服务才能生效这一步经常被忽略。如果ConfigMap里的数据改了但Pod里的进程还是用旧环境变量你以为改了其实没生效。可以用kubectl rollout restart deployment/order-service触发滚动重启让新配置真正落到所有Pod。4.2 HPA自动伸缩副本数不是拍脑袋定的Kubernetes自动伸缩的核心是HorizontalPodAutoscaler也就是HPA。它会周期性获取Pod的资源使用指标和设定的目标利用率对比然后自动调整Deployment的副本数。这里有个常见的误解HPA调整的是Pod副本数不是给单个Pod加CPU加内存垂直伸缩需要其他机制实现。apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: order-service-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: order-service minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60HPA计算的基准不是Pod的实际CPU总量而是相对于Pod请求值的利用率。举个例子如果容器requests.cpu是500m那么每个Pod的CPU使用达到300m时利用率就是60%。HPA尝试让所有Pod的平均利用率维持在60%附近如果连续一段时间超过目标副本数就会增加。具体的副本数计算公式大致是期望副本数等于当前副本数乘以当前利用率除以目标利用率但HPA实际还会考虑冷却窗口避免指标抖动导致频繁扩容缩容。使用HPA之前需要确认集群已经安装metrics-server否则kubectl top pods查不到指标HPA也拿不到数据。常见的坑是Pod没有设置requests导致HPA计算不到利用率或者只给Pod设置了极低的requests比如10m一有流量就触发扩容到最大副本数资源被浪费得很厉害。所以requests的配置要符合业务实际而不是为了让调度器好安排就给一个象征性的值。4.3 探针配置与优雅停机让发布无感知探针决定Kubernetes在什么时候认为一个Pod可用、什么时候需要重启。三类探针各司其职startupProbe管启动期适合启动很慢的服务给足时间别急着杀readinessProbe管流量接入只有通过之后Service才会把Pod加进后端列表livenessProbe管存活如果业务进程还在但核心链路已经不可用就通过重启恢复。三者不可混用尤其不要把livenessProbe和readinessProbe配置成同一个脆弱接口否则会出现流量还没停就重启容器的情况。readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 15 timeoutSeconds: 2 failureThreshold: 3 startupProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 10 periodSeconds: 5 failureThreshold: 60竞选一个比较隐蔽的问题容器收到SIGTERM退出的时候可能正在处理请求同时Service也已经把它从负载池里摘除了但摘除和停止之间有一个时间窗。如果容器瞬间退出这个窗口里的请求就会掉。解决办法是在容器里加preStop钩子让容器先睡几秒给正在处理的请求留出完成时间。lifecycle: preStop: exec: command: [/bin/sh, -c, sleep 5]同时还把terminationGracePeriodSeconds设为合理值比如30秒确保容器有足够时间优雅退出。这套组合拳打下来滚动发布过程中订单服务几乎没有出现过请求失败用户基本无感知。4.4 日志与监控最小实践线上运行没有监控就等于蒙眼开车。微服务场景里日志和监控要尽早接入不用一开始就上很重的方案但至少要做到两件事日志统一收集、指标可视化。容器运行的最大特点是Pod随时可能被重建日志如果写进容器内文件Pod一删连Log都没了所以日志必须写到标准输出由集群层统一收集。我建议先给Kubernetes装一套轻量的监控栈metrics-server负责采集节点和Pod资源数据Prometheus负责抓取业务指标Grafana负责展示。日志方面可以用Loki或者ELK按团队熟悉程度选择。接入之后设置几个核心告警Pod反复重启、节点磁盘使用率超过80%、HPA达到最大副本数还在持续增长、请求错误率突然上升。这些告警能让你在用户发现问题之前先发现问题。监控的另一个价值是倒推配置调优。我第一次给订单服务只能看到CPU在涨但看不出是业务流量涨了还是SQL慢查询导致CPU空转后来配上业务链路指标才能把扩容决策从“拍脑袋”变成“看数据”。5. 实战中的常见问题与排查技巧实录5.1 常见故障速查表这一节把我在容器化和Kubernetes部署中遇到的高频故障整理成一张速查表遇到问题时可以先查表定位方向再结合具体日志去验证。故障现象可能原因排查命令与手段Pod一直Pending节点资源不足、污点容忍不匹配、存储卷不可用kubectl describe pod镜像拉取失败ImagePullBackOff镜像不存在、私有仓库认证失败、网络不通kubectl describe pod、docker pull验证容器反复重启CrashLoopBackOff启动参数错误、探针失败、环境变量缺失kubectl logs、kubectl describe pod服务访问超时Service targetPort配置错、readiness探针失败、DNS异常kubectl get endpoints、kubectl exec进入容器验证Pod被OOMKilledlimits内存设置过小、业务内存泄漏kubectl describe pod、查看内存监控节点磁盘被写满容器日志无限增长、镜像堆积查看/var/lib/docker/containers日志、docker system prune这张表不是万能的但能帮你缩小排查范围。大多数问题的根因其实都在配置上比如镜像tag写错、环境变量没生效、探针路径不对等真正需要深入底层调试的比例很低。5.2 实录一服务一直CrashLoopBackOff怎么定位有一次测试环境里order-service发布后一直处于CrashLoopBackOff状态基础看板上一片红。首先用kubectl get pods确认状态再用kubectl logs查看业务日志。第一次看日志发现是数据库连接失败原因是ConfigMap里MYSQL_HOST写成了localhost容器内可不认识这个地址应该写集群内的服务名mysql.middleware.svc.cluster.local。修正配置之后Pod能启动了但隔了几分钟又开始重启。这次去看describe输出的事件发现readinessProbe的检测路径/actuator/health返回了404。原因是服务启动时还没有完全注册好上下文健康检查接口没起来initialDelaySeconds设得太短探针等不及就判定失败。后来把initialDelaySeconds调到20秒并增加了startupProbe让启动慢的问题不再被liveness探针误杀。从这里可以看出探针参数必须结合应用实际启动时间调整不能抄网上的配置就完事。5.3 实录二节点磁盘被日志写满的惨痛教训运行一段时间后某Worker节点突然报DiskPressure很多Pod被驱逐。登上去一看/var/lib/docker/containers目录下面堆了大量json日志文件单个容器日志已经涨到几个GB。这些日志是容器标准输出被Docker落盘产生的文件如果应用不打日志滚动、Kubernetes没限制日志大小它会无限增长直到撑爆磁盘。解决办法是在节点上按需配置日志轮转。使用Docker容器运行时的话在/etc/docker/daemon.json里加上log-driver和log-opts限制单个日志文件和保留份数。{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }如果是containerd运行时就在kubelet配置里设置containerLogMaxSize和containerLogMaxFiles。我后来还养成了定时巡检的习惯磁盘使用率超过80%就提前预警而不是等到节点被Pod压垮才去处理。日志很重要但日志文件也是需要治理的资源。5.4 实录三间歇性超时问题竟然出在Service配置有一次订单服务偶尔会超时几秒客户投诉不稳定。我先看业务日志发现超时集中在下游支付服务的调用但支付服务的Pod看起来都很健康。后来用kubectl get endpoints查看支付服务对应的Endpoint发现有些Pod的IP没有出现在列表里再一看发现是readinessProbe失败Pod虽然Running但没进入Ready状态Service把流量只转发给了少数几个就绪Pod导致这些Pod压力突然升高进而出现超时。修复探针配置后Endpoint列表恢复了完整超时问题很快就消失了。这件事给我的教训是诊断网络问题时不要只看Pod状态一定要看Service后端Endpoint是否健康Pod Running不代表它一定有资格接收流量。5.5 私有镜像仓库的认证问题镜像仓库如果需要认证集群拉取镜像时必须在Pod里配置imagePullSecrets。很多人会直接把镜像地址写进YAML集群却报ImagePullBackOff看事件提示拉取凭证不足。这时需要先创建Secret再把Secret名称加到Deployment的spec下。kubectl create secret docker-registry registry-key \ --docker-serverregistry.example.com \ --docker-usernameusername \ --docker-passwordpassword \ -n productionYAML里加一行spec: imagePullSecrets: - name: registry-key这里有一个好习惯把镜像拉取凭证放到命名空间级别通过RBAC控制权限而不是复制到每个Pod里。否则Secret失效时所有Deployment都要跟着改一遍运维效率极低。最后说点个人体会。容器化和Kubernetes这套体系真正的价值不是炫技而是把交付流程从“人肉运维”变成“声明式管理”。我踩过很多坑之后最大的感受是镜像tag必须有一套明确规范不要用latest满天飞资源requests和limits必须认真评估别让调度器在边缘疯狂试探探针配置一定要贴合应用实际启动时间否则自愈机制反而会变成事故制造机。这些细节在上线前统一好后面运维会省心得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑