kind 是 Kubernetes in Docker 的简写,是一个使用 Docker 容器作为 Nodes,在本地创建和运行 Kubernetes 群集的工具,适用于在本机创建 Kubernetes 群集环境进行开发和测试,而且支持离线部署。
简介
实际上 Kind 是通过 Docker 容器来模拟一个 node 节点,在 Docker 容器里运行 systemd 并用来管理 kubelet 以及 containerd 服务,然后通过容器内部的 kubelet 把其他 k8s 组件跑起来,比如 kube-apiserver、etcd 等,最后部署上 CNI 整个集群就完成了。
注意,其内部也是通过 kubeadm 进行部署。
容器中会启动多个进程的 Pod 服务,为了方便管理,还会在容器外部启动一个 kubelet 服务,这样就可以无需进入容器直接使用 kubectl 命令了。
其中 Node 是基于 Debain
实现的容器。
准备工作
可以直接从 Github Release 上下载相应的版本,可以直接下载二进制文件,然后添加到 PATH 环境变量所在目录下。如果是离线使用,那么可以通过如下方式安装,实际上主要是准备 Docker 镜像,其中 Docker 镜像版本可以从上面的 Release 信息中获取。
----- 找台在线机器下载镜像,在上述Release Notes中会提及对应版本,也可以使用历史版本
# docker pull kindest/node:v1.27.2@sha256:3966ac761
----- 然后打包,两种方式都可以
# docker save -o kind.v1.27.2.tar kindest/node:v1.27.2@sha256:3966ac761
# docker save kindest/node:v1.27.2@sha256:3966ac761 | gzip > kind.v1.27.2.tar.gz
----- 在所需的离线环境中加载镜像,并重新定义tag
# docker load -i kind.v1.27.2.tar
# docker image tag kindest/node:v1.27.2@sha256:3966ac761 kindest/node:v1.27.2
离线启动时如果默认创建失败,那么可以尝试通过 --image
参数指定镜像。
Kind 通过容器保存了相关的二进制文件信息,其使用的镜像可以查看 Github Images 中的内容,简单来说,就是基于 Ubuntu 进行的适配,内部运行的是 containerd 的相关进程。
----- 也可以在启动后查看内部容器列表
# docker exec kind-control-plane crictl ps
集群操作
这里先创建一个简单的 K8S 集群,只包含一个 Node 节点。
----- 查看版本信息
# kind version
----- 配置文件
# cat cluster-config.yml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
----- 创建集群,默认的名字就是kind,同时会拉取最新的镜像
# kind create cluster --config=cluster-config.yml --name kind --image kindest/node:latest
----- 指定kubectl使用kind集群
# kubectl cluster-info --context kind-kind
----- 获取当前所有集群列表
# kind get clusters
----- 或者删除集群
# kind delete cluster --name kind
此时会在 Docker 中启动一个 kindest/node
镜像,可以通过 docker exec -it kind-control-plane /bin/bash
命令登录后查看对应的 K8S 版本,一般就是该镜像的版本号,这样就可以下载相应的 kubectl 二进制文件了,实际上也可以直接从镜像中复制出来。
----- 直接指定版本或者下载最新版本
$ curl -LO "https://dl.k8s.io/release/v1.27.4/bin/linux/amd64/kubectl"
$ curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
----- 然后进行安装
# install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
----- 需要先确定容器的ID(或者名称),直接从容器中复制出来
# docker cp kind-control-plane:/usr/bin/kubectl /usr/bin/
指定当前使用的集群信息。
----- 可以切换、查看集群,或者通过 kubeconfig 配置文件来设置默认集群
# kubectl cluster-info --context kind-kind
# kubectl cluster-info dump
然后就可以正常使用 K8S 集群了,例如如下命令。
----- 查看Node和Pod信息
# kubectl get nodes -o wide
# kubectl get pods -n kube-system
----- 可以查看某些组件的详细信息
# kubectl -n kube-system describe pods -l component=kube-controller-manager
在 kind 的 Node 内部则默认使用了 ptp 模型,可以查看 /etc/cni/net.d/10-kindnet.conflist
配置文件,该模型的通信机制比较简单,容器和 Node 直接通过一对 veth 进行通信。
节点内查询
因为 Kind 的节点是通过 Docker 进行模拟的,所以可以直接登录 Docker 进行查看。
----- 可以通过名称或者ID登录
# docker ps
----- 登录
# docker exec -it kind-control-plane /bin/bash
----- 查看启动的服务
# systemctl status kubelet
# systemctl status containerd
----- 也可以执行K8S相关的操作
# kubectl get node
配置文件
上面仅介绍了基础操作,除此之外还可以通过文件进行配置。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: your-kind-name # 用来指定集群的名字,或者启动时通过 --name 参数指定
featureGates: # 配置 K8S 集群中的 FeatureGates 参数,详见官方文档
"CSIMigration": true
nodes:
- role: control-plane
image: kindest/node:v1.27.3@sha256:XXX # 指定镜像版本
extraPortMappings: # 默认将APIServer的6443端口暴露为一个随机端口,其它可以在这里指定
- containerPort: 30000 # 将30000端口暴露出来,会将请求转发到该容器上
hostPort: 30000
listenAddress: "127.0.0.1" # 默认监听0.0.0.0
protocol: TCP
- role: worker
- role: worker
如果要高可用的控制平面,那么就多增加 control-plane
角色,多个节点的话就增加 worker
角色。
网络配置
其中 CNI 是 Kind 自己实现的 kindnetd 。
常用命令
----- 查看某个集群的配置信息
# kind get kubeconfig --name=kind
----- 停止或者启动集群直接通过 docker 执行即可
# docker stop test-drone-control-plane
# docker start test-drone-control-plane
存储管理
可以通过 kubectl get storageclass
命令查看当前支持的 StorageClass
信息,默认支持 local path provisioner
的实现,使用方式如下。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-path-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 128Mi
---
apiVersion: v1
kind: Pod
metadata:
name: volume-test
spec:
containers:
- name: volume-test
image: alpine:latest
imagePullPolicy: IfNotPresent
tty: true
stdin: true
volumeMounts:
- name: volv
mountPath: /data
volumes:
- name: volv
persistentVolumeClaim:
claimName: local-path-pvc
然后可以通过如下命令查看状态。
----- 未启动Pod时处于Pending状态,启动后是Bound状态
# kubectl get pvc
----- 可以写入测试数据,如果是attach方式,会导致重启
# kubectl exec volume-test -- sh -c "echo local-path-test > /data/test"
----- 删除、重启之后可以重新查看数据仍然存在
# kubectl delete -f pod.xml
# kubectl apply -f pod.xml
# kubectl exec volume-test -- sh -c "cat /data/test"
删除的过程中需要依次将 Pod、PVC、PV 删除即可,测试可以通过如下方式。
# kubectl exec foobar-fd9fb6dc4-m7cjm -- sh -c "echo local-path-test > /data/test"
# kubectl exec foobar-fd9fb6dc4-sd8vq -- sh -c "cat /data/test"
常用示例
端口映射
这种方式是将 Node 的 Port 暴露出来进行访问,这就要求 Kind 只能有一个节点,否则因为不确定具体绑定到那个节点,如果有多个 worker 那么最好是使用 ingress 方式。
----- 将 3000 端口映射出来
# vim kind-cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30080
protocol: TCP
----- 创建 Pod 简单映射
# vim kind-example-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Never
ports:
- containerPort: 80
hostPort: 30000
# kubectl create -f kind-example-pod.yaml
# curl http://127.0.0.1:30080
也可以通过 Deployment+Service
的方式映射。
----- 通过Pod/Deployment+Service映射
# vim kind-example-service.yaml
kind: Pod
apiVersion: v1
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Never
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- name: http
nodePort: 30000
port: 80
selector:
app: nginx
# kubectl create -f kind-example-service.yaml
# curl http://127.0.0.1:30080
常见问题
加载镜像
在 Kind 中创建的 K8S 集群会使用其 Node 上的镜像,所以,需要将将镜像加载到 Node 中才能被 K8S 使用,默认会直接从公网获取,如果无法获取,那么可以手动将镜像加载到 Node 节点上。
----- 加载alpine镜像
# kind load docker-image alpine:latest --name kind
----- 可以重命名
# kind load docker-image alpine:latest alpine:test --name kind
----- 然后可以运行镜像了
# kubectl run alpine --image=alpine --image-pull-policy=Never -i --tty /bin/sh
配置优化
默认的 APIServer 只会监听本地端口,这样本地环境之外就无法访问。另外,由于国内网络会导致默认 DockerHub 镜像经常无法访问或者超时,可以通过如下方式进行修改。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
apiServerAddress: "<API_SERVER_ADDRESS>"
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["http://f1361db2.m.daocloud.io"]
更多配置,如多节点、不同节点版本化、Pod/Service 子网、KubeProxy 模式、端口映射、本地卷持久化等可以查看 Kind Docs 。
机器重启
如果是 Docker 服务重启的话是不会影响到 kind 的运行的,详细可以参考 Githug Issues 18 中的介绍。
不过当机器重启对应的 Kind 相关进程会挂掉,如果直接再执行 kind create
会报 ERROR: failed to create cluster: node(s) already exist for a cluster with the name "kind"
的错误,需要删除后重新创建,暂时没有看到直接启动的命令。
# kind delete cluster --name kind
然后再重新创建并启动即可。注意,无法直接通过 docker restart
这种方式启动,因为除了启动 docker 相关的内容之外还有一些额外的操作。
参考
- Kind Docs 这里包含了很多开发文档,不确定的场景可以直接查看。