从Docker到K8S:新手避坑指南与实战入门

📅 2026/7/7 23:15:54 👁️ 阅读次数 📝 编程学习
从Docker到K8S:新手避坑指南与实战入门

🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度

这类教程最值得先看的不是它覆盖了多少知识点,而是能不能帮你把 Docker 和 Kubernetes 从“知道名字”变成“能在自己机器上跑起来、能处理实际问题”。很多人学容器和 K8S 卡在第一步:环境装不上、概念太抽象、命令敲了没反应。这个教程的价值在于,它试图用一套连贯的流程,把安装、基础命令、核心概念和简单实战串起来,目标是让你看完能自己搭出一个可用的最小环境。

但这类“速通”教程也有个通病:容易讲成命令罗列,你跟着敲完了,还是不知道为什么要这么做,遇到自己项目里的配置文件、网络问题、存储挂载照样不会。所以,我更建议把学习过程拆成三步:先确保本地或虚拟机环境能稳定运行 Docker,再用 Docker 理解容器的基础操作和镜像构建,最后用 Minikube 或 K3s 这类轻量工具上手 K8S 的核心对象和调度。下面我会按这个实际落地的顺序,把每个环节的关键操作、参数含义和最容易踩的坑点拆解一遍。

1. 先别急着看 K8S,从 Docker 环境准备和最小验证开始

很多人一上来就被 Pod、Service、Deployment 这些概念绕晕了。其实 K8S 管理的是容器,而容器最直接的体验来自 Docker。所以第一步不是安装 K8S,而是先确保你的 Docker 能正常工作。

1.1 环境选择与基础安装:虚拟机还是云主机?

你可以在 Windows、macOS 或 Linux 上安装 Docker Desktop。但对于学习,尤其是后续要接触 K8S 网络和存储,我强烈建议使用一台 Linux 虚拟机。原因有两个:一是 Linux 是 Docker 和 K8S 的原生运行环境,兼容性问题最少;二是很多生产环境也是 Linux,提前熟悉命令行操作没坏处。

  • 方案一(推荐):本地虚拟机。使用 VirtualBox 或 VMware,安装一个 Ubuntu 22.04 LTS 或 CentOS 7/8 Stream。分配至少 2 核 CPU、4GB 内存和 20GB 磁盘空间。这个配置足够同时运行 Docker 和一个轻量级 K8S(如 Minikube)。
  • 方案二:云服务器。在主流云服务商购买一台最低配置的按量计费云服务器(通常被称为“ECS”或“CVM”),选择 Ubuntu 或 CentOS 镜像。好处是网络环境干净,且能模拟公网访问场景。

安装 Docker 本身很简单,以 Ubuntu 为例,官方的一键安装脚本通常可靠:

# 更新软件包索引 sudo apt-get update # 安装必要工具 sudo apt-get install ca-certificates curl # 添加 Docker 官方 GPG 密钥 sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # 设置仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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 # 安装 Docker 引擎 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装后,最关键的一步是将当前用户加入docker,避免每次命令都要加sudo

sudo usermod -aG docker $USER

执行后,你需要退出当前终端并重新登录,这个改动才会生效。这是第一个常见坑点:很多人加了组就直接运行docker ps,发现还是权限错误。

1.2 验证安装与理解 Docker 守护进程

环境装好,不要马上拉镜像跑容器。先做几个基础验证,理解 Docker 的组件。

  1. 检查 Docker 服务状态

    sudo systemctl status docker

    你应该看到active (running)。如果没启动,用sudo systemctl start docker启动它,并用sudo systemctl enable docker设置开机自启。

  2. 运行经典测试容器

    docker run hello-world

    这个命令会做几件事:从 Docker Hub 拉取hello-world镜像(如果本地没有),创建一个容器,执行容器内的程序(打印一段欢迎信息),然后容器退出。如果能看到成功输出的信息,说明 Docker 引擎、镜像拉取和容器运行都正常。

  3. 理解docker ps的输出

    docker ps -a

    -a参数会显示所有容器,包括已退出的。你会看到刚才运行的hello-world容器,状态是Exited。这里要理解几个关键字段:

    • CONTAINER ID: 容器的唯一标识。
    • IMAGE: 创建容器所用的镜像。
    • COMMAND: 容器启动时运行的命令。
    • STATUS: 容器的状态(Up、Exited)。
    • PORTS: 容器映射到主机的端口。
    • NAMES: 容器的名称(可自定义)。

这个阶段的目标是:确保 Docker 服务在运行,能拉取镜像,能创建和运行容器,并且你能看懂基础命令的输出。如果hello-world都跑不起来,问题通常出在网络(拉取镜像失败)、权限(用户不在 docker 组)或服务状态上。

2. 用 Docker 理解镜像、容器和基础操作

能跑通hello-world只是开始。接下来要通过一个更实际的例子,理解镜像和容器的关系,以及如何管理它们。

2.1 从拉取镜像到运行一个持久化服务

我们用一个最常用的镜像nginx来演示。

  1. 拉取镜像

    docker pull nginx:latest

    这里nginx是镜像名,latest是标签(Tag),代表最新稳定版。生产环境通常使用具体版本号,如nginx:1.24,以避免因镜像更新引入意外变更。

  2. 以后台模式运行一个 Nginx 容器

    docker run -d --name my-nginx -p 8080:80 nginx
    • -d: 后台运行(detached mode)。
    • --name my-nginx: 给容器起个名字,方便后续管理。
    • -p 8080:80: 端口映射,将主机的 8080 端口映射到容器的 80 端口(Nginx 默认监听端口)。
    • nginx: 使用的镜像。
  3. 验证服务: 在主机上打开浏览器,访问http://localhost:8080(如果主机是本地虚拟机)或http://<你的服务器IP>:8080(如果是云服务器)。你应该能看到 Nginx 的欢迎页面。 同时,用docker ps可以看到一个状态为Up的容器。

  4. 查看容器日志

    docker logs my-nginx

    这会输出容器内 Nginx 服务的访问日志和错误日志。这是排查容器内应用问题的第一个入口。

2.2 进入容器、修改内容与理解容器隔离性

容器是隔离的环境。怎么查看和修改里面的东西?

  1. 进入运行中的容器

    docker exec -it my-nginx /bin/bash
    • exec: 在已运行的容器中执行命令。
    • -it: 分配一个交互式终端(-i -t)。
    • /bin/bash: 要执行的命令,即启动一个 Bash shell。 进入后,你可以像操作一台独立 Linux 主机一样,使用ls,cat,apt-get update等命令。试试cat /etc/nginx/nginx.conf查看 Nginx 配置。
  2. 理解容器内修改的临时性: 在容器内,执行echo "Hello from container" > /usr/share/nginx/html/test.txt,然后在主机浏览器访问http://localhost:8080/test.txt,能看到你写的文字。 但是,如果你现在停止并删除这个容器:

    docker stop my-nginx docker rm my-nginx

    然后重新用docker run -d --name new-nginx -p 8080:80 nginx启动一个新容器,再去访问/test.txt,会发现文件不见了。这说明对容器内文件系统的修改,默认只存在于该容器的生命周期内,容器删除,修改即丢失。

  3. 使用数据卷(Volume)持久化数据: 为了解决上述问题,需要把容器内需要持久化的目录(如 Nginx 的 HTML 目录/usr/share/nginx/html)挂载到主机的一个目录上。

    # 先在主机创建一个目录 mkdir -p ~/nginx-html # 运行容器并挂载数据卷 docker run -d --name nginx-with-volume -p 8081:80 -v ~/nginx-html:/usr/share/nginx/html nginx
    • -v ~/nginx-html:/usr/share/nginx/html: 将主机的~/nginx-html目录挂载到容器的/usr/share/nginx/html。 现在,你在主机~/nginx-html目录下放一个index.html文件,刷新浏览器就能看到变化。即使删除容器,主机上的文件依然存在,重新挂载即可。

这个阶段的目标是:理解docker pull/run/ps/logs/exec/stop/rm这一套基础命令链,明白镜像(只读模板)和容器(运行时实例)的区别,并初步接触端口映射 (-p) 和数据持久化 (-v) 这两个核心概念。这是后续理解 K8S 中 Service 和 PersistentVolume 的基础。

3. 构建自定义镜像与编写 Dockerfile

只会用现成镜像不够,你需要知道如何把自己的应用打包成镜像。这就要用到 Dockerfile。

3.1 编写第一个 Dockerfile

假设你有一个简单的 Python Web 应用,文件结构如下:

my-python-app/ ├── app.py ├── requirements.txt └── Dockerfile
  • app.py内容:

    from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello from my custom Docker image!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
  • requirements.txt内容:

    flask==2.3.3
  • Dockerfile内容:

    # 第一阶段:使用官方 Python 轻量级镜像作为基础 FROM python:3.11-slim # 设置工作目录,后续命令都在此目录下执行 WORKDIR /app # 将依赖文件复制到工作目录 COPY requirements.txt . # 安装 Python 依赖,使用清华镜像源加速(国内环境) RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt # 将当前目录所有文件复制到工作目录 COPY . . # 声明容器运行时监听的端口 EXPOSE 5000 # 定义容器启动时执行的命令 CMD ["python", "app.py"]

3.2 构建镜像并运行

my-python-app目录下执行:

docker build -t my-python-app:1.0 .
  • -t my-python-app:1.0: 为镜像打上标签(名称:版本)。
  • .: 构建上下文路径,Docker 会把当前目录下的文件发送给 Docker 守护进程。

构建成功后,运行容器:

docker run -d --name my-app -p 5000:5000 my-python-app:1.0

访问http://localhost:5000,你应该能看到自定义的问候语。

3.3 Dockerfile 关键指令与最佳实践

  • FROM: 必须且是第一条指令。选择合适的基础镜像(如alpine,slim版本可以减小镜像体积)。
  • WORKDIR: 设置工作目录,代替RUN cd ... && ...这种复杂命令。
  • COPYvsADD: 优先使用COPY,它更透明。ADD有自动解压等额外功能,但行为不够清晰。
  • RUN: 执行命令并创建新的镜像层。合并多个RUN指令可以减少镜像层数,例如RUN apt-get update && apt-get install -y package1 package2 && rm -rf /var/lib/apt/lists/*
  • EXPOSE: 声明端口,是一种文档形式。实际映射端口仍需在docker run时用-p指定。
  • CMD: 指定容器启动时的默认命令。一个 Dockerfile 只能有一个CMD。通常格式是CMD ["executable", "param1", "param2"](exec 格式)。

这个阶段的目标是:能将自己的简单应用通过 Dockerfile 打包成镜像,理解镜像分层构建的概念,并掌握编写高效 Dockerfile 的几个基本原则。这是实现 CI/CD 和部署到 K8S 的前提。

4. 从单机 Docker 到 Kubernetes 初体验

理解了 Docker 之后,K8S 就不再是空中楼阁。它要解决的核心问题是:当你有成百上千个容器需要跨多台机器部署、管理、扩缩容和保持高可用时,该怎么办?

4.1 选择本地 K8S 环境:Minikube 还是 K3s?

对于学习和开发,不建议直接在生产 K8S 集群上操作。本地轻量级方案是首选。

  • Minikube: 官方维护的单节点 K8S 工具。它在你的机器上创建一个虚拟机,并在里面运行一个单节点的 K8S 集群。功能完整,最适合学习核心概念。
  • K3s: Rancher 发布的轻量级 K8S,易于安装,资源占用更少,甚至可以在树莓派上运行。它更适合边缘计算或资源受限的环境。

对于初学者,我推荐Minikube,因为它最贴近标准 K8S 的体验,且文档和社区支持最好。

4.2 安装并启动 Minikube

在已经安装好 Docker 的 Linux 虚拟机或 macOS/Windows 上,安装 Minikube。

  1. 安装 Minikube 二进制文件(以 Linux 为例):

    curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube
  2. 启动 Minikube 集群

    minikube start --driver=docker
    • --driver=docker: 指定使用 Docker 作为底层容器运行时。Minikube 会在 Docker 内部再启动一个运行 K8S 组件的容器。 首次启动会下载基础镜像,需要一些时间。成功后,你会看到类似Done! kubectl is now configured to use "minikube" cluster的提示。
  3. 配置 kubectlkubectl是管理 K8S 集群的命令行工具。Minikube 会自动为你配置好。验证一下:

    kubectl cluster-info kubectl get nodes

    你应该能看到一个名为minikube的节点,状态为Ready

4.3 部署第一个应用:理解 Pod 和 Deployment

在 K8S 中,最小的部署单元不是容器,而是Pod。一个 Pod 可以包含一个或多个紧密关联的容器。但通常我们不会直接创建 Pod,而是通过Deployment来管理 Pod 的副本和生命周期。

  1. 创建一个 Deployment 配置文件my-nginx-deployment.yaml

    apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 # 指定 Pod 副本数为 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.24 ports: - containerPort: 80
  2. 应用这个配置

    kubectl apply -f my-nginx-deployment.yaml
  3. 查看部署状态

    kubectl get deployments kubectl get pods

    你会看到nginx-deployment创建了 2 个 Pod。kubectl get pods的输出中,READY列显示1/1STATUSRunning时,表示 Pod 已就绪。

  4. 暴露服务:创建 Service。 Pod 的 IP 是临时的,且外部无法直接访问。需要通过Service来提供稳定的访问入口。 创建my-nginx-service.yaml

    apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx # 这个选择器必须匹配 Deployment 中 Pod 的标签 ports: - protocol: TCP port: 80 # Service 对外暴露的端口 targetPort: 80 # 容器内监听的端口 type: NodePort # 类型为 NodePort,会在集群每个节点上开放一个端口(范围 30000-32767)

    应用配置:kubectl apply -f my-nginx-service.yaml

  5. 访问应用: 获取 Service 的 NodePort:

    kubectl get service nginx-service

    在输出中找到PORT(S)列,例如80:30678/TCP,其中30678就是 NodePort。 由于我们使用 Minikube,可以通过以下命令快速获取访问 URL:

    minikube service nginx-service --url

    它会返回一个类似http://192.168.49.2:30678的地址,在浏览器中打开即可访问 Nginx。

这个阶段的目标是:在本地成功启动一个 K8S 集群(Minikube),使用kubectl命令与集群交互,并通过 YAML 文件定义并部署一个最简单的多副本应用(Deployment),最后通过 Service 将其暴露给外部访问。理解Deployment -> Pod -> Container的层次关系,以及Service通过标签选择器 (selector) 关联 Pod 的机制,是 K8S 入门的核心。

5. 深入 K8S 核心概念与日常操作

掌握了基本部署流程后,需要深入理解几个关键对象和它们的日常操作。

5.1 核心对象关系图(概念层面)

Deployment (定义Pod模板和副本数) | v Pod (一个或多个容器) <--- 被 Service 通过 Label Selector 选中 | v Container(s) (运行你的应用)
  • ConfigMap & Secret: 用于将配置信息和敏感数据(如密码)与容器镜像解耦,以环境变量或文件卷的形式注入到 Pod 中。
  • PersistentVolume (PV) & PersistentVolumeClaim (PVC): 用于管理持久化存储。PVC 是 Pod 对存储的“申请”,PV 是集群中的存储资源。管理员创建 PV,用户通过 PVC 消费。
  • Namespace: 用于在同一个物理集群中创建多个虚拟集群,实现资源隔离。kube-systemdefault都是内置的命名空间。

5.2 常用 kubectl 命令与故障排查

kubectl是你与集群交互的主要工具。除了getapply,以下命令至关重要:

  1. 查看详细信息

    kubectl describe pod <pod-name> # 查看 Pod 的详细状态、事件、配置 kubectl describe deployment <deployment-name> kubectl describe service <service-name>

    describe命令是排查 Pod 为什么处于PendingCrashLoopBackOff等异常状态的第一选择。它会显示调度失败、镜像拉取失败、健康检查失败等具体原因。

  2. 查看日志

    kubectl logs <pod-name> # 查看 Pod 内容器的标准输出日志 kubectl logs -f <pod-name> # 持续跟踪日志(类似 tail -f) kubectl logs <pod-name> -c <container-name> # 如果 Pod 有多个容器,指定容器名
  3. 进入 Pod 内的容器

    kubectl exec -it <pod-name> -- /bin/bash

    类似于docker exec,用于调试容器内部。

  4. 删除资源

    kubectl delete -f my-nginx-deployment.yaml # 通过文件删除 kubectl delete deployment nginx-deployment # 通过资源类型和名称删除 kubectl delete pod <pod-name>
  5. 排查 Pod 启动失败的常见原因

    • ImagePullBackOff: 镜像拉取失败。检查镜像名称、标签是否正确,网络是否通畅,是否有拉取私有镜像的凭证 (imagePullSecrets)。
    • CrashLoopBackOff: 容器启动后立即退出。检查应用本身是否有错误,查看kubectl logs
    • Pending: Pod 无法被调度到节点上。检查节点资源是否充足(CPU、内存),是否有节点选择器 (nodeSelector) 限制,或是否存在污点 (Taint)。
    • ErrImagePull: 同 ImagePullBackOff。

5.3 应用更新、回滚与扩缩容

  1. 更新镜像版本(滚动更新):

    kubectl set image deployment/nginx-deployment nginx=nginx:1.25

    K8S 的 Deployment 默认采用滚动更新策略,会逐步用新 Pod 替换旧 Pod,确保服务不中断。可以通过kubectl rollout status deployment/nginx-deployment观察更新状态。

  2. 回滚到上一版本

    kubectl rollout undo deployment/nginx-deployment
  3. 查看更新历史

    kubectl rollout history deployment/nginx-deployment
  4. 手动扩缩容

    kubectl scale deployment nginx-deployment --replicas=5

这个阶段的目标是:熟练使用kubectl describekubectl logs进行故障排查,理解 Pod 常见状态的含义,并掌握应用更新、回滚和扩缩容的基本操作。这已经覆盖了日常运维的大部分场景。

6. 向生产环境迈进:配置、存储与健康检查

要让应用在 K8S 上更健壮,需要关注配置管理、数据持久化和应用健康状态监控。

6.1 使用 ConfigMap 管理配置

将配置与镜像分离。例如,为 Nginx 创建一个自定义主页。

  1. 创建 ConfigMap

    kubectl create configmap nginx-index-html --from-file=index.html=./my-index.html

    假设my-index.html文件内容为<h1>Hello from ConfigMap!</h1>

  2. 在 Deployment 中挂载 ConfigMap: 修改my-nginx-deployment.yaml,在 Pod 模板的spec.containers下添加volumeMounts,并在spec下添加volumes

    spec: containers: - name: nginx image: nginx:1.24 ports: - containerPort: 80 volumeMounts: - name: html-volume mountPath: /usr/share/nginx/html # 挂载到容器内的路径 volumes: - name: html-volume configMap: name: nginx-index-html # 引用刚才创建的 ConfigMap items: - key: index.html path: index.html

    应用更新后,访问 Nginx,主页内容将变为 ConfigMap 中定义的内容。

6.2 使用 PersistentVolumeClaim 挂载持久化存储

在 Minikube 中,可以方便地使用hostPath类型的 PV,但在生产环境通常会使用网络存储(如 NFS、Ceph、云盘)。

  1. 创建 PVCmy-pvc.yaml

    apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-data-pvc spec: accessModes: - ReadWriteOnce # 访问模式:单节点读写 resources: requests: storage: 1Gi # 请求 1Gi 存储空间
  2. 在 Deployment 中使用 PVC: 在 Pod 模板的spec.containers中添加volumeMounts,并在spec下添加volumes,引用 PVC:

    spec: containers: - name: nginx ... volumeMounts: - name:>containers: - name: nginx image: nginx:1.24 livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 # 容器启动后等待 5 秒开始探测 periodSeconds: 10 # 每 10 秒探测一次 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5

    这个阶段的目标是:了解如何将应用配置外置(ConfigMap),如何为有状态应用提供持久化存储(PVC),以及如何通过健康检查让 K8S 更好地管理你的应用生命周期。这是将简单部署转化为可运维、高可用服务的关键步骤。

    7. 学习路径建议与常见避坑点

    最后,结合我自己的经验,给几条学习和实践的建议。

    7.1 学习路径规划

    1. 第一阶段(1-2周):夯实 Docker 基础。做到能熟练构建自定义镜像,理解 Dockerfile 每一行指令的作用,掌握容器网络(--network)和数据卷(-v)的基本用法。
    2. 第二阶段(2-3周):上手 Minikube 和 kubectl。反复练习 Deployment、Service、Pod、ConfigMap、PVC 这几个核心对象的 YAML 编写和命令操作。在本地部署一个多副本的 Web 应用(如 WordPress + MySQL),并配置 Service 访问。
    3. 第三阶段(1-2个月):深入学习核心概念。理解 K8S 的架构(Master/Node)、调度原理、网络模型(CNI)、服务发现(CoreDNS)、Ingress 控制器。可以尝试在云服务器上使用kubeadm手动搭建一个多节点集群,这个过程能极大加深理解。
    4. 第四阶段(长期):关注生态工具。学习 Helm(包管理)、Prometheus(监控)、Grafana(可视化)、EFK/ELK(日志)、GitOps(ArgoCD/Flux)等,这些是构建完整云原生技术栈的组成部分。

    7.2 实践中的常见坑点

    • 镜像拉取失败:确保镜像名称和标签正确。对于私有仓库,需要在 Deployment 中配置imagePullSecrets。国内环境可能需要对 Docker Hub 配置镜像加速器。
    • Pod 一直 Pending:运行kubectl describe pod <pod-name>,查看Events部分。常见原因是节点资源不足(CPU、内存),或 PVC 无法绑定(没有可用的 PV)。
    • Service 无法访问
      • 检查 Service 的selector是否与 Pod 的labels完全匹配。
      • 检查 Pod 的containerPort是否与 Service 的targetPort一致。
      • 对于NodePort类型,检查防火墙是否放行了节点的对应端口(30000-32767)。
      • 在集群内,可以通过kubectl run -it --rm --image=busybox test-pod -- sh启动一个临时 Pod,用wget -O- <service-name>.<namespace>.svc.cluster.local:port测试服务发现。
    • 配置文件格式错误:YAML 对缩进极其敏感,务必使用空格而非 Tab。可以使用在线 YAML 校验工具或kubectl apply --dry-run=client -f your-file.yaml进行预检查。
    • 忘记清理资源:学习过程中会创建大量临时资源。定期使用kubectl get all --all-namespaces查看,并使用kubectl delete清理不再需要的 Deployment、Service、Pod、PVC 等,避免资源浪费。

    我个人更建议把“速通”理解为快速建立核心概念和最小可运行环境,而不是追求一次性掌握所有高级特性。真正的熟练来自于反复的实践和踩坑。先从在 Minikube 上稳定运行一个你自己打包的应用开始,然后逐步加入配置、存储、健康检查,再尝试搭建多节点集群。每一步都确保自己理解了背后的原理和命令的作用,这样积累的经验才是扎实的。

    🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度