☰
Kubernetes入门实战:从容器基础到本地集群部署Nginx
2026/10/12 14:12:02 网站建设 项目流程

简介:这份资源是面向容器与Kubernetes初学者的入门指南,适合具备一定Linux和Docker基础、希望快速上手K8S的开发与运维人员。内容从Docker镜像管理与容器生命周期讲起,延伸到K8S架构组件(API Server、etcd、Scheduler等)及Pod、Deployment、Service、Namespace等核心资源对象,并给出Minikube与kubectl的本地环境搭建方法,最后以Nginx部署实战串联YAML定义、Service暴露与常用命令速查。资源包共1个docx文件,约19KB,以图文笔记形式组织,便于按章节顺序阅读与动手练习。目前已有275人学习,读者可借此建立容器化思维,理解容器与虚拟机的差异,掌握集群搭建、资源编排与故障排查的基本思路,为后续深入学习K8S高级特性打下基础。

1. 从一台没装容器的笔记本开始:为什么K8S入门总卡在“环境”这一步

很多人学 Kubernetes 的路径是这样的:先看了一堆架构图,Pod、Service、Deployment 背得滚瓜烂熟,结果真到动手时,连一个能跑kubectl get nodes的本地环境都搭不起来。这不是你笨,而是容器技术本身有一层“环境前提”——K8S 不直接管你的应用,它管的是容器;而容器要跑起来,又依赖 Linux 内核的命名空间和 cgroups。Windows 和 macOS 上直接装 K8S,等于跳过了这层前提,翻车是必然的。

这篇笔记要解决的就是这个断层:从容器技术基础讲起,把本地环境搭建、Nginx 部署这条最短路径走通。适合两类人:一是刚接触云原生、想在自己电脑上跑通第一个 K8S 集群的开发者;二是用过 Docker 但没碰过 K8S、想搞清楚“容器编排到底编了什么”的运维或后端。读完之后,你应该能在一台普通开发机上拥有一个可用的单节点集群,并且知道每一步为什么这么做、参数改哪里、报错看什么。

2. 容器技术基础:Namespace、Cgroups 与镜像分层到底在干什么

2.1 容器不是轻量级虚拟机,它只是被限制的进程

这是最容易混淆的一点。虚拟机通过 Hypervisor 虚拟出硬件,再装一个完整操作系统;容器没有自己的内核,它直接复用宿主机的内核,靠 Linux 提供的两个机制实现隔离和限制:

  • Namespace:负责“看得见什么”。PID namespace 让容器里的进程以为自己是 1 号进程,看不到宿主机上其他进程;Network namespace 给容器独立的网卡、IP、路由表;Mount namespace 隔离文件系统挂载点。你执行docker run时,Docker 就是调用了clone()并传入一堆CLONE_NEW*标志来创建这些命名空间。
  • Cgroups:负责“能用多少”。CPU 配额、内存上限、IO 带宽都靠它限制。K8S 里给 Pod 写的resources.limits.memory: 256Mi,最终就是落到 cgroup 的memory.max文件上。

理解这一点,后面很多现象就顺了:为什么容器里top看到的 CPU 数是宿主机的?因为/proc没有完全隔离。为什么容器里改时间会影响宿主机?因为时间 namespace 默认不隔离。

2.2 镜像分层:为什么你的镜像越拉越慢

容器镜像不是一个大文件,而是一层层叠加的只读层。Dockerfile 里每条RUN、COPY、ADD都会生成一层。拉取时,如果本地已经有某一层,就跳过不拉。这就是为什么基础镜像(比如alpine)第一次慢、后面快。

分层带来的两个实操影响:

  1. 层数越少越好,但不是越少越对。把apt-get update和apt-get install写在同一层,可以避免缓存过期导致的安装失败;但把所有命令塞进一个RUN里,调试时想改一行就得全量重建。
  2. 构建缓存命中靠指令顺序。COPY package.json放在COPY . .前面,是为了让依赖安装层在源码没变时复用缓存。这个顺序写反,每次改一行代码都要重装依赖。

2.3 从 Docker 到 K8S:编排层到底多做了什么

Docker 解决的是“单机怎么跑一个容器”,K8S 解决的是“一群机器上怎么跑一堆容器,并且它们要互相发现、要能扩缩、挂了要自愈”。具体来说,K8S 在容器之上加了这些抽象:

概念解决什么问题对应 Docker 里的近似物
Pod多个容器共享网络和存储,作为一个调度单元无直接对应,近似--network container:
Deployment声明式管理 Pod 副本数、滚动更新、回滚无,需自己写脚本
Service给一组 Pod 一个稳定虚拟 IP 和 DNS 名无,需自己配反向代理
ConfigMap/Secret配置与镜像解耦-v挂载文件或-e传环境变量

所以“K8S 入门”不是学几个命令,而是理解这套声明式模型:你写 YAML 描述期望状态,控制器负责把实际状态拉过去。本地环境搭建的意义,就是让你有一个能反复试这套模型的地方。

3. 本地环境搭建:用 kind 在五分钟内跑起一个单节点集群

3.1 为什么选 kind 而不是 minikube 或 Docker Desktop

本地跑 K8S 常见三种方案:minikube、kind、Docker Desktop 自带。我一般推荐 kind,理由很实际:

  • kind 把节点跑在 Docker 容器里,所以集群创建和销毁就是docker run和docker rm,干净、快、不污染宿主机。
  • 支持多节点,虽然入门用单节点,但以后想试调度策略、节点亲和性,kind 直接加配置就行。
  • 和 CI 集成好,很多项目的端到端测试就是用 kind 起集群。

minikube 更重,会起虚拟机或复杂驱动;Docker Desktop 的 K8S 藏在设置面板后面,出问题不好排查。kind 的“黑匣子”程度最低。

前置条件只有两个:装好 Docker,装好kubectl。kind 本身是一个二进制文件。

3.2 安装 kind 与 kubectl 的具体命令

Linux 和 macOS 上,用包管理器最省事。以下命令按顺序执行:

# 安装 kind(以 Linux amd64 为例,其他平台替换 URL 中的 os/arch) curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind # 安装 kubectl(版本建议与 kind 支持的 K8S 版本接近) curl -LO "https://dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/kubectl # 验证 kind version kubectl version --client

逻辑说明:kind 本身不依赖 K8S 组件,它只是一个创建 Docker 容器并往里装 K8S 的工具。kubectl是客户端,只负责发请求,版本差一两个小版本通常没问题,但别差太多。

参数说明:v0.20.0和v1.28.0是写这篇文章时的稳定版本,你执行时可以去官方 release 页面看最新稳定版。URL 里的linux/amd64要换成你的平台,macOS M 系列是darwin/arm64。

3.3 创建集群并验证节点状态

一条命令创建默认单节点集群:

kind create cluster --name demo

输出里会看到它拉取kindest/node镜像、启动容器、安装 K8S 组件。完成后验证:

kubectl cluster-info --context kind-demo kubectl get nodes

get nodes应该显示一个Ready状态的节点。如果卡在NotReady,通常是 CNI 网络插件还没就绪,等 30 秒再试。

这里有个细节:kind 默认不装 Ingress Controller,也不装 StorageClass。入门阶段用不到,但如果你后面要部署需要持久化存储或外部访问的应用,得额外装。Nginx 部署用NodePort或port-forward就够了。

3.4 集群起不来时先看这三处

  • docker ps -a看 kind 的容器是否在运行,如果退出,docker logs <容器名>看 K8S 组件报错。
  • kubectl get pods -n kube-system看核心组件 Pod 状态,CrashLoopBackOff多半是资源不够或镜像拉取失败。
  • kind export logs导出完整日志,里面按节点和组件分目录,比盲猜快。

4. 部署第一个 Nginx:从 kubectl 命令到 YAML 清单

4.1 先用命令跑通,再换成声明式 YAML

新手直接写 YAML 容易懵,因为不知道每个字段对应什么。我建议先用命令式跑一遍,看到结果,再翻译成 YAML。

# 创建一个 Deployment,2 个副本,镜像 nginx:1.25 kubectl create deployment nginx-demo --image=nginx:1.25 --replicas=2 # 暴露为 NodePort 服务 kubectl expose deployment nginx-demo --port=80 --type=NodePort # 查看 kubectl get deployments kubectl get pods kubectl get svc nginx-demo

逻辑说明:create deployment会生成一个 Deployment 对象,它再创建 ReplicaSet,ReplicaSet 创建 Pod。expose创建 Service,把流量负载到两个 Pod 上。NodePort会在每个节点上开一个 30000-32767 的端口。

参数说明:--port=80是 Service 的端口,--targetPort默认和--port相同,指向容器端口。--type=NodePort适合本地测试,生产环境通常用LoadBalancer或 Ingress。

4.2 把命令翻译成 YAML:Deployment 清单逐字段拆解

命令式适合试手,但真实项目必须用 YAML,因为要进版本控制、要评审、要复用。下面是对应的 Deployment 清单:

apiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo labels: app: nginx-demo spec: replicas: 2 selector: matchLabels: app: nginx-demo template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 250m memory: 256Mi

逐字段说明:

  • apiVersion: apps/v1:Deployment 属于apps组,v1是稳定版。写错成v1会报no matches for kind。
  • selector.matchLabels:Deployment 靠这个找到自己管的 Pod。必须和template.metadata.labels匹配,否则控制器不知道管谁。
  • template:Pod 模板。里面containers是数组,可以放多个容器(边车模式)。
  • resources.requests:调度依据,K8S 找有这么多空闲资源的节点。limits:运行时上限,超了会被限制或杀掉。

4.3 Service 清单与访问验证

Service 的 YAML:

apiVersion: v1 kind: Service metadata: name: nginx-demo spec: selector: app: nginx-demo ports: - port: 80 targetPort: 80 nodePort: 30080 type: NodePort

selector和 Deployment 的 Pod 标签对应,这样 Service 才知道把流量转给谁。nodePort: 30080是手动指定,不写会随机分配。

应用并验证:

kubectl apply -f nginx-deployment.yaml kubectl apply -f nginx-service.yaml # 查看 Pod 和 Service kubectl get pods -o wide kubectl get svc nginx-demo # 本地访问(kind 集群需要端口映射或 port-forward) kubectl port-forward svc/nginx-demo 8080:80

然后浏览器或curl localhost:8080应该看到 Nginx 欢迎页。port-forward是本地调试最稳的方式,不依赖节点 IP 和防火墙。

4.4 扩缩容与滚动更新:改一个数字看效果

把replicas从 2 改成 4,重新apply,再kubectl get pods,会看到新 Pod 被创建。改镜像版本:

kubectl set image deployment/nginx-demo nginx=nginx:1.26 kubectl rollout status deployment/nginx-demo kubectl rollout history deployment/nginx-demo

rollout status会阻塞直到更新完成,history看历史版本。回滚用kubectl rollout undo deployment/nginx-demo。这套机制是 K8S 相比手写脚本最值钱的地方之一。

5. 避坑与排查:本地 K8S 入门最常见的五个翻车点

5.1 Pod 一直 Pending:资源不够还是镜像拉不动

现象:kubectl get pods显示Pending,describe里 Events 有Insufficient cpu或ImagePullBackOff。

原因:前者是节点资源被 requests 占满,单节点集群尤其容易;后者是镜像名写错、标签不存在、或网络拉取失败。

解决:kubectl describe pod <name>看 Events 最后几行。资源不够就调小requests或删掉其他负载;镜像问题先docker pull同名镜像验证,再检查 YAML 里的image字段。

5.2 Service 访问不通:selector 对不上是头号嫌疑

现象:port-forward能通,但NodePort或集群内curl不通。

原因:Service 的selector和 Pod 标签不匹配,导致 Endpoints 为空。kubectl get endpoints nginx-demo如果显示<none>,就是这个问题。

解决:对比kubectl get pods --show-labels和 Service YAML 里的selector。标签是大小写敏感的,app: nginx和app: Nginx不匹配。

5.3 镜像拉取慢或超时:换镜像源不如先看缓存

现象:ImagePullBackOff,Events 里dial tcp: i/o timeout。

原因:默认镜像仓库网络不稳定,或者镜像层太大。

解决:本地开发可以先把镜像docker pull下来,然后kind load docker-image nginx:1.25 --name demo直接加载进集群,绕过拉取。这是 kind 的一个实用特性,很多人不知道。

5.4 删除资源后卡在 Terminating:finalizer 在作怪

现象:kubectl delete pod后 Pod 一直Terminating,删不掉。

原因:某些资源带 finalizer,控制器没处理完就不让删。本地环境常见于 PVC 或命名空间删除。

解决:kubectl get pod <name> -o yaml看metadata.finalizers。确认不需要后,kubectl patch pod <name> -p '{"metadata":{"finalizers":null}}'强制移除。这是后悔药,生产环境慎用。

5.5 kubectl 连不上集群:context 和 kubeconfig 搞混了

现象:The connection to the server localhost:8080 was refused。

原因:kubectl没找到 kubeconfig,或者当前 context 指向一个已删除的集群。

解决:kubectl config get-contexts看当前 context,kind export kubeconfig --name demo重新导出。如果之前删过集群,旧 context 还在,kubectl config delete-context <name>清掉。

6. 进阶技巧:用 kind 配置文件和本地镜像加载把调试闭环做顺

走到这里,你已经有一个能跑 Nginx 的本地集群了。但真实开发中,反复docker build+kind load+kubectl apply很烦。我一般会做两件事把闭环缩短。

第一,用 kind 配置文件固定端口映射和节点配置。创建一个kind-config.yaml:

kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30080 hostPort: 30080 protocol: TCP

然后kind create cluster --config kind-config.yaml --name demo。这样NodePort 30080直接映射到宿主机,不用每次port-forward。extraPortMappings的原理是 Docker 的端口映射,所以只对NodePort或hostPort生效,对ClusterIP无效。

第二,写一个 Makefile 把构建、加载、部署串起来:

IMAGE := nginx-demo:local CLUSTER := demo build: docker build -t $(IMAGE) . load: kind load docker-image $(IMAGE) --name $(CLUSTER) deploy: kubectl apply -f k8s/ redeploy: build load kubectl rollout restart deployment/nginx-demo .PHONY: build load deploy redeploy

这里的关键是imagePullPolicy: IfNotPresent配合本地镜像标签。如果 YAML 里写nginx:latest,K8S 默认Always拉取,会忽略你加载的本地镜像。改成nginx-demo:local并设IfNotPresent,才能用上kind load的镜像。

验证方法:改一行 Nginx 的index.html,make redeploy,然后curl localhost:30080看内容变没变。如果没变,先kubectl get pods看新 Pod 是否 Running,再kubectl describe pod看 Events 里是不是还在拉旧镜像。这个闭环跑顺之后,你调 K8S 清单的效率会高很多。

最后说一个我踩过的坑:别在本地集群里跑带PersistentVolumeClaim的有状态应用,除非你先装好local-path-provisioner。kind 默认没有 StorageClass,PVC 会一直Pending,然后 Pod 卡在ContainerCreating。这个报错在 Events 里写得很清楚,但新手容易只看 Pod 状态就懵。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询