这篇文章将学习如何使用 Kind (Kubernetes IN Docker)来搭建一个本地 k8s 环境,其实之前在配置 cilium 环境 的时候就使用过 Kind,而这篇文章我们将会更详细地学习 Kind 的使用,并在此基础上搭建一个完整的 k8s 环境。
Kind 环境安装
Kubernetes (k8s) 是一个容器编排平台,用于自动化容器的部署、扩展和管理。Kind (Kubernetes in Docker) 是用 Docker 容器模拟 k8s 节点的工具,每个节点 实际上是一个 Docker 容器,容器内运行着完整的 K8s 组件。通过 Kind,可以适合快速搭建本地开发、测试和学习的 k8s 环境。
系统信息
如下是我当前的 Linux 服务器信息(单台服务器)
项目
信息
系统
Ubuntu 22.04.5 LTS
内核
5.15.0-40-generic
CPU
4核
内存
15Gi
Docker
28.5.1
由于 Kind 依赖于 Docker 来运行 k8s 节点,因此首先需要确保 Docker 已经安装并运行正常
1 2 docker info --format '{{.ServerVersion}}' docker ps -q | head -1
安装 Kind
1 2 curl -sLo /usr/local/sbin/kind "https://kind.sigs.k8s.io/dl/v0.31.0/kind-linux-amd64" chmod +x /usr/local/sbin/kind
1 2 kind v0.31.0 go1.25.5 linux/amd64
这里直接安装 Kind 的最新稳定二进制版本
官网 也提供了其他安装方式,例如通过包管理器安装或者源码安装
2.2 安装 Kubectl
1 2 curl -sLo /usr/local/sbin/kubectl "https://dl.k8s.io/release/v1.35.0/bin/linux/amd64/kubectl" chmod +x /usr/local/sbin/kubectl
1 2 3 4 Client Version: v1.35.0 Kustomize Version: v5.7.1 Server Version: v1.35.0
kubectl 是 Kubernetes 的命令行工具,kind 本身不需要 kubectl,但是为了方便管理集群和资源,建议安装 kubectl
kubectl 用于与 K8s API Server 交互,管理集群资源
Kustomize 是 K8s 原生的配置管理工具,内置于 kubectl
kubectl 的官方安装文档,可以参考这里
这里我们安装的 kubectl 版本和 k8s 版本都是最新的稳定版本
3. 创建集群
3.1 编写集群配置文件
创建文件 kind-config.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: k8s-cluster nodes: - role: control-plane extraPortMappings: - containerPort: 30000 hostPort: 30000 protocol: TCP - containerPort: 30001 hostPort: 30001 protocol: TCP - containerPort: 30002 hostPort: 30002 protocol: TCP - role: worker - role: worker networking: podSubnet: "10.244.0.0/16" serviceSubnet: "10.96.0.0/12"
配置详解 :
配置项
说明
kind: Cluster
声明这是一个 Kind 集群配置
apiVersion: kind.x-k8s.io/v1alpha4
Kind 配置的 API 版本
name: k8s-cluster
集群名称,用于标识和切换上下文
nodes
定义集群节点列表
role: control-plane
控制面节点,运行 K8s 管理组件(API Server、Controller、Scheduler、etcd)
role: worker
工作节点,运行用户的应用 Pod
extraPortMappings
端口映射,将容器端口映射到宿主机,便于访问 NodePort 服务
podSubnet
Pod 网络地址范围,每个 Pod 会获得该范围内的 IP
serviceSubnet
Service 网络地址范围,每个 Service 会获得虚拟 IP(ClusterIP)
K8s 节点角色说明 :
角色
功能
类比
control-plane
集群大脑,管理调度、存储状态、响应 API 请求
公司管理层
worker
执行者,运行实际的应用容器
公司员工
3.2 创建集群
1 kind create cluster --config kind-config.yaml --wait 300s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Creating cluster "k8s-cluster" ... • Ensuring node image (kindest/node:v1.35.0) 🖼 ... ✓ Ensuring node image (kindest/node:v1.35.0) 🖼 • Preparing nodes 📦 📦 📦 ... ✓ Preparing nodes 📦 📦 📦 • Writing configuration 📜 ... ✓ Writing configuration 📜 • Starting control-plane 🕹️ ... ✓ Starting control-plane 🕹️ • Installing CNI 🔌 ... ✓ Installing CNI 🔌 • Installing StorageClass 💾 ... ✓ Installing StorageClass 💾 • Joining worker nodes 🚜 ... ✓ Joining worker nodes 🚜 • Waiting ≤ 5m0s for control-plane = Ready ⏳ ... ✓ Waiting ≤ 5m0s for control-plane = Ready ⏳ • Ready after 12s 💚 Set kubectl context to "kind-k8s-cluster"
步骤解释 :
步骤
说明
Ensuring node image
下载 Kind 的 K8s 节点镜像(包含完整 K8s 组件)
Preparing nodes
创建 3 个 Docker 容器作为 K8s 节点
Writing configuration
写入集群配置(证书、kubeconfig 等)
Starting control-plane
启动控制面组件(API Server、etcd、Controller、Scheduler)
Installing CNI
安装容器网络接口(Kind 默认使用 kindnet),让 Pod 可以互相通信
Installing StorageClass
安装默认存储类(local-path),支持持久化存储
Joining worker nodes
让 worker 节点加入集群,建立与控制面的连接
Waiting for Ready
等待控制面节点状态变为 Ready
关键概念解释 :
组件
功能
CNI (Container Network Interface)
Pod 网络插件,负责 Pod 之间的网络通信。每个 Pod 都有自己的 IP,CNI 让它们 能互相访问
StorageClass
存储类型定义,告诉 K8s 如何创建持久化存储卷。应用数据需要持久化时,K8s 会根据 StorageClass 自动创建存储
kubeconfig
认证配置文件,包含集群地址、证书、用户信息,kubectl 用它连接集群
4. 验证集群状态
在创建集群之后,就可以使用 kubectl 命令来和 k8s 集群进行交互 了。kubectl 会自动使用 KIND 所生成的 kubeconfig 文件 来连接集群,该配置文件默认保存在 ${HOME}/.kube/config 目录下。kubeconfig 文件告诉 kubectl:我要连接哪个集群?用什么身份连接?以及如何验证安全连接?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://127.0.0.1:44199 name: kind-k8s-cluster contexts: - context: cluster: kind-k8s-cluster user: kind-k8s-cluster name: kind-k8s-cluster current-context: kind-k8s-cluster kind: Config users :- name: kind-k8s-cluster user: client-certificate-data: DATA+OMITTED client-key-data: DATA+OMITTED
clusters 字段:集群信息,包括证书和 API 服务器地址,通过 kubectl 命令和集群交互时,就是往这个 API 服务器发送请求
users:用户信息,包括客户端证书和密钥,用于认证和授权
contexts:当前使用的上下文,即当前连接的集群和用户,实现一个逻辑绑定,将用户和集群关联起来
current-context:默认的上下文,执行 kubectl 时会自动使用这个上下文
1 2 3 4 5 Kubernetes control plane is running at https://127.0.0.1:44199 CoreDNS is running at https://127.0.0.1:44199/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump' .
4.1 查看节点状态
1 kubectl get nodes -o wide
输出 :
1 2 3 4 NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-cluster-control-plane Ready control-plane 27s v1.35.0 172.19.0.4 <none> Debian GNU/Linux 12 (bookworm) 5.15.0-40-generic containerd://2.2.0 k8s-cluster-worker Ready <none> 17s v1.35.0 172.19.0.3 <none> Debian GNU/Linux 12 (bookworm) 5.15.0-40-generic containerd://2.2.0 k8s-cluster-worker2 Ready <none> 17s v1.35.0 172.19.0.2 <none> Debian GNU/Linux 12 (bookworm) 5.15.0-40-generic containerd://2.2.0
字段解释 :
字段
说明
NAME
节点名称,Kind 以 集群名-角色 命名
STATUS
节点状态,Ready 表示节点正常,可接受调度 Pod
ROLES
节点角色,control-plane 是控制面,<none> 是工作节点
AGE
节点创建后的运行时间
VERSION
节点上的 Kubernetes 版本
INTERNAL-IP
节点在集群内部的 IP 地址(Docker 网络)
EXTERNAL-IP
外部可访问的 IP(Kind 环境无)
OS-IMAGE
节点容器内的操作系统
CONTAINER-RUNTIME
容器运行时(containerd 是 K8s 默认的容器运行时)
4.2 查看系统组件
输出 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-7d764666f9-9xzlc 1/1 Running 0 18s kube-system coredns-7d764666f9-s9pfm 1/1 Running 0 18s kube-system etcd-k8s-cluster-control-plane 1/1 Running 0 25s kube-system kindnet-267dt 1/1 Running 0 19s kube-system kindnet-kxncz 1/1 Running 0 18s kube-system kindnet-rp49k 1/1 Running 0 18s kube-system kube-apiserver-k8s-cluster-control-plane 1/1 Running 0 25s kube-system kube-controller-manager-k8s-cluster-control-plane 1/1 Running 0 25s kube-system kube-proxy-4bbcx 1/1 Running 0 18s kube-system kube-proxy-5mq89 1/1 Running 0 19s kube-system kube-proxy-6bzmj 1/1 Running 0 18s kube-system kube-scheduler-k8s-cluster-control-plane 1/1 Running 0 25s local-path-storage local-path-provisioner-67b8995b4b-fpggw 1/1 Running 0 18s
参数解释 :
-A 或 --all-namespaces:显示所有命名空间的 Pod
字段解释 :
字段
说明
NAMESPACE
命名空间,用于资源隔离。kube-system 存放系统组件
NAME
Pod 名称(格式:部署名-随机ID)
READY
就绪状态,格式 就绪容器数/总容器数
STATUS
Pod 状态,Running 表示正常运行
RESTARTS
容器重启次数
AGE
Pod 创建后的运行时间
系统组件说明 :
Pod
功能
coredns
集群内 DNS 服务,让 Pod 可以通过 Service 名称访问服务(如 nginx-svc.default.svc.cluster.local)
etcd
K8s 的数据库,存储集群所有状态信息(键值存储)
kindnet
Kind 的 CNI 网络,负责 Pod 网络通信
kube-apiserver
K8s API 服务器,所有请求(kubectl、应用)都通过它
kube-controller-manager
控制器管理器,维护集群状态(如 Pod 数量、节点健康)
kube-scheduler
调度器,决定新 Pod 运行在哪个节点上
kube-proxy
代理组件,负责 Service 的网络转发规则
local-path-provisioner
存储供应器,按需创建本地存储卷
命名空间(Namespace) 是类似文件系统的目录,用于隔离资源:
不同命名空间的资源互不可见(除非跨命名空间访问)
kube-system:系统组件的命名空间
default:用户默认的命名空间
5. 部署测试应用
5.1 创建 Deployment
Deployment 是 K8s 中管理应用的资源类型,
声明式定义:描述期望状态(如 nginx 运行 3 个副本)
无状态应用 控制器:自动维持 Pod 的数量和状态,挂了自动重启,更新自动滚动。Pod 是 k8s 中的最小运行单位(一个容器组)
Deployment 并不直接操作 Pod,它通过管理 ReplicaSet(副本集)来实现副本管理(Replicas)、滚动更新(Rolling Update)、版本回滚(Rollback)等功能
1 2 kubectl create deployment nginx --image=nginx:alpine --replicas=3 kubectl create deployment httpbin --image=kennethreitz/httpbin --replicas=2
create deployment:创建 Deployment(应用部署声明)
--image:使用的容器镜像
--replicas:副本数量,即运行多少个 Pod
查看当前的 deployment:
1 2 3 4 NAME READY UP-TO-DATE AVAILABLE AGE httpbin 2/2 2 2 122m nginx 3/3 3 3 122m
READY:就绪副本数/期望副本数
UP-TO-DATE:已更新到最新版本的副本数
AVAILABLE:可用的副本数
查看当前的业务 pods
1 2 3 4 5 6 7 8 NAME READY STATUS RESTARTS AGE LABELS httpbin-75c95868c8-b429q 1/1 Running 0 3h49m app=httpbin,pod-template-hash=75c95868c8 httpbin-75c95868c8-xh99r 1/1 Running 0 3h49m app=httpbin,pod-template-hash=75c95868c8 nginx-6658f59756-h82mq 1/1 Running 0 3h49m app=nginx,pod-template-hash=6658f59756 nginx-6658f59756-h8k5j 1/1 Running 0 3h49m app=nginx,pod-template-hash=6658f59756 nginx-6658f59756-z6zgf 1/1 Running 0 3h49m app=nginx,pod-template-hash=6658f59756
httpbin 的 2 个 Pod 也分布在两个 worker 节点
nginx 的 3 个 Pod 分布在 worker 和 worker2 两个节点
这是 K8s 调度器自动决定的,会考虑负载均衡
5.2 创建 Service
kubectl expose 的作用是为一组 Pod(通常是 Deployment 管理的 Pod)创建一个 Service,从而让这些 Pod 能够被访问。在 K8s 中,Pod 的 IP 地址是动态且不可靠的。如果一个 Pod 退出了,Deployment 会拉起一个新的 Pod,但新 Pod 的 IP 会变,这样就会导致客户端(或其它服务)无法通过一个固定的 IP 找到你的应用 。kubectl expose 会创建一个 Service。Service 拥有一个固定的虚拟 IP(ClusterIP),它像一个负载均衡器,会自动追踪并转发流量给后端那些变化的 Pod。
1 2 kubectl expose deployment nginx --port=80 --target-port=80 --type =NodePort --name=nginx-svc kubectl expose deployment httpbin --port=80 --target-port=80 --type =NodePort --name=httpbin-svc
expose deployment:为 Deployment 创建 Service
--port:Service 对外暴露的端口,其他服务访问 Service 时使用该端口
--target-port:容器内部的应用端口,也就是你的程序在容器里实际监听的端口
--type=NodePort:type 指定了 service 类型
ClusterIP (默认): 仅在集群内部可见,适合服务间通信
NodePort: 在每个 Node 上开启一个高位端口(30000+),让你可以通过 节点IP:端口 从集群外部访问
LoadBalancer: 如果你在云环境(阿里云、AWS),它会自动去申请一个公网负载均衡器
查看当前 service:
1 2 3 4 5 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpbin-svc NodePort 10.108.21.16 <none> 80:31995/TCP 135m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 135m nginx-svc NodePort 10.97.67.102 <none> 80:30858/TCP 135m
NAME:服务名称,集群内其他 Pod 可以通过这个名字直接访问(依靠 CoreDNS)
TYPE:服务类型,
ClusterIP: 仅限集群内访问
NodePort: 在每个节点上开启一个固定端口,允许外部访问
CLUSTER-IP:集群内部虚拟 IP,K8s 为服务分配的固定 IP。即使后端的 Pod 销毁重建,这个 IP 也永远不变
EXTERNAL-IP:外部访问 IP,在 Kind 或私有环境通常为 <none>。只有在阿里云/AWS 等云环境使用 LoadBalancer 时才会显示 IP
PORT(S):端口映射,格式为 Service端口:NodePort端口/协议。这是流量进入的 大门
需要注意,当你创建一个 NodePort 或 LoadBalancer 类型的 Service 时,Kubernetes 仍然会自动为其分配一个 ClusterIP(除非你显式设置 clusterIP: None,即 Headless Services 。在 Kubernetes 的设计逻辑中,Service 类型是**层层递进(继承)**的。你可以把这看作一个 包含关系:
ClusterIP:最基础的,只有 ClusterIP
NodePort:包含 ClusterIP + NodePort。
LoadBalancer:包含 ClusterIP + NodePort + External LoadBalancer IP(云厂商提供)
这样实现的原因是:
统一的内部访问入口:集群内的 Pod 可以通过 ClusterIP 稳定访问,无需知道 NodePort
kube-proxy 转发逻辑:kube-proxy 依赖 ClusterIP 配置 iptables/IPVS 规则
负载均衡:ClusterIP 提供负载均衡,NodePort 最终也转发到 ClusterIP
当你通过 NodePort 访问服务时,流量经过的链路如下:
用户请求 节点IP:31995
节点网络层捕获流量,根据 iptables 或 IPVS 规则将其转发给 ClusterIP (10.108.21.16:80)。
ClusterIP 负载均衡器再将流量转发给具体的 Pod IP
如果没有 ClusterIP,流量在进入节点后就没有一个统一的、稳定的目的地来做负载均衡了 。
因此对于上述服务:
6. 服务访问测试
6.1 通过临时 Pod 测试
由于 Kind 集群节点运行在 Docker 容器内,直接从宿主机访问 NodePort 较复杂。使用临时 Pod 测试是最可靠的方式。
1 kubectl run curl-test --image=curlimages/curl:latest --rm --restart=Never -it -- curl -s http://nginx-svc.default.svc.cluster.local/
输出:
1 2 3 4 5 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ......
kubectl run:创建一个临时 Pod 并运行命令
--rm:Pod 执行完毕后自动删除
--restart=Never:不自动重启
-it:交互模式,可以看到输出
curl -s:静默模式请求 URL
这里的 nginx-svc.default.svc.cluster.local 格式为:
nginx-svc:Service Name,你创建服务时指定的 NAME
default:Namespace,服务所属的命名空间。如果不指定,默认就在 default
svc:Resource Type,表示这是一个 Service 资源(区别于 pod)
Root Domain:Root Domain,cluster.local,K8s 集群默认的内部根域名(通常在安装时配置)
K8s 的 DNS 搜索域(Search Domains)非常智能,它可以让你在不同场景下使用 缩写:
同 Namespace 访问:只需要指定 nginx-svc 即可
跨 Namespace 访问:需要加命名空间,nginx-svc.default
最全路径(全限定域名):即当前这种格式
所以这样访问也是可以的:
通过 NodePort 访问
上述命令在 k8s 集群中创建客户端 Pod 并在客户端 Pod 内访问 nginx-svc 服务。这种集群内服务访问的方式本质上是通过 ClusterIP 的来访问的,如果想在 Kind 环境(节点是 Docker 容器)中通过 NodePort 来访问服务,有以下几种方式:
通过 docker exec 进入节点容器,然后 curl localhost:NodePort
1 2 3 4 HTTP/1.1 200 OK ......
1 2 3 4 5 6 7 8 9 10 11 12 13 14 k8s-cluster-control-plane 172.19.0.4 k8s-cluster-worker 172.19.0.3 k8s-cluster-worker2 172.19.0.2 HTTP/1.1 200 OK HTTP/1.1 200 OK Server: nginx/1.29.8
如果配置了 extraPortMappings,可以通过宿主机端口访问,但是由于我们之前配置的 extraPortMappings 中没有映射 30858 端口,因此这里服务无法通过宿主机端口访问
指定 Service 的 NodePort
我们新创建一个 NodePort 类型的 Service,并指定具体的 NodePort,这样就可以演示通过宿主机的 NodePort 来访问服务了。
服务的配置文件 nginx-external-svc.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Service metadata: name: nginx-external spec: type : NodePort selector: app: nginx ports: - port: 80 targetPort: 80 nodePort: 30000
1 kubectl apply -f /root/code/private/go/test/k8s/nginx-external-svc.yaml
1 2 3 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-external NodePort 10.96.2.159 <none> 80:30000/TCP 2m5s
通过宿主机映射的端口 30000(映射到容器的 30000 端口,也就是所指定的 NodePort)访问:
1 2 3 $ curl 10.9.33.133:30000 -I HTTP/1.1 200 OK Server: nginx/1.29.8
httpbin 服务也可以通过上面类似的方式访问,这里就不再赘述。
小结
这篇文章详细介绍了如何通过 KIND 在本地 Linux 服务器上搭建 k8s 环境,并学习了 k8s 的 集群、节点、Pod、Deployment、Service 等基础知识,后续我们就可以继续在这个环境中学习和实验 k8s 的各种功能特性了。