资讯动态

Docker与K8s关系全解:从容器镜像到K8s编排落地实战

发布时间:2026/9/18 18:12:34 来源:尧图企业网站定制
先把一个常见误区摆到台面上很多人刚接触容器技术时会把 Docker 和 Kubernetes下称 K8s当成“二选一”的竞品甚至在群里问“现在都上 K8s 了Docker 是不是要被淘汰了”。这个问题我这些年被问过不下几十次每次都得先纠正一个前提——它们压根就不在一个层面上解决问题。Docker 解决的是“把应用和它的运行环境打包成一个标准单元”K8s 解决的是“当你有几十上百个这样的单元时怎么让它们稳定、有序、可扩展地跑起来”。打个不太严谨的比方Docker 像集装箱K8s 像港口调度系统没有集装箱港口无货可运只有集装箱没有调度系统港口会乱成一锅粥。这篇文章想聊的正是 k8s 和 docker 之间的关系以及围绕它们衍生出来的一整套落地实践从 Docker 的镜像、容器、仓库三件套到 K8s 的编排、调度、自愈机制再到单节点集群搭建、常见命令、安装踩坑、迁移上云的思路。不管你是刚装完 Docker Desktop 想进一步了解容器编排的新手还是已经在维护 K8s 集群、想回头把底层逻辑梳理清楚的老手都能从里面找到对自己有用的部分。我会尽量把原理讲透把容易踩的坑提前标出来同时给出可以直接抄作业的命令和配置。1. 先把概念摆正Docker 和 K8s 根本不在一个层面上很多争论之所以吵不出结果是因为双方对“它们是什么”的定义都没对齐。所以我习惯先把两者的定位讲清楚后面所有讨论才有共同语言。1.1 Docker 是容器化工具不是编排工具Docker 最核心的价值是把一个应用及其依赖代码、运行时、系统工具、库、配置打包成一个轻量、可移植、自包含的镜像然后以容器的形式运行。它关心的是“单个或少量容器怎么构建、怎么跑起来、怎么分发”。我平时最常用的几个动作无非就是# 构建镜像 docker build -t myapp:1.0 . # 运行容器 docker run -d -p 8080:8080 --name myapp myapp:1.0 # 查看运行中的容器 docker ps # 进入容器排查 docker exec -it myapp /bin/sh这些命令解决的都是“单机、单容器或少数量容器”的问题。Docker 本身也提供了docker-compose来做多容器编排可以定义服务依赖、网络、卷适合单机多容器场景但它的能力边界也就在这里跨主机调度、故障自愈、滚动更新、服务发现docker-compose原生做得并不好。注意Docker Compose 适合开发环境和单机多服务场景比如本地起一个 MySQL Redis 应用的组合。生产环境尤其是多节点集群还是得靠 K8s 这类编排系统。1.2 K8s 是容器编排系统不负责“造容器”K8s 的定位是容器编排平台。它不关心你的镜像是用 Docker 构建的还是用 Buildah、Kaniko 构建的也不强制要求运行时必须是 Docker。它关心的是这个应用要跑几个副本ReplicaSet/Deployment副本应该调度到哪些节点Scheduler某个副本挂了怎么自动拉起来Controller Manager服务之间怎么互相发现Service/DNS怎么对外暴露Ingress/NodePort/LoadBalancer配置和密钥怎么管理ConfigMap/Secret有状态应用怎么稳定存储StatefulSet/PV/PVC换句话说Docker 负责“把东西装进集装箱”K8s 负责“决定集装箱放在哪个码头、什么时候装卸、坏了一个怎么补上”。两者是上下游关系不是替代关系。1.3 为什么总有人觉得它们在“打架”这个误解主要来自两个变化。第一K8s 早期确实把 Docker 当作默认容器运行时后来引入了 CRI容器运行时接口把运行时抽象出来于是有了 containerd、CRI-O 等选择Docker 不再是唯一选项很多人就误读成“K8s 抛弃了 Docker”。第二Docker 公司自己也做过 Docker Swarm 编排和 K8s 是直接竞争关系Swarm 逐渐式微后大家又把“Swarm 的失败”和“Docker 的失败”混为一谈。实际上你现在用 Docker 构建镜像push 到镜像仓库再在 K8s 里拉取运行这条链路依然是最主流的工作流之一。Docker Desktop 里自带的单节点 K8s也是很多人入门 K8s 的第一站。对比维度DockerK8s核心定位容器化与镜像构建容器编排与集群管理作用范围单机为主跨节点集群典型命令build、run、pushkubectl apply、get、describe自愈能力需配合 restart 策略能力有限原生支持副本自动重建服务发现依赖 Compose 或手动配置原生 Service/DNS适用场景开发、单机部署、CI 构建生产集群、微服务、弹性伸缩2. 拆开看本质镜像、容器、仓库三件套到底怎么回事要真正理解两者的关系得先把 Docker 这套底层机制吃透因为 K8s 编排的对象本质上就是这些镜像和容器。2.1 镜像分层叠加的只读模板Docker 镜像采用联合文件系统UnionFS的分层结构。一个镜像由若干只读层叠加而成每一层对应 Dockerfile 里的一条指令。比如FROM openjdk:17-jre-slim WORKDIR /app COPY target/app.jar app.jar EXPOSE 8080 ENTRYPOINT [java,-jar,app.jar]这里FROM产生基础层COPY产生一个包含 jar 包的新层ENTRYPOINT只是元数据变更。分层最大的好处是复用和缓存多个镜像共享相同基础层时本地只需存一份构建时某层没变后面的层可以直接用缓存构建速度大幅提升。我踩过的一个坑是把COPY放在RUN安装依赖之前导致每次改一行代码依赖安装这一层缓存全部失效构建时间从两分钟变成十分钟。后来把依赖声明文件单独复制、先装依赖再复制源码缓存命中率一下就上来了。这个技巧在 Java、Node、Python 项目里都通用。注意镜像层是只读的。容器启动时会在镜像最上层加一个可写层所有运行时改动都写在这里。容器删除可写层也随之消失所以重要数据一定要挂载卷或外部存储。2.2 容器镜像的运行实例容器是镜像的运行态本质是一个被 Linuxnamespace隔离、被cgroups限制资源的进程。namespace 负责看得见的隔离PID、网络、挂载、UTS、IPC、用户cgroups 负责资源限额CPU、内存、IO。可以这样理解镜像是一张光盘容器是放进播放器里正在播放的碟片。同一张光盘可以放进多个播放器同时播放对应到 Docker 就是同一个镜像可以启动多个容器实例。常用操作我整理了一张速查表操作命令启动容器docker run -d --name 名称 镜像查看运行容器docker ps查看所有容器docker ps -a停止容器docker stop 名称删除容器docker rm 名称查看日志docker logs -f 名称进入容器docker exec -it 名称 /bin/sh查看资源占用docker stats2.3 仓库镜像的分发中心镜像是要分发的Docker Hub、私有 Harbor、各大云厂商的容器镜像服务都是仓库。docker push把本地镜像推到仓库docker pull从仓库拉到本地。K8s 调度时也是让节点上的运行时从仓库拉取镜像。这里有个经验生产环境一定要用私有仓库并且给镜像打不可变 tag不要用latest。我见过太多因为latest被覆盖导致线上回滚困难的案例。正确做法是 tag 里带上 git commit 号或构建号比如myapp:20240521-a3f9c1这样任何一个历史版本都能精确还原。3. K8s 补位的那些事编排到底编排了什么弄明白了 Docker 的能力边界就能理解 K8s 为什么必须存在。当你有几十个微服务、几百个容器实例分布在多台机器上时靠手动docker run管理基本就是灾难。3.1 调度把容器放到合适的节点上K8s 的 Scheduler 负责给每个待创建的 Pod 选择节点。它会综合节点资源、亲和性/反亲和性、污点与容忍、拓扑分布等策略。你可以通过nodeSelector、affinity指定调度偏好。比如想避免同一服务的多个副本挤在一台机器上affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: myapp topologyKey: kubernetes.io/hostname这段配置的意思是尽量让带app: myapp标签的 Pod 分散到不同主机上降低单机故障带来的影响。3.2 自愈副本掉了自动补Deployment 声明期望副本数Controller Manager 持续对比实际状态与期望状态一旦发现副本不足就重建。这就是所谓的声明式 API你告诉 K8s“我要三个副本”至于怎么达成它自己想办法。我实测过一个场景三副本的 Deployment手动删掉一个 Pod大约几秒到十几秒内就会有新 Pod 被创建出来。这个速度取决于镜像拉取、调度和启动探针配置。如果镜像在节点上已经有缓存恢复会非常快。3.3 服务发现与负载均衡Service 是核心Pod 的 IP 是不固定的重建后就会变。所以 K8s 引入了 Service为一组 Pod 提供稳定的虚拟 IP 和 DNS 名称。ClusterIP 供集群内访问NodePort 暴露到节点端口LoadBalancer 通常结合云厂商负载均衡使用。apiVersion: v1 kind: Service metadata: name: myapp-svc spec: selector: app: myapp ports: - port: 80 targetPort: 8080 type: ClusterIP集群内的其他服务就可以通过myapp-svc或myapp-svc.default.svc.cluster.local访问它完全不用关心后端 Pod 的具体 IP。3.4 配置与密钥ConfigMap 和 Secret把配置从镜像里剥离出来是云原生的一条基本原则。ConfigMap 存普通配置Secret 存敏感信息Base64 编码注意不是加密。这样同一个镜像可以在不同环境用不同配置启动不用重新构建。注意Secret 默认只是 Base64 编码不安全。生产环境建议开启 etcd 加密并配合 RBAC 严格控制读取权限。4. 落地实操从 Docker 单机到 K8s 集群的路径概念讲完接下来是实打实的操作。我按“先单机、后集群”的顺序来这样新手不会被一上来就劝退。4.1 Windows 上装 Docker Desktop 的常见坑Windows 装 Docker Desktop最容易卡在虚拟化检测这一步。启动时报virtualization support not detected或failed to start because virtualisation support wasnt detected基本都是两个原因BIOS/UEFI 里没开虚拟化Intel VT-x 或 AMD-VWindows 功能里的 Hyper-V 或 WSL2 没启用排查顺序建议这样先确认 BIOS 里虚拟化已开启再在“启用或关闭 Windows 功能”里勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”然后重启。用 WSL2 后端一般比 Hyper-V 后端更顺滑。还有个报错failed to connect to the docker API at npipe:////./pipe/dockerDesktopLinuxEngine通常是 Docker Desktop 服务没起来。可以尝试在服务里重启 Docker Desktop Service或者干脆退出程序重新打开。如果还不行检查是否有杀毒软件拦截了管道通信。至于docker 权限错误怎么解决Linux 下最常见的是没把当前用户加入 docker 组sudo usermod -aG docker $USER # 重新登录后生效4.2 Linux 上安装 Docker 的稳妥流程以 Ubuntu 为例我一般走官方仓库安装避免用发行版自带的旧版本sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release echo $VERSION_CODENAME) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin国内拉镜像慢的话可以配置镜像加速源。这里不展开具体地址思路是在/etc/docker/daemon.json里配置registry-mirrors然后systemctl restart docker。对于离线环境比如内网服务器、国产化环境如龙芯平台就需要提前在有网的机器上把 deb/rpm 包和依赖下载齐全或者直接导出镜像 tar 包用docker load导入。docker save -o myapp.tar myapp:1.0 docker load -i myapp.tar4.3 用 Docker 跑常用中间件的实际配置光跑个 hello world 没意思我拿几个高频场景演示。MySQL 8.0docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpass \ -v /data/mysql:/var/lib/mysql \ mysql:8.0 \ --character-set-serverutf8mb4 \ --collation-serverutf8mb4_unicode_ci关键点在于挂载/var/lib/mysql不然容器一删数据全没。字符集参数也建议显式指定免得后期乱码返工。Redis 主从可以先起一个 master再起从节点并指定--replicaof。生产环境还要考虑哨兵或 Cluster 模式单纯主从在主挂掉后需要手动切换。docker run -d --name redis-master -p 6379:6379 redis:7 docker run -d --name redis-slave -p 6380:6379 redis:7 redis-server --replicaof redis-master 6379GitLab容器化部署 GitLab 一定要预留足够内存低于 4G 基本跑不起来启动过程也比较慢属于正常现象。Docker Compose 则适合把这些组合起来version: 3.8 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: yourpass volumes: - ./mysql:/var/lib/mysql redis: image: redis:7 app: build: . depends_on: - mysql - redis ports: - 8080:8080一套docker compose up -d就能把整套开发环境拉起来这是单机阶段最舒服的体验。4.4 单节点 K8s 搭建先用 minikube 或 Docker Desktop 入门想学 K8s不必一上来就搭多节点。minikube、kind、Docker Desktop 自带的 K8s 都提供单节点环境足够跑通大部分概念。用 minikube 的典型流程minikube start --cpus4 --memory8g kubectl get nodes kubectl create deployment myapp --imagemyapp:1.0 kubectl expose deployment myapp --port80 --target-port8080 kubectl get pods,svc如果是国内网络minikube start拉基础镜像可能很慢可以提前指定镜像仓库或使用本地缓存的镜像。也可以直接用 kind把节点作为 Docker 容器跑起来速度更快。在单节点上部署一整套若依微服务是很多人验证学习成果的经典场景网关、认证、系统服务、业务服务、MySQL、Redis、Nacos 全部容器化。资源吃紧的话建议把 Nacos 换成单机模式MySQL 内存限制调低并给节点留出至少 4G 到 8G 空闲内存。工具适用场景优点注意点minikube本地学习、功能验证安装简单、文档全资源占用较高kindCI、快速验证启动快、基于容器网络配置稍复杂Docker Desktop K8sWindows/Mac 入门一键启用资源受限、生产不适用kubeadm生产集群搭建官方标准、可控性强需要手动处理网络插件4.5 多节点集群与监控kubeadm Prometheus生产或准生产集群kubeadm 是主流选择。大致步骤是初始化控制平面、安装网络插件Calico、Flannel 等、加入工作节点、部署存储和 Ingress。监控方面Prometheus Grafana 几乎是标配。用 Helm 安装 kube-prometheus-stack 最省事helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm install monitor prometheus-community/kube-prometheus-stack -n monitoring --create-namespace装完后重点关注节点 CPU/内存、Pod 重启次数、API Server 延迟、etcd 健康度这几类指标。很多线上故障的早期信号都能在 Pod 重启次数和资源水位上提前看出来。5. 常见命令与问题排查实录学 K8s 最忌只看不练。这一部分我把高频命令和真实踩坑整理出来方便随时查阅。5.1 kubectl 高频命令速查kubectl get pods -A -o wide # 查看所有命名空间 Pod kubectl describe pod name # 查看 Pod 详情与事件 kubectl logs -f pod -c container # 跟踪日志 kubectl exec -it pod -- /bin/sh # 进入容器 kubectl apply -f deploy.yaml # 应用配置 kubectl rollout status deploy/name # 查看滚动更新状态 kubectl rollout undo deploy/name # 回滚 kubectl top pod # 查看资源占用describe是排查问题的第一入口事件区往往会直接告诉你镜像拉取失败、调度失败还是探针失败。5.2 典型故障与排查思路现象常见原因排查方向Pod 一直 Pending资源不足、污点、亲和性不满足describe 看 EventsImagePullBackOff镜像名错、私有仓库无凭证检查 imagePullSecretsCrashLoopBackOff应用启动失败、配置错误看 logs 和上一次日志OOMKilled内存超限调高 limits 或优化内存Service 无法访问selector 不匹配、端口错检查 endpoints节点 NotReadykubelet 异常、网络插件故障查看 kubelet 日志我印象最深的一次是某个服务一直 CrashLoopBackOff日志里没有异常最后发现是探针配置的初始延迟太短应用还没启动完就被判定失败重启。把initialDelaySeconds调大后问题消失。所以探针参数一定要结合应用实际启动时间设置不能盲抄。5.3 几个容易被忽视的运维细节第一资源 requests/limits 要设置。不设 limits 的 Pod 可能把节点资源吃光拖垮同节点其他服务不设 requests 则调度器无法准确评估容易超卖。第二优雅关闭要配置。应用要正确处理 SIGTERM配合terminationGracePeriodSeconds否则滚动更新时会丢请求。第三镜像要瘦身。用 alpine、distroless 或 jre-slim 基础镜像减少攻击面也加快拉取。Java 应用还可以用分层构建或 jlink 裁剪 JRE。第四命名空间要规划。按环境或团队划分 namespace配合 ResourceQuota 和 LimitRange避免资源被单方占用。6. 迁移上云与持续演进的实践考量学到一定程度很多人会遇到把本地单节点环境迁移到云端 ECS 或托管 K8s 的需求。这里面的门道不少。6.1 不停服、不丢数据迁移的基本思路目标通常是“准不停服、不丢数据”。核心思路是数据层先行、流量最后切换。以若依微服务为例大致可分几步在云端搭好 K8s 集群和中间件MySQL、Redis 数据先用从库同步应用镜像推到云端仓库配置改指向云端中间件用 DNS 或负载均衡权重做灰度先切一小部分流量观察无异常后全量切换保留旧环境一段时间做回滚兜底数据同步确认无延迟后再正式下线旧库压测环节一般会用 JMeter 脚本模拟高并发重点看云上环境的承载能力确认扩容策略、数据库连接池、限流配置是否经得住。注意迁移最怕数据不一致。切换前一定要核对主从延迟最好在业务低峰期操作并准备好回滚预案。6.2 服务网格与 Dubbo 的结合微服务数量上来之后服务间的流量治理、熔断、链路追踪会变得复杂。Dubbo 本身有服务治理能力而 K8s Service Mesh如 Istio在基础设施层提供流量管理。两者结合的方式通常是让 Dubbo 专注 RPC 语义Mesh 负责东西向流量、mTLS 和可观测性。是否引入 Mesh 要权衡复杂度中小团队先把基础监控和限流做扎实往往比直接上 Mesh 收益更高。6.3 学习路径与资料选择我看到很多人搜k8s权威指南第五版pdf下载这类关键词找资料。书确实系统但我的建议是边动手边看。先装 Docker跑通几个容器再用 minikube 理解 Pod、Deployment、Service然后尝试用 kubeadm 搭一个两节点集群最后把一套真实微服务部署上去。这套路径走下来比只看书理解得深得多。面试场景下高频问题一般集中在Pod 生命周期、Deployment 与 StatefulSet 区别、Service 类型、探针类型与作用、ConfigMap/Secret 用法、调度机制、网络模型等。这些只要亲手实践过回答起来会很有底气。回到最开始那个问题——k8s 和 docker 之间到底是什么关系我的答案是Docker 让容器变得好用且标准化K8s 让容器在规模化和生产化场景下变得可控可管。它们是容器技术演进的两个阶段而不是同一赛道的对手。理解了这一层再去学具体命令和架构就不会被各种“谁取代谁”的说法带偏。我自己从最早用docker run起单个服务到后来管几十个微服务的集群这一路最大的体会是底层机制想清楚了上层工具换来换去都不慌。

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

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

免费获取报价