Kubernetes入门:容器基础、本地K8S环境搭建与Nginx部署
简介这是一份面向Kubernetes初学者的入门指南重点覆盖容器技术基础与K8S核心概念适合具备一定Linux和Docker基础、希望快速上手容器编排的开发或运维人员。内容从Docker镜像与容器生命周期管理讲起再到K8S的API Server、etcd、Scheduler等组件以及Pod、Deployment、Service、Namespace等资源对象并通过Minikube与kubectl完成本地集群搭建和Nginx部署实战帮助读者将概念转化为可操作经验。包体为单个docx文档压缩包仅19KB篇幅紧凑却覆盖常用命令、YAML定义与排查要点便于随时查阅。该文档已有274人学习浏览适合作为入门K8S的第一份实践手册按章节顺序学习并动手部署即可理解核心对象与工具链为后续掌握高级特性打下扎实基础。1. Kubernetes入门容器技术基础与K8S核心概念本地环境搭建到底在搭什么Kubernetes 入门最劝退的不是概念多而是概念和实操对不上。你背了一堆 Pod、Deployment、Service打开终端却不知道第一行命令该敲什么。我见过太多人把时间耗在装集群上最后 Nginx 都没跑起来。这篇笔记沿着一条主线走先讲清楚容器技术基础——为什么是 Docker 镜像再动手把 K8S 核心概念落到本地环境搭建上最后用一台笔记本完成 Nginx 部署实战。适合刚接触 Kubernetes 的开发者、运维以及想在公司内网搭一套可复现环境的同学。你可以不碰生产但至少要能在本地把一个 Nginx 通过 Service 暴露出来。2. 容器技术基础Docker 镜像与容器让 Nginx 先在单机跑起来2.1 容器与镜像的关系K8S 里最小调度单位的地基先澄清一个概念Kubernetes 编排的不是镜像也不是裸容器而是 Pod。但 Pod 里的进程仍然对应一个容器运行时containerd、CRI-O 或 Docker。所以容器技术基础必须从镜像讲起。镜像是一个只读的、分层打包的 rootfs容器是在这个 rootfs 之上加一个可写层并运行进程。可以这么记镜像是一张“安装光盘”容器是“用这张光盘启动的操作系统实例”。K8S 之所以把容器作为底座而不是直接跑二进制是因为容器把应用和依赖一起打包让 Nginx 在本地、测试机、生产机上以同样的方式启动。容器和虚拟机最大的区别是不需要完整的 guest OS直接共享宿主机内核。这意味着容器启动快、资源占用小但也意味着你得确保镜像里的二进制和宿主机内核兼容。Nginx 这种纯用户态程序基本没踩过坑但如果你要跑 GPU 推理容器就得检查内核模块、设备映射。这也是为什么后来 K8S 社区出现 Device Plugin 这类扩展。你可以等入门后了解现在只要记住镜像做不可变交付容器做进程隔离。2.2 安装 Docker 并拉取 Nginx 镜像最小命令注意如果你的机器上还没有 Docker先安装 Docker Engine。因为不同发行版安装命令不一样这里不贴安装脚本只确认守护进程可用。# 验证 Docker 守护进程是否可用返回 Server 版本 docker version --format {{.Server.Version}} # 从 Docker Hub 拉取 nginx 镜像alpine 版本体积更小适合本地实验 docker pull nginx:1.24-alpine # 查看本地镜像列表 docker images | grep nginx逻辑说明docker version 的 --format 参数直接输出服务端版本号如果这行命令不报错说明 Docker 安装成功且 daemon 在运行。docker pull 会把镜像拉取到本地缓存。nginx:1.24-alpine 基于 Alpine Linux镜像大约几十 MB比官方 nginx 镜像小不少本地拉取快也方便后续 K8S 实验。参数说明1.24 是 Nginx 主版本alpine 是变体 tag。实际生产可以根据稳定版本选择。docker images 用来确认镜像 tag 是否在本地。如果你在 aarch64ARM64机器上Docker 会自动匹配对应架构的镜像但要注意部分老镜像没有 arm64 变体拉取时会报 “no matching manifest”这时候得换成支持多架构的版本。常见做法如果你在一个纯内网环境可以先用 docker save 打包镜像再拷到目标机器 docker load。这就是后面本地环境里镜像私有化的雏形K8S 集群里所有节点拉镜像的思路和这个一样。2.3 用 docker run 验证端口映射容器是怎么“上网”的# 后台运行一个 nginx 容器把宿主机 8080 端口映射到容器 80 端口 docker run -d --name nginx-single -p 8080:80 nginx:1.24-alpine # 验证容器状态 docker ps | grep nginx-single # 请求宿主机 8080能返回 nginx 默认欢迎页 curl -I http://localhost:8080逻辑说明-d 让容器在后台运行--name 给容器起名-p 8080:80 是端口映射意思是宿主机上的 8080 端口收到的流量会转发给容器的 80 端口。Nginx 默认监听 80所以访问宿主机 8080 就能看到页面。curl -I 只取响应头能快速看到 HTTP/1.1 200 就说明通了。参数说明如果你不想占 8080可以换成 8081:80只要不冲突。这个映射是 K8S 里 NodePort Service 的雏形——区别是K8S 的端口分配由集群统一管理而不是 docker run 手工指定。容器本身没有“IP 上网”的概念你看到的 localhost 是宿主机端口容器内部的网卡是另一个隔离网络。容器本身的日志也很重要。当你 curl 不通时第一件事不是改端口而是看容器日志docker logs nginx-single如果日志里没有 access log说明请求根本没到容器如果有 403 而你是用 -I 请求根路径可能是 Nginx 配置问题。这种“先看日志再改配置”的顺序到 K8S 里同样成立只是把 docker logs 换成 kubectl logs。清理容器docker stop nginx-single docker rm nginx-single为什么说这步很重要因为后面用 K8S 部署 Nginx 时你不能同时让 Docker 占用 80 或 8080避免端口冲突。这个习惯能帮你少踩一个坑。3. 本地环境搭建用 minikube 拉起单节点 Kubernetes 集群3.1 为什么本地入门不用 kubeadmminikube 与 kind 的选型Kubernetes 官方推荐的安装工具是 kubeadm它能搭出符合生产规范的多节点集群但意味着你要准备至少两台机器或虚拟机、处理容器运行时、初始化控制面、安装网络插件 CNI、配置工作节点 join。对入门来说这套流程太长而且很多报错来自网络和环境不是 Kubernetes 本身。本地环境搭建更常用的选择是 minikube 或 kind。minikube 适合“我要一台完整的单节点集群”内置了 kubelet、容器运行时、kube-apiserver 等组件并且支持多种驱动Docker、VirtualBox、KVM、QEMU。kind 则是用容器模拟节点轻量但有些高级功能如负载均衡、跨节点网络支持不完全。我的建议是如果你主要在本机做 Nginx 这类无状态应用实验选 minikube如果你要快速验证 CI 流水线选 kind。这篇按 minikube 走因为它的 preflight 检查更接近 kubeadm 的输出你看过一遍就不怕生产环境初始化报错了。3.2 安装 kubectl 与 minikube版本对齐和驱动选择首先安装 kubectl。macOS 可以用 brew install kubectlLinux 可以用 curl 下载二进制Windows 可以用 choco。但更保险的做法是下载和你的集群版本一致或接近的 kubectl。minikube 启动时会在集群里跑某个 Kubernetes 版本如果 kubectl 版本差太多会出现 client/server version mismatch 警告命令可能失败。# 检查本机 kubectl 版本 kubectl version --client # 安装 minikube以 Linux x86_64 为例其他平台到官方 release 下载 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube # 查看 minikube 版本 minikube version逻辑说明kubectl 是客户端它通过 kubeconfig 文件连接 kube-apiserver。minikube 是启动本地集群的“最小 manager”。这两者需要单独安装。curl 下载的是官方预编译二进制install 把它放到 /usr/local/bin。注意这里的下载地址是官方存储桶如果公司内网没有外网权限你需要请管理员同步二进制而不是自己折腾。参数说明minikube 默认会自动选择可用驱动如 Docker。如果你已经装了 Dockerminikube start 默认用 docker 驱动也就是在 Docker 里跑一个“节点”容器这样不需要额外虚拟化。如果你想强制指定驱动用 --driverdocker 或 --drivervirtualbox。3.3 启动集群minikube start 与 [preflight] 前置检查启动 minikube 需要能够拉取本地节点镜像和 Kubernetes 控制面镜像。如果你访问默认仓库超时minikube 提供 --image-repository 参数可以指向你内网可用的 registry。minikube start --driverdocker --kubernetes-versionv1.26.0 --cpus2 --memory2048这个命令会做一系列 preflight 检查。你会看到类似这样的输出[minikube] Running pre-flight checks [preflight] Using kubernetes version: v1.26.0 [preflight] Running pre-flight checks这不是 kubeadm但概念一致检查端口占用、CPU 数量、内核参数、容器运行时是否可用。如果你的 Docker 没有启动会在这里直接报错。逻辑说明--kubernetes-version 指定要部署的 K8S 版本这里固定 v1.26.0 只是为了复现教程输出。--cpus 和 --memory 控制分配给 minikube 节点的资源。如果你只有 2 核 4G 内存至少保留 1G 给系统否则集群启动后容易 OOM。参数说明--driverdocker 表示用 Docker 容器作为节点这样不需要虚拟机管理程序。--cpus2 至少需要 2 个核否则 kube-scheduler 和 kube-controller-manager 可能无法及时调度。启动完成后minikube status 可以查看节点状态。如果启动失败常用的排查是 minikube delete 后重新 start而不是直接重启 Docker。3.4 验证集群kubectl get nodes 与 kubectl get pods -Akubectl get nodes kubectl get pods -A kubectl cluster-info第一个命令会显示 ready 的节点比如 minikube。第二个命令列出所有命名空间下的 Pod正常情况下会看到 kube-system 里的 coredns、etcd、kube-apiserver 等组件处于 Running。第三个命令给出控制面地址本地一般是 https://127.0.0.1:xxxxx。这里有个新手常犯的错误kubectl get nodes 一直报 connection refused原因往往是 minikube 集群没有启动而不是 kubeconfig 错了。你要先确认 minikube status 是否正常再检查 kubeconfig。另外minikube 会把 kubeconfig 写到 ~/.kube/config并且把当前 context 切换到 minikube。如果你之前用过别的集群切回来要执行kubectl config use-context minikube这一步在本地环境搭建里很关键否则你对着别的集群敲半天命令对象完全不对。4. K8S 核心概念Pod、Deployment、Service 在本地集群里怎么落地4.1 Pod先 kubectl run 一个 Nginx Pod 看概念Pod 是 K8S 的最小调度单位它封装一个或多个容器共享网络命名空间、存储卷。最简单的 Pod 只有一个容器。我们可以在本地集群里直接 run 一个 Nginx Podkubectl create namespace dev kubectl -n dev run nginx-dev --imagenginx:1.24-alpine --port80 kubectl -n dev get pods逻辑说明kubectl create namespace dev 建立一个逻辑隔离空间。kubectl run 是快速创建 Pod 的命令在新版 K8S 中run 默认创建 Deployment而不是裸 Pod除非你加 --restartNever。这里我们把它当作 Deployment 的快速入口。--image 指定镜像--port 声明容器端口。注意这里没有暴露 NodePort所以从集群外访问不到但集群内部可以。参数说明指定命名空间用 -n dev避免污染 default。如果你执行 kubectl run --restartNever可以创建一个裸 Pod这样你能看到它的 IP 会在重建后变化这就是为什么需要 Service。Pod 里为什么可以放多个容器常见的是 sidecar 模式主容器跑 Nginxsidecar 容器同步日志或处理流量。它们共享网络访问对方只需要 localhost。入门阶段先一个 Pod 一个容器理解“Pod 是逻辑主机”就够了。4.2 Deployment声明你要几个 Nginx 副本裸 Pod 被删除就没了而 Deployment 会确保你期望的副本数一直都在。用命令行的方式创建 Deploymentkubectl -n dev create deployment nginx-dev --imagenginx:1.24-alpine --replicas2 kubectl -n dev get deployment这里 create deployment 直接创建一个 Deployment默认副本数为 1指定 --replicas2。此时 Pod 会变成两个副本。Deployment 通过 ReplicaSet 控制器管理 Pod 的创建/删除。你可以执行 kubectl -n dev get rs 查看 ReplicaSet名字会带上随机后缀。为什么用 Deployment 而不是手动 kubectl run因为 Deployment 是声明式对象你告诉控制面“我要 2 个 nginx 副本”它会自己调整。这个思想贯穿 K8S 所有对象。后面第5章我们写 YAML 也是这个道理。4.3 Service把 Pod 的“临时 IP”固定成访问入口Pod 的 IP 是临时的副本扩容或重建后会变。Service 是稳定的抽象层它通过标签选择器匹配一组 Pod并提供统一的 ClusterIP或者 NodePort。为了给上面的 Deployment 暴露访问可以先创建 Servicekubectl -n dev expose deployment nginx-dev --typeNodePort --port80 --target-port80 kubectl -n dev get service逻辑说明expose deployment 根据 Deployment 的标签选择器自动生成 Service。NodePort 类型会在每个节点上分配一个 30000-32767 的端口本地访问 https://localhost: 就能到 Nginx。--port 是 Service 端口--target-port 是容器端口。这里有个关键点Service 的 selector 必须和 Pod 的标签匹配。如果你手工创建的 Pod 没有 appnginx-dev 标签expose 不会选中它。这也是为什么推荐用 Deployment 管理 Pod标签由 Deployment 统一维护。4.4 Namespace 与 kubeconfig本地多环境的第一道隔离Namespace 用来做逻辑隔离它不隔离网络但能让你在同一个集群里同时跑 dev、test、prod 而不互相干扰。kubeconfig 则是“连接配置”它保存了集群地址、证书和上下文。你可以用下面的命令查看当前上下文kubectl config get-contexts kubectl config current-context如果你在多个集群之间切换要修改的就是 context。minikube 创建后自带一个 minikube context。这在本地环境搭建中很重要你以后可能同时面对公司集群和本地 minikube命令一样但对象归属于不同集群别搞混。另外Namespace 的名字会在资源对象里反复出现。你写的每个 YAML 都能指定 namespace如果没指定就落到 default。本地实验建议一律用 -n dev避免和 kube-system 混在一起。5. Nginx 部署实战与避坑从 YAML 到 Service5 个本地环境常见问题排查5.1 编写 Nginx Deployment YAML从零到 kubectl apply命令行 create 适合临时实验生产推荐 YAML 文件。我们写一个最小的 nginx-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy namespace: dev spec: replicas: 2 selector: matchLabels: app: nginx-demo template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.24-alpine imagePullPolicy: IfNotPresent ports: - containerPort: 80应用它kubectl apply -f nginx-deployment.yaml kubectl -n dev get deployment nginx-deploy逻辑说明apiVersion 是 apps/v1Deployment 属于 apps 组。metadata.name 是对象名namespace 是所属命名空间。spec.replicas 声明期望副本数。selector.matchLabels 必须匹配 template.metadata.labels这是 Deployment 选择 Pod 的依据。template 就是 Pod 的模板里面定义了唯一容器 nginx暴露端口 80。参数说明image 标签不能省略否则默认拉 latest每次都可能变化。imagePullPolicy: IfNotPresent 表示如果本地已经有这个镜像就不去远程仓库拉取。你在纯内网环境用 docker load 导入了镜像一定要加这个参数否则可能会因为无法访问远程仓库而报 ImagePullBackOff。5.2 暴露 NginxNodePort 与 kubectl port-forward 对比创建 ServiceapiVersion: v1 kind: Service metadata: name: nginx-svc namespace: dev spec: type: NodePort selector: app: nginx-demo ports: - port: 80 targetPort: 80 nodePort: 30080应用后查看kubectl apply -f nginx-service.yaml kubectl -n dev get svc nginx-svc可以看到 ClusterIP 和 NodePort 30080。本地浏览器访问http://localhost:30080 或 minikube ip 加上端口。NodePort 的端口范围是 30000-32767我写 30080 是约定俗成。如果端口被占用会报错换一个就行。如果你不想占节点端口可以用端口转发kubectl -n dev port-forward svc/nginx-svc 8080:80这个命令将本地 8080 转发到 Service 的 80。转发期间终端不能关。区别在于NodePort 是集群层面的暴露port-forward 是 kubectl 客户端帮你建立的临时通道适合调试。本地环境搭建时两者都能用到公司内部环境NodePort 更接近真实暴露方式。如果需要更高层入口生产环境一般会在前面放一个 Ingress Controller它本质上是基于 Nginx 的反向代理按域名和路径把流量转发到不同 Service。5.3 扩容与滚动更新一次发布里发生了什么把副本数改成 3kubectl -n dev scale deployment nginx-deploy --replicas3 kubectl -n dev get pods滚动更新可以用 set image 或修改 YAMLkubectl -n dev set image deployment/nginx-deploy nginxnginx:1.25-alpine kubectl -n dev rollout status deployment/nginx-deploy第一条命令把容器镜像更新到 1.25第二条命令等待滚动完成。滚动更新的过程是Deployment 创建一个新的 ReplicaSet先扩容新副本再缩容旧副本保证服务不中断。如果你发现更新后访问异常可以用撤销命令回滚到上一个版本kubectl -n dev rollout undo deployment/nginx-deploy这个“后悔药”就是 K8S 相比裸容器最实用的一点。滚动更新期间你会发现 Pod 列表里同时存在新旧两种版本的 Pod这是正常现象。等 rollout status 显示 successfully rolled out旧 Pod 才会被清理干净。5.4 避坑记录5 个本地环境常见问题与排查坑1启动 minikube 时卡在 preflight 检查报 Docker 相关错误。现象minikube start 长时间停在 preflight最后报错退出。 原因本机 Docker 守护进程异常或之前 minikube 启动残留了旧容器。 解决先 docker ps 确认状态然后 minikube delete 后重新 start。不要用 sudo 硬改 /var/lib/docker 权限那会引发更诡异的问题。坑2kubectl get pods 显示 ImagePullBackOff。现象Pod 一直拉不到镜像事件里显示 Failed to pull image。 原因镜像 tag 写错或内网环境无法访问 Docker Hub。 解决先 docker pull nginx:1.24-alpine 确认镜像存在内网环境用 docker save/load 导入并在 YAML 里加 imagePullPolicy: IfNotPresent。坑3访问 NodePort 超时但 kubectl describe svc 看到 Endpoints 为空。现象curl localhost:30080 失败NodePort 的 Endpoints 列表没有 Pod IP。 原因Service 的 selector 和 Pod 标签不匹配或 Deployment 副本数为 0。 解决kubectl -n dev get pods --show-labels对比 selector确认 Deployment replicas 不为 0。坑4kubectl port-forward 显示 “unable to forward port because pod is not running”。现象转发失败终端报错。 原因Pod 还没进入 Running或者你指定了错误命名空间。 解决kubectl -n dev get pods 查看状态等 Pod Ready 后再转发。注意 -n 要和 Service 所在命名空间一致。坑5kubectl 连的却不是本地集群命令行为异常。现象kubectl cluster-info 显示另一个集群地址或 kubectl get pods 总返回别的结果。 原因kubeconfig 的当前 context 不是 minikube可能是之前用过其他集群留下的。 解决kubectl config use-context minikube再 minikube status 确认节点状态。6. 进阶验证用 kubectl diff 和 rollout 给 Nginx 部署上“后悔药”6.1 用 kubectl diff 和 describe 快速定位变更影响在改任何 YAML 之前先跑 kubectl diff -f nginx-deployment.yaml它会对比当前集群对象和本地文件的差异。我第一次上线时没做这步直接 apply 结果发现镜像 tag 打错导致一堆 Pod 滚动重建。从那以后我习惯“先 diff后 apply”这个习惯救过我好几次。kubectl -n dev diff -f nginx-deployment.yaml如果输出为空说明文件和集群状态一致有 diff 时会以类似 git diff 的格式显示新增、修改、删除的字段。这个命令不会改动集群纯只读可以放心用。6.2 用 rollout history 和 endpoints 验证更新结果kubectl -n dev rollout history deployment/nginx-deploy kubectl -n dev describe deployment nginx-deploy kubectl -n dev get endpoints nginx-svcrollout history 能查看发布历史describe 能看事件。如果某个 Pod 一直 CrashLoopBackOffdescribe pod 里会显示退避原因比如镜像启动命令错误。日志则用 kubectl -n dev logs deployment/nginx-deploy。Endpoints 列表里有几个 IP说明 Service 关联了几个副本如果 IP 数量和 replicas 不一致说明标签选择器有问题。最后补一个验证回滚的演练故意把镜像 tag 写成一个不存在的版本执行 kubectl set imageDeployment 会自动卡住。这时候你会发现新 ReplicaSet 一直没法完成旧 Pod 还在正常服务。这是 K8S 的滚动更新保护机制。演练完之后执行 kubectl rollout undo 回到上一个正常版本。我踩过最深的一个坑是“只在本地用编排不验证回滚”。滚动更新不是发布完就结束你要演练失败场景故意把镜像 tag 写错然后看 Deployment 怎么卡住、怎么回滚。这套动作在本地环境搭建阶段练熟到生产才不慌。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →