Docker与Kubernetes实战指南:从容器化到云原生应用部署 1. 从“集装箱”到“超级码头”为什么我们需要Docker和Kubernetes如果你在IT行业尤其是运维、开发或者架构领域待过一阵子最近几年肯定被两个词反复刷屏Docker和Kubernetes常简称为K8s。它们就像一对黄金搭档一个负责把货物打包成标准集装箱另一个负责管理整个港口的调度和运输。我刚开始接触时也犯迷糊觉得概念一堆什么容器、镜像、Pod、Service听着就头大。但真正用起来之后才发现这套组合拳彻底改变了我们构建、交付和运行应用的方式。简单来说Docker解决了应用“打包”和“环境一致性”的难题。回想以前开发在本地跑得好好的程序一到测试或生产环境就各种报错——“我电脑上没问题啊”这种场景太常见了。Docker通过容器技术将应用及其所有依赖库、环境变量、配置文件打包成一个轻量级、可移植的“镜像”。这个镜像在任何安装了Docker引擎的机器上都能以完全一致的方式运行起来就像集装箱无论在货轮、火车还是卡车上内部环境都保持不变。而Kubernetes解决的是大规模容器“编排”和“管理”的难题。当你只有三五个容器时手动管理还行。但一旦发展到几十、上百个容器分布在多台服务器上问题就来了哪个容器挂了怎么自动重启流量大了如何自动扩容服务之间如何发现和通信版本更新怎么做到无缝滚动Kubernetes就是为应对这些复杂场景而生的“容器编排平台”它像一个自动化的超级码头调度中心确保你的容器化应用集群能够稳定、高效、弹性地运行。所以学习Docker和K8s绝不是追逐时髦。对于开发者它意味着更简单的环境搭建、更一致的开发体验和更快的本地集成测试。对于运维和架构师它代表着基础设施即代码、不可变基础设施、声明式配置和强大的自动化运维能力是构建现代云原生应用架构的基石。2. Docker深度解析不仅仅是“轻量级虚拟机”很多人初学Docker第一反应是把它和虚拟机VM对比认为它只是个更轻、更快的VM。这个类比有助于理解但容易让人忽略Docker最核心的价值。我花了很长时间才跳出这个思维定式。2.1 核心概念镜像、容器与仓库Docker的架构围绕三个核心概念运转理解它们就理解了Docker的一半。镜像Image这是Docker世界的“构建模板”或“只读的二进制包”。你可以把它理解为一个应用程序的“安装包”但这个安装包包含了运行所需的一切——代码、运行时、系统工具、系统库和设置。镜像是分层的每一层代表Dockerfile构建镜像的脚本中的一条指令。这种分层机制使得镜像可以复用非常节省存储空间。例如一个基于Ubuntu的Python应用镜像底层是Ubuntu基础层中间是Python环境层最上层才是你的应用代码层。容器Container容器是镜像的运行实例。当你执行docker run命令时Docker引擎会从镜像创建一个可写的容器层称为容器层并在其之上启动进程。容器是隔离的拥有自己的文件系统、网络和进程空间但它与宿主机共享操作系统内核。这正是它比虚拟机轻量得多的原因——虚拟机需要模拟完整的硬件并运行一个完整的客户机操作系统。仓库Registry仓库是存放镜像的地方。最著名的是Docker Hub一个公共的镜像仓库你可以从中拉取pull像Nginx、Redis、MySQL等常用软件的官方镜像。你也可以搭建私有仓库如Harbor用于存储企业内部的自定义镜像。注意务必区分“Docker引擎”和“Docker Desktop”。Docker引擎是核心的容器运行时在Linux上原生运行。Docker Desktop是为Mac和Windows用户提供的桌面应用它通过创建一个轻量级Linux虚拟机在Windows上可能是WSL2来运行Docker引擎。如果你在Windows上遇到“virtualisation support not detected”或启动转圈的问题通常是因为未开启BIOS中的虚拟化技术VT-x/AMD-V或未启用Hyper-V/WSL2。2.2 Docker解决了哪些具体痛点从我自己的项目经验来看Docker带来的好处是实实在在的环境标准化与一致性我们团队曾有一个老项目依赖一个特定版本的Node.js和一堆全局npm包。新同事搭建环境花了整整两天版本冲突不断。后来我们用Dockerfile定义了环境新人只需要docker-compose up一分钟内就能获得一个完全一致的开发环境。生产环境的部署也从“手动配环境”变成了“拉取镜像并运行”部署成功率从70%提升到99%。持续集成与交付CI/CD的基石在CI流水线中构建阶段直接在一个干净的Docker容器中执行确保了构建环境纯净。产出的直接就是一个可部署的Docker镜像。这个镜像可以被推送到仓库然后被相同的命令部署到测试、预发布和生产环境实现了真正的“一次构建处处运行”。资源利用与快速启停启动一个虚拟机通常需要分钟级而启动一个容器是秒级甚至毫秒级。这对于需要快速弹性伸缩的微服务场景至关重要。同时因为容器共享内核其内存和CPU开销远小于虚拟机可以在同一台物理机上运行更多的应用实例。微服务架构的天然载体每个微服务都可以被打包成一个独立的Docker镜像拥有自己明确的依赖和配置。服务之间通过定义好的网络进行通信解耦彻底也便于独立升级和扩展。2.3 实操心得编写高效的Dockerfile光会docker run拉取现成镜像还不够自己编写Dockerfile才是真功夫。这里分享几个踩坑后总结的经验使用合适的基础镜像别动不动就用ubuntu:latest。对于生产环境优先选择体积更小、更安全的官方镜像如alpine极简Linux发行版或distroless只包含应用及其运行时没有shell包管理器。例如一个Go应用可以用golang:alpine作为构建阶段镜像用alpine作为运行阶段镜像最终镜像可能只有十几MB。利用构建缓存与分层Dockerfile的每条指令都会生成一个镜像层且层是缓存的。把变化频率低的指令如安装系统依赖包放在前面把变化频率高的指令如拷贝应用代码放在后面。这样可以最大化利用缓存加速后续构建。# 不好的例子代码变动会导致apt-get每次重新运行极慢 COPY . /app RUN apt-get update apt-get install -y python3 # 好的例子依赖安装层被缓存只有代码变更时才重建后面层 RUN apt-get update apt-get install -y python3 COPY . /app一个容器只运行一个进程这是12-Factor应用和Docker的最佳实践。不要在一个容器里用Supervisor运行Nginx、PHP-FPM和MySQL。这违背了容器的单一职责原则会让日志收集、监控和水平扩展变得复杂。应该拆分成多个容器用Docker Compose或K8s来编排它们之间的关系。不要将敏感信息写入Dockerfile或镜像密码、API密钥等应通过环境变量-e参数或env文件或K8s Secrets在运行时注入。可以在Dockerfile中定义环境变量的默认值但真实值由编排平台提供。3. Kubernetes全景透视从容器管理到云原生操作系统当你的应用从“几个容器”发展到“一套由数十个微服务组成的分布式系统”时手动管理就变成了灾难。这时Kubernetes登场了。它不只是一个工具更像是一个为容器化应用提供部署、运维、扩展等全生命周期管理的“分布式操作系统”。3.1 核心架构与核心概念K8s的架构是典型的主从Master-Node模式理解了它的核心组件就能看懂它如何工作。控制平面Master Node这是集群的“大脑”负责决策和管理。API Server所有操作的唯一入口提供了RESTful API。我们使用的kubectl命令就是和它交互。etcd一个高可用的键值数据库存储了整个集群的所有配置数据和状态信息是K8s的“记忆中枢”。Scheduler负责“调度”监听未被调度的Pod根据资源需求、亲和性等策略为它们选择一个合适的Node来运行。Controller Manager运行着各种控制器它们是K8s的“自动化引擎”。例如Node控制器负责节点状态Deployment控制器负责确保指定数量的Pod副本在运行。工作节点Worker Node这是运行容器的“肌肉”。kubelet节点上的“代理”负责与API Server通信管理本节点上Pod的生命周期创建、销毁并确保容器健康运行。kube-proxy负责节点上的网络代理和负载均衡实现Service概念让Pod之间可以相互发现和通信。容器运行时负责运行容器的软件如Docker、containerd或CRI-O。K8s通过CRI容器运行时接口与它们交互。理解了架构再看几个最核心的资源对象它们是你在YAML文件中定义的内容PodK8s管理的最小可部署单元。一个Pod可以包含一个或多个紧密关联的容器比如一个主应用容器和一个日志收集sidecar容器它们共享网络命名空间、IPC、UTS以及可以通过Volume共享存储。Pod是短暂的会被频繁地创建和销毁。Deployment这是你最常打交道的对象。它定义了Pod的期望状态用什么镜像、要运行多少个副本。Deployment控制器会确保实际状态始终匹配期望状态。当需要更新应用时你可以修改Deployment的镜像版本K8s会自动进行滚动更新这是其核心魅力之一。ServicePod是动态的IP地址会变。Service提供了一个稳定的访问端点一个虚拟IP和DNS名并将流量负载均衡到后端一组匹配的Pod上。它是服务发现和内部通信的关键。IngressService通常提供的是集群内部访问。Ingress则管理从集群外部访问内部服务的HTTP/HTTPS路由规则。它需要配合一个Ingress Controller如Nginx Ingress Controller使用后者才是实际处理流量的“入口网关”。3.2 K8s与Docker的关系演进与现状这是一个常见误区。早期K8s确实使用Docker作为默认的容器运行时。但两者的关系已经发生了变化。K8s的核心需求是管理容器它并不关心容器具体是由Docker、containerd还是其他什么工具创建的。为了标准化K8s定义了CRI容器运行时接口。任何实现了CRI的运行时都可以被K8s使用。Docker本身是一个完整的容器平台包含了构建、镜像管理、运行时、网络等全套功能。而K8s只需要其中的“运行时”部分。因此从K8s 1.20版本开始它逐渐弃用了对Docker的直接支持确切地说是弃用了内置的dockershim组件。现在在K8s集群中更常见的底层运行时是containerd它本身也是从Docker项目中分离出来的或CRI-O。对于用户而言这个变化几乎无感。你仍然可以用Docker来构建镜像、在本地运行容器。当你把这些镜像部署到K8s集群时K8s会通过containerd来运行它们。所以学习Docker对于理解容器和镜像的概念依然至关重要它是学习K8s的最佳铺垫。3.3 部署模式解析单节点、多节点与托管集群根据你的学习和生产需求K8s有多种部署方式本地学习/开发环境Minikube在单台机器上创建一个单节点的K8s集群最适合初学者上手体验。Docker Desktop内置K8s在Mac/Windows的Docker Desktop中一键启用一个单节点集群非常方便但资源有限。KindKubernetes in Docker用Docker容器来模拟K8s节点可以快速创建多节点集群用于测试。生产级自建集群kubeadm官方提供的集群部署工具能帮你快速搭建一个符合最佳实践的集群。你需要在多台CentOS/Ubuntu服务器上手动安装容器运行时、kubelet、kubeadm等然后通过kubeadm init和kubeadm join命令构建集群。这是理解K8s架构细节的好方法但运维成本较高。二进制部署直接下载各个组件的二进制文件手动配置和启动。最灵活但也最复杂通常只在特殊需求或深度定制时使用。托管集群云服务EKS (AWS), AKS (Azure), GKE (Google Cloud)这是目前生产环境的主流选择。云厂商负责管理控制平面Master你只需要创建工作节点Node并支付节点资源费用。这极大地降低了运维复杂度让你能更专注于应用本身。实操心得对于个人学习和中小团队我强烈建议从Minikube或Docker Desktop的K8s开始。想体验多节点可以用Kind。千万不要在初期就试图在裸机上用kubeadm部署生产集群那会消耗你大量时间在环境配置和故障排查上容易打击信心。先学会“用”K8s部署和管理应用再深入学“搭”K8s。4. 实战入门从零部署一个微服务应用到K8s理论说了这么多我们来点实际的。假设我们有一个经典的“LNMP”应用Linux, Nginx, MySQL, PHP现在我们要将它容器化并部署到K8s集群。这里我们用WordPress为例因为它组件清晰。4.1 第一步容器化应用编写Dockerfile首先我们需要为每个组件创建镜像。对于WordPress我们通常需要两个镜像WordPress本身和MySQL。MySQL的Dockerfile示例 我们直接使用官方镜像但需要准备一个初始化数据库的脚本和自定义配置文件。这里更常见的做法是使用docker-compose或K8s的ConfigMap来配置但为了理解我们先看一个简单的自定义镜像思路实际生产可能直接用官方镜像加环境变量。# 使用官方MySQL镜像作为基础 FROM mysql:8.0 # 设置环境变量密码应在运行时通过Secret注入这里仅为示例 ENV MYSQL_ROOT_PASSWORDrootpass ENV MYSQL_DATABASEwordpress ENV MYSQL_USERwpuser ENV MYSQL_PASSWORDwppass # 将自定义配置文件复制到镜像中 COPY my.cnf /etc/mysql/conf.d/ # 将初始化SQL脚本复制到docker-entrypoint-initdb.d目录容器首次启动时会自动执行 COPY init.sql /docker-entrypoint-initdb.d/ # 暴露端口 EXPOSE 3306init.sql可以包含创建数据库和用户的语句虽然环境变量已能创建但这里展示自定义初始化能力。WordPress的Dockerfile示例 同样我们基于官方镜像可能添加一些自定义的PHP插件或调整配置。FROM wordpress:php8.1-apache # 安装额外的PHP扩展例如imagick RUN apt-get update apt-get install -y libmagickwand-dev --no-install-recommends \ pecl install imagick \ docker-php-ext-enable imagick \ apt-get clean \ rm -rf /var/lib/apt/lists/* # 复制自定义的Apache虚拟主机配置或php.ini配置 COPY custom.ini /usr/local/etc/php/conf.d/ COPY 000-default.conf /etc/apache2/sites-available/ # WordPress代码已包含在基础镜像中我们无需再COPY # 环境变量如数据库连接信息将在K8s部署时通过ConfigMap和Secret注入构建镜像docker build -t my-wordpress:latest .和docker build -t my-mysql:latest .4.2 第二步定义K8s部署清单YAML文件现在我们需要编写K8s的YAML文件来定义如何运行这些容器。我们通常会为每个组件创建独立的部署文件。1. MySQL的部署mysql-deployment.yamlapiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: # 使用 echo -n yourpassword | base64 生成base64编码 root-password: cm9vdHBhc3M # rootpass database-password: d3BwYXNz # wppass --- apiVersion: v1 kind: ConfigMap metadata: name: mysql-config data: my.cnf: | [mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci innodb_buffer_pool_size256M --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql-deployment spec: selector: matchLabels: app: mysql strategy: type: Recreate # 数据库部署策略通常用Recreate避免多个实例同时写数据 template: metadata: labels: app: mysql spec: containers: - name: mysql image: my-mysql:latest # 或使用官方镜像 mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password - name: MYSQL_DATABASE value: wordpress - name: MYSQL_USER value: wpuser - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: database-password ports: - containerPort: 3306 volumeMounts: - name: mysql-config-volume mountPath: /etc/mysql/conf.d readOnly: true - name: mysql-persistent-storage mountPath: /var/lib/mysql volumes: - name: mysql-config-volume configMap: name: mysql-config - name: mysql-persistent-storage persistentVolumeClaim: claimName: mysql-pvc # 需要提前创建PVC --- apiVersion: v1 kind: Service metadata: name: mysql-service spec: selector: app: mysql ports: - protocol: TCP port: 3306 targetPort: 3306 clusterIP: None # 使用Headless Service便于Pod直接通过DNS发现关键点解析使用了Secret来安全存储密码避免明文写在YAML里。使用了ConfigMap来管理配置文件。Deployment的strategy设置为Recreate这对于有状态应用数据库是常见选择确保更新时先终止旧Pod再创建新Pod防止数据冲突。Service的类型是ClusterIP并且设置了clusterIP: None这创建了一个Headless Service。Pod将获得一个唯一的DNS记录pod-name.service-name.namespace.svc.cluster.localWordPress Pod可以通过这个DNS直接连接到具体的MySQL Pod。2. WordPress的部署wordpress-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: wordpress-deployment spec: selector: matchLabels: app: wordpress replicas: 2 # 运行两个副本以实现负载均衡和高可用 template: metadata: labels: app: wordpress spec: containers: - name: wordpress image: my-wordpress:latest env: - name: WORDPRESS_DB_HOST value: mysql-service.default.svc.cluster.local # 通过Service名访问MySQL - name: WORDPRESS_DB_USER value: wpuser - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: database-password - name: WORDPRESS_DB_NAME value: wordpress ports: - containerPort: 80 volumeMounts: - name: wordpress-persistent-storage mountPath: /var/www/html/wp-content # 挂载内容目录主题、插件、上传文件需要持久化 volumes: - name: wordpress-persistent-storage persistentVolumeClaim: claimName: wordpress-pvc --- apiVersion: v1 kind: Service metadata: name: wordpress-service spec: selector: app: wordpress ports: - protocol: TCP port: 80 targetPort: 80 type: ClusterIP # 内部服务先通过ClusterIP暴露 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: wordpress-ingress spec: rules: - host: wordpress.my-domain.com # 你的域名 http: paths: - path: / pathType: Prefix backend: service: name: wordpress-service port: number: 80关键点解析Deployment的replicas设置为2K8s会确保始终有两个WordPress Pod在运行。环境变量WORDPRESS_DB_HOST的值是MySQL Service的DNS名称。在K8s集群内Pod可以通过service-name.namespace.svc.cluster.local访问一个Service。这里default是命名空间。通过Ingress资源将服务暴露到集群外部。你需要有一个Ingress Controller例如部署了Nginx Ingress Controller来处理这些Ingress规则并需要将域名wordpress.my-domain.com解析到Ingress Controller的Service或节点IP。3. 持久化存储persistent-volume-claim.yaml 容器内的数据是临时的Pod重启会丢失。对于数据库和WordPress上传的文件我们必须使用持久化存储。# 为MySQL申请存储 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: accessModes: - ReadWriteOnce # 单节点读写 resources: requests: storage: 5Gi --- # 为WordPress申请存储 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wordpress-pvc spec: accessModes: - ReadWriteMany # 多节点读写因为多个WordPress Pod需要访问同一份上传文件 resources: requests: storage: 10Gi注意ReadWriteMany的存储卷类型需要底层存储系统支持如NFS、CephFS、云厂商提供的文件存储。在本地测试环境如Minikube可能只支持ReadWriteOnce。你需要根据实际环境调整。4.3 第三步部署与验证应用配置确保你已配置好kubectl并连接到你的K8s集群Minikube、Kind或云集群。创建资源按顺序执行以下命令。# 创建Secret和ConfigMap kubectl apply -f mysql-deployment.yaml # 创建持久化存储声明PVC集群会自动绑定可用的PV持久卷 kubectl apply -f persistent-volume-claim.yaml # 创建WordPress部署和服务 kubectl apply -f wordpress-deployment.yaml检查状态kubectl get pods # 查看Pod状态应为Running kubectl get deployments # 查看部署状态 kubectl get services # 查看服务 kubectl get pvc # 查看存储声明是否绑定成功访问应用如果你使用了Ingress并配置了正确的域名和Ingress Controller就可以通过http://wordpress.my-domain.com访问。在本地测试环境如Minikube你可以使用端口转发临时访问kubectl port-forward service/wordpress-service 8080:80然后在浏览器访问http://localhost:8080。通过这个实战你应该能清晰地看到从镜像构建、YAML定义到集群部署的完整流程。K8s通过声明式的YAML文件让你清晰地定义了应用的终态而它负责自动地实现并维持这个状态。5. 进阶概念与生产实践要点当你掌握了基础部署后要走向生产环境以下几个概念和技巧至关重要。5.1 配置管理ConfigMap与Secret的最佳实践ConfigMap用于管理非敏感的配置数据如配置文件、环境变量、命令行参数。不要将整个大配置文件塞进一个ConfigMap的data字段可以按功能拆分。对于真正的配置文件如nginx.conf可以使用volumeMount将其挂载到容器内这样文件更新后Pod内的文件也会自动更新有一定延迟。Secret用于存储敏感数据如密码、令牌、密钥。虽然K8s中的Secret默认以Base64编码存储并非加密但配合RBAC和网络策略比明文放在环境变量或镜像中安全。生产环境应考虑启用Secret的静态加密Encryption at rest或者使用外部Secret管理方案如HashiCorp Vault、云厂商的密钥管理服务。5.2 存储方案选型PVC、PV与StorageClassPersistentVolume (PV)集群中的一块网络存储资源由管理员预先配置或动态供给。PersistentVolumeClaim (PVC)用户对存储的请求。它指定了所需存储的大小和访问模式。StorageClass定义了“存储类”描述了可以动态创建PV的“供应商”和“参数”。当用户创建PVC并指定了storageClassName时集群会自动按需创建符合要求的PV。生产建议永远使用动态供给。即定义好StorageClass然后在PVC中引用它。这样开发人员无需关心底层存储细节只需申请“5Gi的快速SSD存储”即可。云平台上如AWS的gp2 Azure的managed-premium都有对应的StorageClass。5.3 网络策略与安全默认情况下K8s集群内所有Pod是互通的。在生产环境中这不符合最小权限原则。你需要使用NetworkPolicy来定义Pod之间的网络隔离规则。例如只允许Ingress Controller的Pod访问WordPress的80端口只允许WordPress的Pod访问MySQL的3306端口。apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-wordpress-to-mysql spec: podSelector: matchLabels: app: mysql policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: wordpress ports: - protocol: TCP port: 3306要实现NetworkPolicy你的K8s集群必须安装了支持它的网络插件如Calico、Cilium或Weave Net。5.4 监控与日志监控你需要监控集群状态节点、Pod资源使用和应用指标请求数、延迟。核心组合是Prometheus指标收集与存储 Grafana数据可视化。K8s生态中还有kube-state-metrics这个服务它将K8s对象如Deployment、Pod的状态转换为Prometheus可抓取的指标。日志容器日志是标准输出和标准错误。你需要一个集群级的日志收集方案。经典的EFK栈Fluentd或Fluent Bit日志收集与转发 Elasticsearch存储与索引 Kibana可视化。在云平台上也可以直接使用托管的日志服务如AWS CloudWatch Logs, GCP Stackdriver。5.5 持续部署与GitOps当你的YAML文件越来越多时手动kubectl apply容易出错且难以追溯。这时需要引入GitOps工作流。HelmK8s的包管理工具。你可以将一套复杂的应用包含多个Deployment、Service、ConfigMap等打包成一个Chart。通过helm install一键部署通过helm upgrade轻松升级和回滚。社区有大量现成的Chart如nginx-ingress, redis-cluster。Argo CD / Flux CDGitOps工具。它们持续监视你指定的Git仓库里面存放着声明式的YAML或Helm Chart。当仓库中的配置发生变化时它们会自动将变更同步到K8s集群中确保集群状态与Git中定义的期望状态一致。这实现了部署过程的版本化、可审计和自动化。6. 常见问题与故障排查实录在学习和使用Docker和K8s的过程中我踩过不少坑。这里记录一些典型问题和排查思路希望能帮你节省时间。6.1 Docker常见问题问题1Docker Desktop启动失败提示“virtualisation support not detected”。原因宿主机Windows/Mac的虚拟化支持未开启。排查Windows进入BIOS确保Intel VT-x或AMD-V虚拟化技术已启用。然后在Windows“启用或关闭Windows功能”中确保“Hyper-V”和“Windows虚拟机监控程序平台”已勾选。对于WSL2后端还需要启用“适用于Linux的Windows子系统”。Mac较新的Mac无需特别设置。如果使用旧版Docker Desktop需在“安全性与隐私”中允许系统软件。任务管理器Windows或活动监视器Mac查看CPU虚拟化是否已启用。问题2docker pull镜像速度极慢。原因默认从Docker Hub拉取国内网络访问可能较慢。解决配置国内镜像加速器。在Docker Desktop的设置Settings - Docker Engine中添加镜像仓库地址{ registry-mirrors: [ https://registry.docker-cn.com, https://hub-mirror.c.163.com, https://mirror.baidubce.com ] }修改后点击“Apply Restart”。问题3容器内应用无法访问宿主机服务或外部网络。原因网络模式或防火墙问题。排查默认的bridge模式下容器通过docker0网桥与外界通信。访问宿主机服务应使用宿主机在docker网络中的IP通常是172.17.0.1而不是localhost。检查宿主机防火墙是否放行了相关端口。6.2 Kubernetes常见问题问题1Pod一直处于Pending状态。排查命令kubectl describe pod pod-name # 查看Pod的详细事件这是最重要的命令 kubectl get nodes # 查看节点状态是否Ready kubectl describe node node-name # 查看节点详情是否有资源不足的污点Taint常见原因资源不足节点CPU或内存不足。查看kubectl describe node输出中的Allocatable和Allocated。没有匹配的节点Pod有节点选择器nodeSelector或亲和性affinity要求但没有节点满足。存储卷无法绑定PVC找不到合适的PV绑定一直处于Pending状态。问题2Pod处于CrashLoopBackOff或Error状态。排查命令kubectl logs pod-name [-c container-name] # 查看容器日志定位应用错误 kubectl describe pod pod-name # 查看事件可能看到容器启动失败的原因如镜像拉取失败、命令执行错误 kubectl exec -it pod-name -- /bin/sh # 进入容器内部排查如果容器能启动常见原因应用本身错误查看日志通常是代码bug、配置错误、依赖服务连接不上。镜像拉取失败kubectl describe pod事件中会有Failed to pull image错误。检查镜像名、标签是否正确镜像仓库权限是否足够。启动命令错误在kubectl describe pod中查看容器的Command和Args是否正确。存活探针Liveness Probe失败应用启动慢探针检查太频繁导致容器被重启。调整探针的initialDelaySeconds、periodSeconds和failureThreshold参数。问题3Service无法访问。排查命令kubectl get svc service-name # 查看Service的ClusterIP和端口 kubectl get endpoints service-name # 查看Service背后关联的Pod IP和端口列表如果为空说明selector不匹配 kubectl get pods -l appyour-label # 检查Pod的标签是否与Service的selector匹配 kubectl run -it --rm --imagebusybox testpod -- sh # 启动一个临时调试Pod在集群内测试网络连通性 # 进入busybox Pod后执行 # nslookup service-name # 测试DNS解析 # wget -O- service-cluster-ip:port # 测试网络连通常见原因标签不匹配Service的selector与Pod的labels不一致导致Endpoints为空。端口映射错误Service的targetPort与Pod容器暴露的containerPort不一致。网络插件问题集群网络插件如Calico、Flannel工作异常。Pod本身服务未就绪确保Pod内的应用已经在监听指定端口。问题4Ingress不生效返回404或无法连接。排查命令kubectl get ingress # 查看Ingress状态ADDRESS字段是否为空 kubectl describe ingress ingress-name # 查看Ingress事件 kubectl get pods -n ingress-controller-namespace # 查看Ingress Controller的Pod是否运行 kubectl get svc -n ingress-controller-namespace # 查看Ingress Controller的Service确认其类型通常是LoadBalancer或NodePort和外部IP/端口常见原因Ingress Controller未部署或未运行这是最可能的原因。你必须先部署一个Ingress Controller如nginx-ingress。Ingress规则配置错误检查host和path是否正确backend的serviceName和servicePort是否与你的Service匹配。防火墙/安全组规则在云平台上需要确保Ingress Controller Service对应的负载均衡器或节点端口的防火墙规则允许外部流量如80/443端口。掌握这些排查思路和命令就像拥有了一个强大的工具箱能帮你快速定位和解决大部分常见问题。记住kubectl describe和kubectl logs是你最好的朋友。