ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

运维实战进阶:Docker、K8s、CI/CD与监控排错全解析

运维实战进阶:Docker、K8s、CI/CD与监控排错全解析 1. 命令与脚本运维的基本功1.1 高频命令的真实用法很多人把“Linux常用命令”当成面试题背但实际上运维日常用到的命令就那几十条关键在于用得够不够“透”。我见过不少刚转运维的朋友遇到环境问题第一反应是去查监控面板或者在网上搜图形化工具结果绕了一大圈不如一条命令在现场看得清楚。以最基础的排查场景来说端口占用、进程状态、磁盘空间、大文件定位这四个问题几乎每周都会遇到。查端口占用不要再用netstat了虽然它还在但ss的输出更快、信息更全一条ss -lntp能看到监听端口和对应进程。查进程用ps -ef配合grep但更建议用pgrep -f按完整命令行匹配避免进程名太短误杀。磁盘满了不要急着删先df -h看挂载点再用du -sh /目录/* | sort -rh | head逐层往下找把“哪个目录吃了磁盘”这件事一次性定位清楚。日志排查也有讲究。tail -f跟踪日志是最常用的但如果是系统刚启动就异常要看journalctl -u 服务名 --no-pager -n 200比直接翻文件方便得多尤其是使用systemd管理的服务。想知道某段时间内有没有报错可以journalctl --since 1 hour ago -p err这比肉眼翻几百行日志靠谱得多。另外还有一个容易被忽略的细节用到管道的时候要注意前后命令的退出码。比如grep没匹配到任何内容默认返回非0如果用在脚本里就会导致脚本提前退出。类似这种“命令没报错但结果不对”的情况恰恰是运维脚本里最常见的坑。1.2 脚本化思维把重复劳动交给定时任务命令是砖脚本才是墙。运维日常的备份、日志清理、健康检查、状态上报几乎都可以脚本化。很多人写脚本是“一次性”的临时解决问题用完就丢下次遇到再手敲一遍。这种习惯非常消耗精力我个人的建议是只要同一个操作用了两次以上就值得整理成脚本放进工具库。写脚本前先想清楚三件事一是什么时候运行二是在哪里运行三是失败时怎么办。以日志清理为例生产环境日志增长快如果不及时清理磁盘很容易被打满。一个简单的清理脚本核心逻辑就是“按天统计、按保留天数删除”但有几个容易踩的坑要注意路径不能用相对路径因为cron执行时的环境变量和手动执行不一样删除操作前要提前做好目录校验避免路径写错导致误删脚本输出一定要落到日志文件里这样出问题时能查证。我这边常用的备份脚本结构比较简单大概就是这样#!/bin/bash set -euo pipefail BACKUP_DIR/data/backup SOURCE_DIR/var/lib/mysql RETENTION_DAYS7 LOG_FILE/var/log/backup.log if [ ! -d $SOURCE_DIR ]; then echo $(date %F %T) ERROR: source dir not found $LOG_FILE exit 1 fi tar czf $BACKUP_DIR/backup_$(date %F_%H%M%S).tar.gz -C $SOURCE_DIR . find $BACKUP_DIR -name backup_*.tar.gz -mtime $RETENTION_DAYS -delete echo $(date %F %T) backup finished $LOG_FILEset -euo pipefail这三行加粗如果你不熟悉一定要弄明白-e表示遇到错误退出-u表示变量未定义时退出pipefail表示管道中任何一条命令失败都会让整条管道返回失败。这三条组合起来能避免很多低级失误。真正干了几年级别之后你会慢慢地开始形成一套自己的脚本模板写出来的东西会越来越好用。脚本不用炫技逻辑清晰、参数明确、失败时能给出有效提示才是关键。2. Docker与Dockerfile镜像与容器的日常2.1 容器管理的基础操作与核心概念Docker是目前运维绕不开的基础工具。它在工作场景中的价值不用多说——构建一次到处运行让环境一致性大幅度提升。但实际用起来很多人卡在了概念上镜像、容器、数据卷、网络这四者关系是什么命令怎么组合才合理出了问题怎么定位。我先用大白话把几个核心概念捋一遍。镜像是模板相当于装系统时的ISO文件容器是镜像运行后的实例相当于装好系统并正在运行的机器数据卷是独立的存储空间容器删了它还在网络则决定了容器之间能不能互相通信、能不能被外部访问。这个三角关系一旦清楚了Docker的大部分命令就顺了。日常运维中容器的启停和日志是最常见的操作。启动一个容器时无论用docker run还是docker compose up都要提前考虑三个问题数据是否要持久化端口要怎么映射容器退出后要不要自动重启。数据持久化用-v挂载日志和配置文件建议都挂在宿主机上端口映射用-p但要注意避免端口冲突自动重启策略用--restartunless-stopped这个策略比always更实用因为手动停止的容器不会被强制拉起来。容器网络那边bridge网络下容器之间可以通过服务名互相访问前提是它们在同一个docker network里。跨主机通信则推荐用overlay网络搭配K8s或Docker Swarm一起用。如果只是单机小项目桥接网络就足够了千万别为了追求“所谓的高端方案”把网络搞得过于复杂维护成本会成倍增加。2.2 Dockerfile的正确打开方式Dockerfile表面上看是一个“写构建指令的文件”但实际使用中它决定了镜像的体积、构建速度和运行安全性。我刚接触Dockerfile时总觉得只要把环境配好、服务跑起来就行后来发现这样写出来的镜像个个都像“老古董”体积大、层级多、漏洞隐患也多。先说Dockerfile的基本指令。FROM定基础镜像WORKDIR定工作目录COPY拷文件RUN执行构建时的命令EXPOSE声明端口CMD或ENTRYPOINT指定容器启动时的进程。这些指令里最容易被忽略的是ENTRYPOINT和CMD的区别ENTRYPOINT定义的是容器的主程序CMD提供默认参数两者配合使用时docker run后面追加的参数会覆盖CMD但不会覆盖ENTRYPOINT。按我的实践经验大多数服务用ENTRYPOINT写启动命令、CMD留默认参数是最不容易出错的组合。举个例子一个Java服务的Dockerfile可以这么写FROM maven:3.8-jdk-11 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests FROM openjdk:11-jre-slim WORKDIR /app COPY --frombuilder /build/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]这段多阶段构建其实学到了精髓第一段负责编译第二段只保留运行环境最终镜像里没有源码、没有Maven体积能小一半以上。所有容器镜像的构建都应该朝着“只装运行所需、不装编译工具”的方向靠。还有个关键文件叫.dockerignore。很多人没写它导致COPY . /app的时候把本地的.git、target、node_modules全打进去了镜像体积瞬间膨胀构建速度也慢得离谱。正确的做法是提前声明忽略项像这样.git node_modules target logs *.md这样构建上下文会小很多同时也能避免把宿主机上的本地配置或密钥文件带到镜像里。安全底线镜像里永远不要出现私钥、API令牌、数据库密码这些敏感信息这些应该通过环境变量、配置中心或者K8s Secret注入。2.3 Compose编排与Docker Desktop安装中的经典坑单容器解决不了微服务的问题于是有了Docker Compose。它用YAML文件把多个容器的启动参数集中管理一条docker-compose up -d就能把整套环境拉起来。Compose文件里最常用的配置是services、networks、volumes这三个块可以对应到传统的启动参数。以Redis主从为例很多运维人员都在本地环境或测试环境搭过这套。用Compose写主从结构会比直接敲三四条docker run命令清晰得多version: 3 services: redis-master: image: redis:7 container_name: redis-master restart: unless-stopped ports: - 6379:6379 command: redis-server --appendonly yes redis-slave: image: redis:7 container_name: redis-slave restart: unless-stopped depends_on: - redis-master ports: - 6380:6379 command: redis-server --slaveof redis-master 6379这个Compose文件里的depends_on要注意它只控制启动顺序不保证服务内部已经就绪。如果主库还没完全拉起从库连接失败可能在启动日志里出现重试报错。更稳妥的做法是在应用启动脚本里加等待和重试逻辑。另外很多人装Docker Desktop会遇到Virtualization support not detected的报错在Windows上尤其多见。这个问题的本质是宿主机没有开启硬件虚拟化或Hyper-V功能。排查顺序建议是先确认CPU虚拟化在BIOS里已经开启Intel VT-x或AMD-V再去“启用或关闭Windows功能”里把Hyper-V和Windows虚拟机监控程序平台勾选上最后打开任务管理器性能页确认“虚拟化”显示为“已启用”。装了第三方虚拟化软件或者旧版Android模拟器的机器还可能和Hyper-V冲突建议先卸载或停用再重试。这个坑我见过好几个同事踩主要是看着报错很唬人其实按步骤检查下来绝大多数都是BIOS里那一项没开。3. CI/CD从代码到发布的自动化通道3.1 一套零成本起步的CI/CD架构CI/CD中文叫持续集成和持续交付简单讲就是让每一次代码提交都能自动触发构建、测试、打包、部署的过程。对小团队来说最务实的方案其实是GitLab加GitLab Runner因为GitLab本身自带CI/CD能力不需要额外引入Jenkins少维护一个系统就少一份负担。架构上一条完整的流水线长这样开发push代码到GitLabGitLab Runner检测到分支变化拉取代码在一个专门的执行环境比如Docker容器里跑测试和构建构建成功后生成镜像并推送到镜像仓库最后在目标服务器上执行部署命令。整个过程不需要任何人去手动敲命令。结合标题里提到的“GitLab Docker Engine CI/CD”有一个经验值得分享Runner的executor类型建议直接用docker这样每个流水线任务都会在一个全新的容器里运行环境干净且隔离。但这会带来一个常见问题——Runner容器内部没办法直接调用宿主机的docker命令这时候有两种解法一是挂载宿主机的docker.sock给Runner容器让容器内docker CLI直接和宿主机docker daemon通信二是用Docker in Docker方式在Runner容器内再起一个daemon。前者配置简单但存在安全隐患后者隔离更好但镜像层会有额外损耗。团队刚起步时选前者效率最高规模大了再上DinD也不迟。before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY实际跑流水线时这个登录步骤几乎是必须的因为推镜像、拉私有大镜像都要先认证。用户名密码建议用CI/CD变量注入别硬编码在.gitlab-ci.yml文件里否则相当于把仓库的访问凭证拱手送出。3.2 流水线文件设计与实际踩坑.gitlab-ci.yml是整个CI/CD活动的核心文件它跟项目代码放在一起随着仓库版本一起演进。初次写这个文件的人最容易犯的错是“一个stage里堆了太多事情”测试、构建、推送、部署全塞一起结果某一步失败很难定位。正确做法是拆成多个stage每个stage有一个明确职责失败后能快速看到是哪一段出了问题而且后续的stage可以复用前面产出的内容。一个基础的Java后端流水线大概是这样的stages: - test - build - deploy variables: MAVEN_OPTS: -Dmaven.repo.local$CI_PROJECT_DIR/.m2/repository cache: paths: - .m2/repository/ maven-test: stage: test image: maven:3.8-jdk-11 script: - mvn test docker-build: stage: build image: docker:20 services: - docker:20-dind script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA deploy-test: stage: deploy script: - ssh usertest-server cd /opt/app docker compose pull docker compose up -d only: - main这个方案跑通了之后代码从提交到部署到测试环境一般在三分钟以内。这里面的cache配置值得多说一句它会把Maven依赖目录缓存下来避免每次流水线都重新下载依赖否则构建时间会成倍增加。另一个细节是部署时用了docker compose pull docker compose up -d这种做法的好处是先把新镜像拉下来再重启能减少正在运行的服务因拉镜像失败而中断的概率。踩坑最多的点在三个地方一是Runner服务器的资源不足构建时OOM导致任务失败需要给Runner加上内存限制或者在Runner配置里降低并发数二是services: docker:dind需要特权模式有些自建Runner环境默认没开导致docker命令报权限错误三是分支和tag的触发条件没写对导致每次提交都触发全量部署生产环境被频繁重启。这些问题都是“跑几天才暴露”的建议在新环境上先小流量试跑几条流水线观察资源配置和日志再放开全量。4. K8s与容器编排从单机到集群的跃迁4.1 K8s核心概念与入门路径K8s全称Kubernetes它是容器编排领域的事实标准。有人问K8s和Docker到底什么关系最简单的理解是Docker解决了“单个容器怎么跑”的问题K8s解决的是“一堆容器怎么调度、怎么互相发现、怎么扩容缩容、怎么保证高可用”的问题。换句话说Docker是发动机K8s是整车。学习K8s建议先抓住四条主线Pod、Deployment、Service、Ingress。Pod是K8s里最小的调度单位一个Pod可以包含一个或多个容器共享网络和存储卷Deployment负责管理无状态应用的副本数、滚动更新和回滚Service为一组Pod提供稳定的访问入口相当于给随时可能“去世”的Pod发了一张“永不换号码”的名片Ingress负责把集群外的HTTP请求路由到Service上。这四个概念串起来就是一个请求从域名到Pod的完整链路。部署方式上单节点测试环境推荐用KubeKey、kubeadm或者minikube图省事就装个发行版自带的K8s套件。生产环境至少三节点起步越重要的系统越要关注高可用比如控制平面需要三台Masteretcd数据也要有备份。我最开始只用单节点实验等到跑真实业务时发现节点一挂整个集群直接瘫痪才老老实实把多Master的架构搭起来。基础概念的牢固程度直接决定了后续排查故障的速度。4.2 单节点到高可用Master节点怎么保证稳标题里有个搜索词“k8s三台master怎么保证高可用kubekey”这个问题很实际。K8s的高可用本质上分为两个层面一是控制平面的高可用二是业务工作负载的高可用。控制平面里的关键组件是etcd它保存了整个集群的状态而且用的是Raft算法保证数据一致性。Raft要求多数派存活才能继续工作三台Master意味着最多只能坏一台如果坏了两台etcd就选不出领导者了整个集群会进入只读状态甚至不可用。三台Master的架构通常长这样每台Master上部署kube-apiserver、kube-controller-manager、kube-scheduler、etcd然后在前面放一个负载均衡器比如HAProxy、Nginx或者云上的SLB把kube-apiserver的6443端口统一暴露给Worker节点和外部客户端。Work节点上的kubelet和kube-proxy只连接这个负载均衡器地址而不是某个具体Master的IP。这样即使某台Master宕机了流量也会自动切换到健康的Master上。我在实际搭建时用KubeKey在离线环境部署过一套三主多从的集群整个过程相对友好版本兼容问题被官方工具处理了一部分。但有几个细节还是要重点检查一是所有节点的hostname不能重复且不能有大写字母二是节点之间要能通过主机名互相解析建议直接写hosts文件三是内核和网络参数要提前配好主要是net.ipv4.ip_forward、bridge-nf-call-iptables这些。如果你省略这些步骤大概率会在集群初始化或Pod网络插件安装那一步失败回头排查起来非常费时间。4.3 应用迁到K8s的实操思路把已有应用迁到K8s很多人一上来就写一堆YAML结果部署到一半发现配置错了、探针有问题、PVC没绑定最后回滚也很难受。迁移的本质不是“把docker run命令翻译成YAML文件”而是要把应用的工作方式改造成“能随时被杀、能随时重建、能水平扩展”的模式。以“若依微服务不停机迁移”为例这类应用通常包含多个服务前端、后端、认证、网关等模块。迁移之前先盘一下现状哪些服务是有状态的哪些是无状态的配置是写在文件里的还是环境变量里的日志是写到磁盘还是标准输出。把这些理清楚之后再动手往往事半功倍。无状态服务写一个Deployment加Service就能搞定。下面这个配置就是非常典型的模板apiVersion: apps/v1 kind: Deployment metadata: name: app-backend namespace: production spec: replicas: 3 selector: matchLabels: app: backend template: metadata: labels: app: backend spec: containers: - name: backend image: registry.example.com/app-backend:1.0.0 ports: - containerPort: 8080 env: - name: DB_HOST value: mysql-service readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 15 periodSeconds: 5 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1 memory: 1Gi --- apiVersion: v1 kind: Service metadata: name: app-backend-service namespace: production spec: selector: app: backend ports: - port: 8080 targetPort: 8080这里面的readinessProbe特别重要它决定Pod是否被纳入Service的负载均衡列表。如果探针没配启动很慢的应用可能在还没就绪时就被转发请求直接导致大量5xx错误。迁移时我会建议先接流量观察不要一次性把全部副本切到新集群可以用Ingress或者网关按比例灰度逐步放量直到确认稳定后再把旧环境缩容。“不停机、不丢数据”的迁移策略上要分步走先把数据层同步好再将应用层分批切换最后在低峰期做一次流量切换和验证。整个过程如果提前规划好回滚方案心里就有底得多。5. 监控与告警给系统装上仪表盘5.1 一套监控体系怎么搭起来从零搭一套可用的监控体系Prometheus Grafana Node Exporter Alertmanager是目前最推荐的组合。原因很简单开源、生态大、资料多而且和K8s、Docker都能无缝配合。先理解Prometheus的工作方式。它是一个按“时间序列”存储数据的监控系统每隔一个采集周期从目标机器或者目标服务上拉取指标数据。数据源用exporter暴露HTTP接口供Prometheus拉取而Grafana负责把数据从Prometheus查出来并画成图表Alertmanager则根据Prometheus里的告警规则来决定往钉钉、邮件或企业微信发通知。部署顺序建议是先装Node Exporter采集机器基础指标再装Prometheus存数据之后装Grafana出图最后配Alertmanager发告警。K8s集群里的监控通常会用一个Prometheus Operator来管理它对Kubernetes原生的服务发现支持得非常好能自动发现集群里的Pod和Service并采集指标这也是“k8s集群搭建prometheus”最常见的落地方式。下面是一段极简的Prometheus配置示例把node_exporter和kube-state-metrics都加入采集目标global: scrape_interval: 15s scrape_configs: - job_name: node static_configs: - targets: [192.168.1.10:9100, 192.168.1.11:9100] - job_name: kubernetes-pods kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true这段配置里kubernetes_sd_configs是核心它让Prometheus通过K8s API自动发现带“prometheus.io/scrape: true”注解的Pod也就是说以后新部署一个服务只要在Pod模板上打上注解监控采集就自动生效再也不用手动改配置、再reload了。5.2 告警规则与一次磁盘告警的复盘监控的价值在于“提前发现问题”如果只采集指标不做告警那本质上和没监控差不多。告警规则不建议一上来就配二三十条先把最核心的几类配上节点不可用、CPU持续高、内存剩余不足、磁盘使用率超阈值、Pod反复重启。以磁盘告警为例规则可以写成这样groups: - name: node-alerts rules: - alert: DiskUsageHigh expr: disk_used_percent 85 for: 10m labels: severity: warning annotations: summary: 节点磁盘使用率超过85% description: Node {{ $labels.instance }} disk usage is {{ $value }}%for: 10m这个字段很重要它表示持续10分钟才触发告警避免因瞬时峰值误报。设置告警阈值还要考虑业务的实际情况如果磁盘本身就很小或者增长极快85%可能太晚需要更早介入。我复盘过一起典型的磁盘告警事件告警平台在凌晨两点发出磁盘使用率超过85%的通知我当时没有立即处理想着凌晨业务量低早上一并清理。结果五点没到Prometheus自己的TSDB把剩余空间吃光了监控数据本身写不进去告警也停了整个系统进入了“黑屏”状态。从那次以后我把Prometheus的存储目录单独挂一块大容量盘并给监控主机设置了更高的告警优先级确保监控系统本尊不会先于业务系统说再见。这类经验真不是从书里能学到的没踩过坑的人很难有这种警觉。5.3 监控系统落地后的日常维护搭建完监控体系后日常维护的主要工作是三块第一是定期检查Exporter是否全部在线发现挂掉的采集目标要及时恢复第二是梳理指标和看板把不常用的指标从采集配置里去掉避免存储膨胀第三是每隔一段时间就检视一下告警规则因为业务在变以前合理的阈值现在可能已经失效了。还要强调一点监控数据要保留一定的历史周期。Prometheus默认本地存储有保留期--storage.tsdb.retention.time如果留太短出了问题时查不到过去的曲线就很难做“故障前后对比”。我的建议是热数据保留15天如果要跨月度对比考虑接一个Thanos或者把数据长期归档到对象存储。6. 故障排查现场处置的方法论和方法6.1 一套可复用的排查思路故障排查是运维工作的最终战场。一套系统的排查顺序如果对了五分钟内基本能定位八成问题顺序乱了很容易做着做着把自己绕进去。我常用的排查顺序是先确认影响范围再看应用日志接着看资源指标最后看网络链路。影响范围决定了处置的紧急程度是全挂还是部分挂是新发版导致还是老问题复发这些信息直接影响后续动作。应用日志是定位的第一手证据很多问题其实看日志就能看出来。资源瓶颈则通过top、free、df、iostat这些命令去确认比如CPU满载、内存不足、磁盘IO过高都会让服务出现“假死”的状态。网络层排查主要看连通性、DNS解析、端口访问和防火墙规则。还有一条重要的经验不要贸然重启服务。重启确实能让很多“症状”消失但也会把定位问题的证据一起带走。遇到问题先抓现场再判断是否重启。如果是内存泄漏重启后再观察可能需要等好几天才能复现。6.2 真实案例一Docker服务起不来现象是systemctl start docker卡在启动中CentOS系统上执行systemctl status docker后看到dockerd一直在等待。这个问题的排查思路是看dockerd的日志执行journalctl -u docker -n 100 --no-pager大概率能看到具体原因。我遇到过的典型情况是/etc/docker/daemon.json配置里的网段和宿主机现有网段冲突或者数据目录权限不对还有磁盘空间不足导致docker daemon无法写临时文件。解决方式分别是改配置、修复目录权限、清理磁盘。还有个隐藏问题如果宿主机开了防火墙或SELinuxdocker的端口映射可能怎么配都无效这时候用getenforce看下SELinux状态临时改成Permissive作为定位手段确认后再决定要不要彻底关闭或配置放行规则。Docker daemon起不来的另一个高频原因是storage driver和内核版本或文件系统不兼容。老系统上的overlayfs支持不完整daemon启动日志里会出现“failed to mount overlay”之类的信息这种情况下要么升级内核要么在daemon.json里显式指定storage-driver: vfs性能差一些但稳定。6.3 真实案例二CI/CD流水线报Docker Engine未就绪这个案例很典型在我的经验里发生过至少三次。现象是GitLab Runner在跑流水线时执行到docker build这一步直接报错提示“Cannot connect to the Docker daemon”或者是Docker未启动。第一次遇到这个问题我第一反应是检查Runner所在主机的dockerd有没有启动结果系统里docker命令正常用docker ps也没有报错也就是说Host的Docker Engine是好的。真正的原因其实在Runner配置。如果你用的是Shell executor在主机上跑命令那runner用户可能没有权限访问/var/run/docker.sock解决方案是把runner用户加入docker组如果你用的是Docker executorRunner容器内部并没有独立的Docker daemon需要挂载宿主机的docker.sock或者加上docker:20-dind服务作为DinD后台。很多新手会卡在docker.sock权限这个地方报错信息又不直白所以排查方向很容易跑偏。另外就算能连上Docker daemondocker build时如果没有使用--networkhost一些需要访问宿主机内部服务的构建过程也会失败。我的经验是构建阶段尽量只在容器内做标准的事像拉Maven依赖、npm install这类只需要外网的步骤不用额外处理但如果构建过程要访问内网私服一定要配置好pip或者maven的私服地址别让构建期间的动作依赖宿主机环境。6.4 真实案例三K8s Pod反复处于ImagePullBackOff在K8s里部署新应用Pod一直起不来状态停在ImagePullBackOff是每个入门者都会遇到的事。原因其实就那几种镜像地址写错、镜像标签不存在、镜像仓库需要凭证但Pod没有配置imagePullSecrets、或者仓库地址访问不通。排查流程很清晰执行kubectl describe pod pod-name看Events部分有没有Failed to pull image或者ImagePullBackOff的具体描述再根据描述去做处理。如果是私有仓库需要认证创建一个docker-registry类型的secret然后在Deployment的spec.template.spec.imagePullSecrets里引用这个secretapiVersion: v1 kind: Secret metadata: name: registry-key type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: base64编码的docker config json内容把docker login生成的config.json内容用base64编码填入然后在Deployment里加上spec: template: spec: imagePullSecrets: - name: registry-key小型集群经常遇到这类问题尤其是从本地Docker直接搬到K8s的团队很少一开始就考虑私有仓库的认证方式。所以如果准备迁移K8s先把镜像仓库的认证打通后面会省很多事。6.5 常见问题速查表日常运维中一些可快速对照的高频问题我整理成了一个表格。排查顺序不是死的但按这个表去定位大多数场景都能在几分钟内找到方向。问题现象常见原因快速排查命令/动作服务端口无法访问服务没启动、端口未监听、防火墙拦截ss -lntp查看监听curl -v验证连通firewall-cmd --list-all检查策略CPU 使用率持续100%应用死循环、高消耗任务、容器无限重启top定位进程pidstat -p pid 1看线程状态必要时抓线程dump磁盘写满但df显示空被删除文件仍被进程占用lsof L1定位已删除但仍占用的文件句柄重启对应进程Docker 容器反复重启启动命令退出、内存超限、健康检查失败docker logs container看退出原因docker inspect查重启策略和OOM状态K8s 节点NotReadykubelet异常、网络插件损坏、磁盘压力kubectl describe node、journalctl -u kubelet、检查容器运行时Prometheus 抓取不到指标Exporter未启动、网络不通、服务发现配置错误curl http://IP:端口/metrics本地验证检查scrape_configsCI/CD 流水线卡住Runner并发满、镜像拉取慢、资源不足查看Runner日志检查并发数和资源限制必要时提升超时时间这张速查表可以打印出来贴在工位上或者放团队知识库里。随着你遇到的实际问题越多这张表也会越长越全最终形成自己的知识库体系。7. 收尾一点实在的体会写了这么多我其实发现运维这个岗位最值钱的东西不是某个工具用得熟而是故障发生时的冷静和对系统全貌的理解。好多时候问题看起来千奇百怪但拆开来看无非就那几个层面资源够不够、配置对不对、网络通不通、代码有没有异常。只要把这些基础修炼扎实了再借助Docker、K8s、CI/CD和监控体系把这些能力固化下来很多东西自然会变得标准化故障也会越来越少。最后再分享一个小技巧每次处理完一个疑难故障之后都花十五分钟把整个过程写成一篇复盘笔记记录现象、排查步骤、根因、解决方式和预防措施。积累几十篇之后你会发现自己从一个“救火队员”慢慢变成了能预测问题、提前规避风险的运维老手。这可能是做运维最值得坚持的习惯了。
返回列表