最近两年,我身边不少做后端开发、测试甚至前端的朋友,都开始频繁地问我同一个问题:“现在学 Docker 和 K8S 还来得及吗?感觉不会这些,简历都过不了。” 这背后反映的,远不止是几个技术工具的流行,而是一个更根本的趋势: 软件交付和运维的“基础设施”正在从物理机、虚拟机,不可逆地转向以容器和编排为核心的新范式。 你可能会觉得,我只是个写代码的,或者我只是个维护服务器的,这些“运维”的东西离我很远。但现实是,当你的应用需要快速部署、弹性伸缩、故障自愈时,当团队需要统一开发、测试、生产环境时,理解这套体系,已经从“加分项”变成了“必选项”。

然而,很多初学者面对 Docker 和 K8S 时,容易陷入两个极端:要么被一堆晦涩的概念(Pod、Service、Ingress、Operator)吓退,觉得这是运维专家的领域;要么跟着教程敲了几条命令,跑通了 docker run kubectl apply ,就以为掌握了精髓,结果一遇到真实的多节点部署、网络配置、存储挂载或滚动更新就束手无策。 Docker 和 K8S 的真正价值,不在于你记住了多少命令,而在于你是否理解了它们如何重塑了从代码到服务的整个生命周期管理逻辑。

所以,这篇文章不会是一个简单的命令手册或视频教程的文字版。我想和你探讨的是,作为一个“零基础”的开发者或运维人员,如何构建一个 系统且可落地 的 Docker 与 K8S 认知与实践体系。我们会从“为什么需要它们”这个最根本的问题出发,一步步拆解核心概念,并最终落到一个可以亲手搭建和操作的迷你实战环境上。目标是让你不仅能“跑起来”,更能明白“为什么这么跑”,以及“下一步该往哪里跑”。

1. 先破除迷雾:Docker 和 K8S 到底解决了什么问题?

在一头扎进命令和配置文件之前,我们必须先搞清楚,这两个技术究竟在为什么样的困境提供解决方案。这决定了你学习时的侧重点和思考方式。

1.1 从“它在我这跑得好好的”说起:环境一致性问题

这是最经典,也最刺痛开发者的问题。开发人员在 Mac 上基于 Node.js 18 开发,测试环境是 CentOS 7 上的 Node.js 16,生产环境则是 Ubuntu 上的 Node.js 18 但系统库版本不同。结果就是:“本地没问题,测试环境报错,线上直接崩溃。”

传统解决方案 是编写冗长的环境配置文档(Ansible Playbooks, Shell 脚本),或者提供完整的虚拟机镜像。前者维护成本高,易出错;后者笨重(动辄GB级),启动慢,资源利用率低。

Docker 带来的改变 :它将应用及其 完整的运行依赖 (代码、运行时、系统工具、系统库、设置)打包成一个轻量级、可移植的“镜像”。这个镜像可以在任何安装了 Docker 引擎的机器上,以完全一致的方式运行起来,形成一个隔离的“容器”。 它解决的不是“安装软件”,而是“交付一个确定性的运行环境单元”。 你可以把它理解为一个超级轻量、标准化的“软件集装箱”,里面装好了运行应用所需的一切。

1.2 从“服务器挂了怎么办”说起:应用高可用与弹性伸缩问题

单个容器解决了环境一致性问题,但生产环境面临更多挑战:如何保证应用7x24小时可用?流量高峰时如何快速扩容?某个实例崩溃了如何自动恢复?如何高效地管理成百上千个容器?

传统解决方案 可能是购买多台服务器做负载均衡,写监控脚本自动重启服务,但扩容缩容慢,配置复杂,各服务间的依赖和资源调度是一团乱麻。

Kubernetes (K8S) 登场 :它是一个生产级别的 容器编排系统 。你可以告诉 K8S:“我需要运行 3 个副本的我的 Web 应用容器,它们需要能被外部访问,并且当 CPU 使用率超过 70% 时自动扩容到 5 个,如果某个容器挂了就自动重启它。” K8S 会自动帮你调度这些容器到集群中的合适节点上运行,并持续监控状态,确保实际运行状态始终符合你的“期望状态”。 它解决的是容器化应用的“编排”、“调度”和“声明式管理”问题。

1.3 核心关系再澄清:不是替代,是协作

很多人会混淆 Docker 和 K8S 的关系,甚至认为 K8S 是 Docker 的替代品。这是错误的。

  • Docker 是一个 容器运行时引擎 ,负责创建和运行单个容器。它是“集装箱”的制造和运行标准。
  • Kubernetes 是一个 容器编排平台 ,负责管理大量 Docker(或其他符合标准的)容器,决定它们在哪儿运行、如何联网、如何存储、如何更新。它是管理成千上万个“集装箱”的“超级港口自动化系统”。

简单说: Docker 用来“造”和“跑”容器,K8S 用来“管”一大堆容器。 现在 K8S 为了更开放,已经支持多种容器运行时(如 containerd),但 Docker 仍然是其中最流行、生态最完善的一个,也是最佳的学习起点。

2. 零基础实战第一步:搭建你的 Docker 游乐场

理论之后,必须动手。我们避开复杂的生产环境,从单机学习开始。目标是在你的机器上建立一个可用的 Docker 环境,并完成“拉取镜像 -> 运行容器 -> 定制镜像 -> 挂载数据”的核心操作闭环。

2.1 环境准备与安装

对于绝大多数学习者,我强烈建议在 Linux 系统 上学习 Docker。这能让你更贴近生产环境,避免在 Windows 或 Mac 上遇到各种因平台差异导致的诡异问题。最简单的方式是使用一台云服务器(如腾讯云、阿里云的轻量应用服务器,选择 Ubuntu 22.04 LTS 或 CentOS 7.9/8),或者在你的电脑上通过 VirtualBox/VMware 安装一个 Linux 虚拟机。

安装 Docker 本身非常简单,以 Ubuntu 为例:

# 1. 更新软件包索引
sudo apt-get update

# 2. 安装必要的依赖包,以便 apt 可以通过 HTTPS 使用仓库
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

# 3. 添加 Docker 的官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 4. 设置稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 5. 再次更新,并安装 Docker CE (社区版)
sudo apt-get update
sudo apt-get install -y docker-ce

# 6. 验证安装,运行 hello-world 镜像
sudo docker run hello-world

如果看到 “Hello from Docker!” 的输出,恭喜你,Docker 引擎安装成功。

注意 :默认情况下,运行 docker 命令需要 sudo 权限。为了方便,可以将当前用户加入 docker 用户组: sudo usermod -aG docker $USER ,然后 退出终端重新登录 即可生效。

2.2 核心四步走:体验 Docker 工作流

现在,让我们通过四个核心操作,感受 Docker 的魔力。

第一步:拉取镜像 镜像是容器的模板。Docker Hub 是一个公共镜像仓库。

# 拉取一个 Nginx 镜像
docker pull nginx:latest
# 查看本地已有镜像
docker images

第二步:运行容器 基于镜像,启动一个容器实例。

# 运行一个 Nginx 容器,并将容器的 80 端口映射到主机的 8080 端口
docker run -d -p 8080:80 --name my-nginx nginx
  • -d : 后台运行。
  • -p 8080:80 : 端口映射,主机端口:容器端口。
  • --name : 给容器起个名字。 访问 http://你的服务器IP:8080 ,你应该能看到 Nginx 欢迎页。

第三步:进入容器与修改 容器是运行中的实例,我们可以进去看看。

# 进入正在运行的容器内部
docker exec -it my-nginx /bin/bash
# 此时你就在容器的 Linux 环境里了,可以执行 ls, cat 等命令
# 退出容器输入 exit

但容器内的修改是临时的。如果删除容器,修改会丢失。为了持久化,我们需要 挂载卷

第四步:数据持久化与定制镜像 将主机上的目录挂载到容器内,实现数据持久化。

# 1. 先在主机创建目录和自定义首页
mkdir -p ~/my-nginx-html
echo "<h1>Hello from My Custom Nginx!</h1>" > ~/my-nginx-html/index.html

# 2. 运行新容器,挂载主机目录到容器内的 /usr/share/nginx/html
docker run -d -p 8081:80 -v ~/my-nginx-html:/usr/share/nginx/html --name my-custom-nginx nginx

访问 8081 端口,看到的是你的自定义页面。即使容器重启或删除,主机上的 ~/my-nginx-html 目录下的文件依然存在。

如果这个自定义的 Nginx 配置(比如加了特定模块或配置文件)想分享给别人,可以基于运行中的容器 构建新镜像 ,但更规范的做法是使用 Dockerfile 。这是 Docker 的“构建说明书”,因篇幅所限,这里不展开,但它是你从 Docker 使用者迈向构建者的关键一步。

3. 攀登下一阶:理解 K8S 的核心抽象与最小集群搭建

当你熟悉了 Docker 的单机操作,并意识到要管理多个相互协作的容器(比如一个 Web 应用需要容器、Redis 容器、MySQL 容器)非常麻烦时,就是引入 K8S 的时候了。K8S 的学习曲线更陡,因为它引入了一套全新的抽象概念。

3.1 必须理解的 K8S 核心抽象

不要死记硬背,把它们想象成 K8S 这个“操作系统”提供给应用的管理单元。

  1. Pod :K8S 管理和调度的 最小单位 。一个 Pod 可以包含一个或多个紧密关联的容器(比如主应用容器和一个日志收集 sidecar 容器),它们共享网络和存储空间。 Pod 是短暂的,会被频繁地创建和销毁。
  2. Deployment :这是你 最常打交道 的对象。它定义了一个 Pod 的模板以及期望的副本数量。Deployment 负责确保任何时候都有指定数量的 Pod 副本在运行,并管理滚动更新和回滚。 它管理的是无状态应用。
  3. Service :Pod 的 IP 地址是不固定的。Service 提供了一个稳定的网络端点(一个固定的 ClusterIP 或对外暴露的 NodePort/LoadBalancer),将流量负载均衡到后端一组 Pod。 它是 Pod 的访问入口和负载均衡器。
  4. ConfigMap & Secret :将配置信息和敏感数据(如密码、密钥)从容器镜像中解耦出来,以键值对或文件的形式挂载到 Pod 中使用。实现了配置的集中管理和安全分发。
  5. Volume :K8S 中的存储抽象。Pod 中的容器可以访问 Volume 中存储的数据,即使 Pod 被重启或调度到其他节点,数据也能保留(取决于 Volume 类型)。

3.2 搭建一个最小化的 K8S 学习环境:Minikube

在生产中,K8S 集群至少需要多台机器(Master 和 Node)。对于学习,我们使用 Minikube ,它可以在单机上快速创建一个单节点的 K8S 集群。

安装与启动 Minikube (以 Linux 为例)

# 1. 安装 Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 2. 启动集群 (需要提前安装好 Docker)
minikube start --driver=docker
# 这个过程会下载镜像,初始化集群,需要几分钟。

# 3. 验证集群状态
minikube status
kubectl get nodes # kubectl 是操作 K8S 的命令行工具

如果 kubectl 命令未找到,需要安装:

# 安装 kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

3.3 你的第一个 K8S 应用:部署 Nginx

我们通过一个 YAML 文件来“声明”我们想要的应用状态。创建一个文件 nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment # 资源类型是 Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # 期望运行 2 个副本
  template: # Pod 模板
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service # 资源类型是 Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx # 选择标签为 app: nginx 的 Pod
  ports:
    - protocol: TCP
      port: 80 # Service 端口
      targetPort: 80 # 容器端口
  type: NodePort # 对外暴露端口的方式

执行部署:

kubectl apply -f nginx-deployment.yaml

查看状态:

# 查看 Deployment
kubectl get deployments
# 查看 Pod (应该能看到两个 Running 的 Pod)
kubectl get pods
# 查看 Service
kubectl get svc

kubectl get svc 会输出 nginx-service 的端口映射,比如 80:3xxxx/TCP 。通过 Minikube 访问:

minikube service nginx-service --url

这个命令会返回一个 URL,访问它就能看到 Nginx 页面。你已经成功在 K8S 上运行了一个高可用(2副本)的 Web 服务!

4. 从入门到实战:构建可复现的完整应用栈

单容器演示只是开始。真正的价值在于管理一个多组件的应用。让我们部署一个经典的“WordPress + MySQL”博客系统,将前面学的概念串联起来。

4.1 分解应用与资源定义

这个应用栈包含两个有状态组件:

  1. MySQL数据库 :需要持久化存储密码。我们将使用 Secret 存储密码,使用 PersistentVolumeClaim (PVC) 申请持久化存储。
  2. WordPress前端 :需要连接数据库。它将通过环境变量读取数据库连接信息(来自 Secret ),并通过 Service 访问 MySQL。

由于涉及多个 YAML 文件,我们使用一个目录来组织。创建以下文件:

1. mysql-secret.yaml (保存数据库密码)

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  password: cm9vdDEyMzQ1Ng== # "root123456" 的 base64 编码

2. mysql-pvc.yaml (为 MySQL 申请存储)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

3. mysql-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  ports:
    - port: 3306
  clusterIP: None # Headless Service,便于 WordPress Pod 通过域名发现

4. wordpress-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-deployment
spec:
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress:latest
        ports:
        - containerPort: 80
        env:
        - name: WORDPRESS_DB_HOST
          value: mysql-service # 通过 Service 名访问
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress-service
spec:
  selector:
    app: wordpress
  ports:
    - port: 80
      targetPort: 80
  type: NodePort

4.2 部署与访问

按顺序应用这些配置:

kubectl apply -f mysql-secret.yaml
kubectl apply -f mysql-pvc.yaml
kubectl apply -f mysql-deployment.yaml
kubectl apply -f wordpress-deployment.yaml

检查所有资源是否就绪:

kubectl get pods,svc,pvc

等待所有 Pod 状态变为 Running 。然后获取 WordPress 的访问地址:

minikube service wordpress-service --url

用浏览器打开返回的 URL,你就会看到 WordPress 著名的安装界面。按照提示完成安装,你的博客就运行在了由 K8S 管理的容器化环境中。即使重启 Minikube,你的博客数据(存储在 PVC 中)也会得以保留。

4.3 复盘与关键点

这个实战案例虽然简单,但涵盖了 K8S 的核心工作流:

  1. 声明式配置 :你用 YAML 文件描述了“最终想要的状态”。
  2. 控制器模式 :Deployment、Service 等控制器会持续工作,驱动集群向声明的状态收敛。
  3. 服务发现 :WordPress 容器通过 mysql-service 这个 DNS 名称访问 MySQL,无需关心 Pod IP。
  4. 配置与数据分离 :密码放在 Secret ,数据库文件放在 PVC ,与容器镜像解耦。
  5. 故障恢复 :如果某个 WordPress Pod 挂了,Deployment 会自动创建一个新的。

5. 超越入门:构建持续学习与实践的路径

当你成功运行起上述环境,你只是拿到了进入容器化世界的门票。要真正掌握它,你需要一个系统性的进阶路径。

5.1 知识深化:必须啃下的核心概念

  • 网络 :Pod 之间如何通信?Service 的 ClusterIP/NodePort/LoadBalancer 区别?Ingress 如何做七层路由?
  • 存储 :PV、PVC、StorageClass 的关系。不同存储类型(本地、NFS、云盘)如何选择?
  • 配置管理 :ConfigMap 的热更新问题。如何安全地使用 Secret?
  • 工作负载控制器 :除了 Deployment,还有 StatefulSet(用于有状态应用,如数据库)、DaemonSet(每节点运行一个,如日志收集)、Job/CronJob(批处理任务)。
  • 安全 :ServiceAccount, Role, RoleBinding (RBAC 权限控制)。Pod 安全策略。
  • 运维 :如何监控(Prometheus + Grafana)?如何查看日志(集中式日志收集)?如何调试( kubectl exec , kubectl logs , kubectl describe )?

5.2 实践进阶:从 Minikube 到真实环境

  1. 搭建多节点集群 :使用 kubeadm 工具在 2-3 台虚拟机上手动搭建一个集群。这会让你彻底理解 Master 组件(API Server, Scheduler, Controller Manager, etcd)和 Node 组件(kubelet, kube-proxy, 容器运行时)的作用。
  2. 尝试托管 K8S 服务 :在阿里云 ACK、腾讯云 TKE 或华为云 CCE 上创建一个托管集群。体验云厂商如何简化 Master 节点的管理,并学习如何与云上网络、存储服务集成。
  3. 学习 Helm :当应用包含几十个 YAML 文件时,管理和部署变得困难。Helm 是 K8S 的“包管理器”,通过模板和值文件来定义、安装和升级复杂的 K8S 应用。
  4. CI/CD 集成 :将你的代码仓库(GitLab/GitHub)与 K8S 集群连接,实现提交代码后自动构建 Docker 镜像、推送镜像仓库、并更新 K8S 中的 Deployment,完成自动化部署(GitOps 工具如 ArgoCD 是更高级的选择)。

5.3 建立排查思维:当 Pod 状态不是 Running 时

这是运维 K8S 的日常。建立一个固定的排查顺序:

  1. 看 Pod 状态 kubectl get pods 看状态是 Pending CrashLoopBackOff 还是 Error
  2. 描述 Pod 详情 kubectl describe pod <pod-name> ,重点关注 Events 部分,这里常有调度失败、镜像拉取失败、资源不足等关键信息。
  3. 查看容器日志 kubectl logs <pod-name> [-c <container-name>] ,直接看应用输出的日志。
  4. 进入 Pod 调试 kubectl exec -it <pod-name> -- /bin/sh ,进入容器内部检查环境变量、配置文件、网络连通性。
  5. 检查相关资源 :检查对应的 Deployment、Service、ConfigMap、PVC 等资源配置是否正确。

学习 Docker 和 K8S,本质上是在学习一套全新的、以“声明式”和“自动化”为核心的软件交付与运维哲学。它开始可能显得复杂,但一旦你习惯了这种“描述目标,而非执行过程”的思维方式,并建立起从单容器到多服务编排的清晰心智模型,你就会发现,它带来的环境一致性、部署速度和系统弹性,是传统方式难以比拟的。不要试图在一天内记住所有命令,先从理解核心概念和完成一次完整的部署闭环开始,然后在不断的实践和解决问题中,让这些知识真正内化。这条路没有捷径,但每一步都算数。

更多推荐