Kind(Kubernetes in Docker)简介
Kind
是一个使用Docker容器“节点”运行本地
Kubernetes
集群的工具。它允许用户快速创建、删除
Kubernetes
集群,非常适合本地开发和测试。
Kind
的名称是
Kubernetes in Docker
的缩写,意味着它将
Kubernetes
的所有组件部署在一个或多个
Docker
容器中,以此来模拟一个完整的
Kubernetes
集群。通过
Kind
,用户可以轻松地搭建单节点或多节点的
Kubernetes
集群,这对于开发和测试
Kubernetes
相关的应用非常有帮助。
使用
Kind
安装配置集群的步骤相对简单,首先需要确保已经安装了
Docker
和
Go
环境。安装完成后,用户可以通过命令行工具Kind来创建和管理
Kubernetes
集群。Kind支持通过配置文件来定义集群的配置,包括节点数量、网络配置等,从而满足不同场景下的需求。此外,Kind还支持高可用集群的搭建,通过模拟多个节点来实现集群的高可用性。
Kind
的主要用途包括:
- 本地开发:开发者可以使用Kind在本地快速搭建一个Kubernetes环境,模拟生产环境的各种场景,从而加速应用的开发和测试过程。
- 测试:由于Kind搭建的集群完全在本地运行,因此非常适合进行单元测试、集成测试等,确保应用在Kubernetes环境中的兼容性和稳定性。
- 教育和学习:对于学习和教学来说,Kind提供了一个低成本、高效率的方式来理解和实践Kubernetes的工作原理和架构。
总之,
Kind
是一个功能强大且易于使用的工具,无论是开发者、测试人员还是教育工作者,都可以通过它来更好地理解和使用
Kubernetes
。
使用kind安装配置集群
kind
主要用于在本地机器上快速启动一个
Kubernetes
集群,由
K8s
官方开发设计,用于日常开发和测试(勿用于生产环境)。
本文参照kind官方文档,介绍如何使用kind安装配置Kubernetes集群。
笔者使用的机器是MacBookPro M1,所以演示的一些命令为macOS平台下的指令。
kind内部使用kubeadm来启动一个多节点集群,它使用自实现的
kindnetd
作为容器网络接口(CNI)实现。更多设计细节参考kind设计文档。
1. 安装kind
支持多种方式安装,笔者是macOS,所以使用Homebrew安装:
brew install kind
其他系统参考二进制安装kind。
2. 创建一个集群
kind使用一个构建好的节点镜像以容器的形式来启动一个集群(一个K8s单节点集群运行在一个容器中),镜像中包含了Kubernetes的关键组件,比如kubelet等。
节点镜像托管在DockerHub
,查看它的更多介绍。
创建命令如下:
kind create cluster --image=kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72
如果不使用
--image
flag,则使用当前kind版本默认的节点镜像。但为了确定安装行为,请使用
--image
flag。
在kind版本发布页查找当前kind版本的预构建的不同K8s版本的节点镜像tag。
如果没有你想要的
K8s
版本,参考这个页面自行构建节点镜像。
创建后使用下面的命令简单管理集群:
kind get clusters
kind delete cluster -n<name>
当然,以上只是以最简化的集群配置方式启动。
kind
支持通过
yaml
文件[
kind-config.yaml
]来详细配置集群的启动参数,以下是一个包含注释的
1主2Worker集群
的完整
kind
配置示例。使用配置文件启动集群:
# nonk8s# 此配置文件的完整说明位于:https://kind.sigs.k8s.io/docs/user/configuration/#getting-startedkind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: test-1.27# 集群名featureGates:# 启动/禁用K8s的特性门"AdmissionWebhookMatchConditions":true# 配置API Server的--runtime-config# https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/runtimeConfig:"api/alpha":"false"# 配置集群的网络#networking:# ipFamily: ipv6# apiServerAddress: 127.0.0.1 # 默认127.0.0.1# apiServerPort: 6443 # 默认随机# podSubnet: "10.244.0.0/16" # 默认值# serviceSubnet: "10.96.0.0/12" # 默认值# disableDefaultCNI: true # 默认false,禁用后需安装其他CNI,例如calico# kubeProxyMode: "ipvs" # kube-proxy使用的组件,默认iptables,设置none则禁用 kube-proxy# 配置节点,下面是一个一主多worker的配置nodes:-role: control-plane # 默认的主节点# 可选的为每个节点配置使用的节点镜像,不指定则使用kind版本对应的默认值image: kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72
# 可选的节点路径映射配置,用于持久化数据# 若使用mac或win上的docker,需要检查hostPath必须存在于Docker配置中的Preferences -> Resources -> File SharingextraMounts:-hostPath: ~/node_volume # 需提前创建containerPath: /node_volume
-hostPath: ~/node_volume/example_file
containerPath: /example_file
readOnly:true# 默认falseselinuxRelabel:false# 默认false。selinuxRelabel是一个linux内核安全模块,请自行查询此参数的用途propagation: None # https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation# 可选的端口映射配置,用于像节点容器传入流量# 若使用Docker for Desktop,则必须配置extraPortMappings:-containerPort:30080# 作为Pod的hostPorthostPort:80# listenAddress: "127.0.0.1" # 默认0.0.0.0protocol: TCP # 支持TCP(默认),有UDP, SCTP# 可选的节点标签配置labels:tier: frontend
# 因为使用kubeadm启动集群,所以支持kubeadm的配置文件(可选)kubeadmConfigPatches:-|
# 仅限第一个主节点使用InitConfiguration
kind: InitConfiguration # 还支持ClusterConfiguration,KubeProxyConfiguration,KubeletConfiguration,JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "master=true"-role: worker
kubeadmConfigPatches:-|
kind: JoinConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "worker=true"-role: worker
# 注意内存占用,主节点占用约500MB,Worker节点占用约200MB,总共占用约1GB。确保你的宿主机内存充足
kind create cluster --config=kind-config.yaml --retain--wait=1m
其中的
--retain
flag表示在
kind
命令执行结束后保留节点容器,否则集群会自动删除。保留的目的是方便在启动集群失败时进入容器查看错误日志:
journalctl -xeu kubectl
--wait=1m
是等待控制节点
Ready
的最长等待时间。下文将使用这个集群进行演示。
1.1 安装kubectl
kind创建集群后,我们需要在本机上安装
kubectl
来连接并管理集群。
如果你的机器已存在
kubectl
但版本与安装的
k8s
版本不同,可通过以下方式卸载:
which kubectl
sudorm<path>
安装kubectl v1.27.3版本:
curl-LO"https://dl.k8s.io/release/v1.27.3/bin/darwin/arm64/kubectl"sudomv kubectl /usr/local/bin
sudochmod +x /usr/local/bin/kubectl
kubectl version
该命令安装arm64架构的kubectl,其他架构请参考kubectl安装文档。
1.2 连接集群
kind在创建集群后会自动在本机的
$HOME/.kube/config
处配置好kubeconfig文件。此时我们已经可以使用kubectl来连接并管理集群了。
kubectl cluster-info
# 查看宿主机上的节点容器列表dockerps|grep test-1.27
# 查看使用的容器运行时(containerd)dockerexec-it test-1.27-control-plane crictl info|grep runtimeType
不过有个问题得注意一下,
containerd
默认的镜像仓库地址是
docker.io
,后续使用
K8s
拉取远端镜像会特别慢,
你可以参考
containerd.config.toml
,来修改每个节点容器中的containerd配置文件(位于
/etc/containerd/config.toml
,搜索关键字
registry.mirrors
),修改后需要重启containerd(
service containerd restart
)。
containerd.config.toml
配置:
disabled_plugins =[]
imports =[]
oom_score =0
plugin_dir =""
required_plugins =[]
root ="/var/lib/containerd" # 容器存放路径,确保可用空间充足
state ="/run/containerd"
version =2[cgroup]
path =""[debug]
address =""
format =""
gid =0
level =""
uid =0[grpc]
address ="/run/containerd/containerd.sock"
gid =0
max_recv_message_size =16777216
max_send_message_size =16777216
tcp_address =""
tcp_tls_cert =""
tcp_tls_key =""
uid =0[metrics]
address =""
grpc_histogram = false
[plugins][plugins."io.containerd.gc.v1.scheduler"]
deletion_threshold =0
mutation_threshold =100
pause_threshold =0.02
schedule_delay ="0s"
startup_delay ="100ms"[plugins."io.containerd.grpc.v1.cri"]
disable_apparmor = false
disable_cgroup = false
disable_hugetlb_controller = true
disable_proc_mount = false
disable_tcp_service = true
enable_selinux = false
enable_tls_streaming = false
ignore_image_defined_volumes = false
max_concurrent_downloads =3
max_container_log_line_size =16384
netns_mounts_under_state_dir = false
restrict_oom_score_adj = false
sandbox_image ="registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6"
selinux_category_range =1024
stats_collect_period =10
stream_idle_timeout ="4h0m0s"
stream_server_address ="127.0.0.1"
stream_server_port ="0"
systemd_cgroup = false
tolerate_missing_hugetlb_controller = true
unset_seccomp_profile =""[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir ="/opt/cni/bin"
conf_dir ="/etc/cni/net.d"
conf_template ="/etc/cni/net.d/cni-default.conf"
max_conf_num =1[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name ="runc"
disable_snapshot_annotations = true
discard_unpacked_layers = false
no_pivot = false
snapshotter ="overlayfs"[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
base_runtime_spec =""
container_annotations =[]
pod_annotations =[]
privileged_without_host_devices = false
runtime_engine =""
runtime_root =""
runtime_type =""[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options][plugins."io.containerd.grpc.v1.cri".containerd.runtimes][plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
base_runtime_spec =""
container_annotations =[]
pod_annotations =[]
privileged_without_host_devices = false
runtime_engine =""
runtime_root =""
runtime_type ="io.containerd.runc.v2"[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
BinaryName =""
CriuImagePath =""
CriuPath =""
CriuWorkPath =""
IoGid =0
IoUid =0
NoNewKeyring = false
NoPivotRoot = false
Root =""
ShimCgroup =""
SystemdCgroup = true
[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime]
base_runtime_spec =""
container_annotations =[]
pod_annotations =[]
privileged_without_host_devices = false
runtime_engine =""
runtime_root =""
runtime_type =""[plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options][plugins."io.containerd.grpc.v1.cri".image_decryption]
key_model ="node"[plugins."io.containerd.grpc.v1.cri".registry]
config_path =""[plugins."io.containerd.grpc.v1.cri".registry.auths][plugins."io.containerd.grpc.v1.cri".registry.configs][plugins."io.containerd.grpc.v1.cri".registry.headers][plugins."io.containerd.grpc.v1.cri".registry.mirrors][plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint =["https://docker.mirrors.ustc.edu.cn","http://hub-mirror.c.163.com"][plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
endpoint =["https://gcr.mirrors.ustc.edu.cn"][plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint =["https://gcr.mirrors.ustc.edu.cn/google-containers/"][plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
endpoint =["https://quay.mirrors.ustc.edu.cn"][plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]
tls_cert_file =""
tls_key_file =""[plugins."io.containerd.internal.v1.opt"]
path ="/opt/containerd"[plugins."io.containerd.internal.v1.restart"]
interval ="10s"[plugins."io.containerd.metadata.v1.bolt"]
content_sharing_policy ="shared"[plugins."io.containerd.monitor.v1.cgroups"]
no_prometheus = false
[plugins."io.containerd.runtime.v1.linux"]
no_shim = false
runtime ="runc"
runtime_root =""
shim ="containerd-shim"
shim_debug = false
[plugins."io.containerd.runtime.v2.task"]
platforms =["linux/amd64"][plugins."io.containerd.service.v1.diff-service"]default=["walking"][plugins."io.containerd.snapshotter.v1.aufs"]
root_path =""[plugins."io.containerd.snapshotter.v1.btrfs"]
root_path =""[plugins."io.containerd.snapshotter.v1.devmapper"]
async_remove = false
base_image_size =""
pool_name =""
root_path =""[plugins."io.containerd.snapshotter.v1.native"]
root_path =""[plugins."io.containerd.snapshotter.v1.overlayfs"]
root_path =""[plugins."io.containerd.snapshotter.v1.zfs"]
root_path =""[proxy_plugins][stream_processors][stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
accepts =["application/vnd.oci.image.layer.v1.tar+encrypted"]
args =["--decryption-keys-path","/etc/containerd/ocicrypt/keys"]
env =["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path ="ctd-decoder"
returns ="application/vnd.oci.image.layer.v1.tar"[stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
accepts =["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
args =["--decryption-keys-path","/etc/containerd/ocicrypt/keys"]
env =["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path ="ctd-decoder"
returns ="application/vnd.oci.image.layer.v1.tar+gzip"[timeouts]"io.containerd.timeout.shim.cleanup"="5s""io.containerd.timeout.shim.load"="5s""io.containerd.timeout.shim.shutdown"="3s""io.containerd.timeout.task.state"="2s"[ttrpc]
address =""
gid =0
uid =0
当然还有另一种办法,那就是直接使用宿主机的docker镜像,后面的3.1节会介绍如何操作。
1.4 创建并管理多个集群
前面已经介绍了可以通过
kind get clusters
看到当前kind安装的K8s集群列表。这就告诉了我们kind可以同时安装多个集群。
安装多集群后,可以切换context来连接不同的集群。
# 安装两个集群
$ kind create cluster
$ kind create cluster --name kind-2
# 查看集群列表
$ kind get clusters
kind
kind-2
# 切换context(默认是kind-kind)
$ kubectl cluster-info --context kind-kind
$ kubectl cluster-info --context kind-kind-2
3. 部署应用
3.1 添加镜像到节点容器
如果我们想要将宿主机上已存在的docker镜像直接导入节点容器(免去重复拉取),参照下面的命令:
# 需要先将镜像拉取到宿主机docker pull busybox
# 再进行load操作
kind load docker-image busybox -n test-1.27
# 也可以从tar包导入
kind load image-archive /my-image-archive.tar
# 导入镜像到特定节点容器(默认所有)
kind load docker-image <image1>--nodes<node-name>
Load之后,查看节点容器中的镜像:
$ dockerexec-it test-1.27-control-plane crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/kindest/kindnetd v20230511-dc714da8 b18bf71b941ba 25.3MB
docker.io/kindest/local-path-helper v20230510-486859a6 d022557af8b63 2.92MB
docker.io/kindest/local-path-provisioner v20230511-dc714da8 eec7db0a07d0d 17.3MB
docker.io/library/busybox latest 23466caa55cb7 4.27MB
registry.k8s.io/coredns/coredns v1.10.1 97e04611ad434 14.6MB
registry.k8s.io/etcd 3.5.7-0 24bc64e911039 80.7MB
registry.k8s.io/kube-apiserver v1.27.3 634c53edb5c14 79.8MB
registry.k8s.io/kube-controller-manager v1.27.3 aea4f169db16d 71.5MB
registry.k8s.io/kube-proxy v1.27.3 278dd40f83dfb 68.1MB
registry.k8s.io/kube-scheduler v1.27.3 6234a065dec4c 57.6MB
registry.k8s.io/pause 3.7 e5a475a038057 268kB
3.2 部署Pod
注意,我们前面已经在宿主机上安装了kubectl,所以现在可以直接在宿主机上管理集群,而不需要进入节点容器。
pod_busybox.yaml
配置如下:
apiVersion: v1
kind: Pod
metadata:name: busybox
labels:app: busybox
spec:containers:-name: busybox-container
image: busybox
command:["sleep","infinity"]
下面以清单 [
pod_busybox.yaml
]为例进行部署演示。
$ kubectl apply -f pod_busybox.yaml
# 清单中使用的镜像是上一节中导入的镜像,所以Pod应该很快Running
$ kubectl get po
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 36s
再部署一个可通过宿主机访问的应用 [
deployment_python_http_svc_nodeport.yaml
]:
apiVersion: apps/v1
kind: Deployment
metadata:name: python-http-serv
spec:selector:matchLabels:app: http
template:metadata:labels:app: http
spec:containers:-name: http-container
image: python:3.9-alpine
command:["python3","-mhttp.server","8080"]ports:-containerPort:8080---apiVersion: v1
kind: Service
metadata:name: python-http-serv
spec:type: NodePort
selector:app: http
ports:-port:80targetPort:8080nodePort:30080
具体操作:
$ docker pull python:3.9-alpine
$ kind load docker-image python:3.9-alpine -n test-1.27
$ kubectl apply -f deployment_python_http_svc_nodeport.yaml
$ kubectl get po
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 1(15m ago) 19m
python-http-serv-6b874b4bdf-wtfhl 1/1 Running 0 5s
# 访问宿主机80端口(映射到控制平面节点的30080端口),可以看到一个HTML输出,其中包含Pod内容器的根目录下的文件列表# 推荐使用浏览器访问
$ curl http://localhost/
结尾
在查看
kind
官方文档的时候,发现kind缺少一个可能比较关键的功能,那就是在
kind
配置文件限制节点容器的CPU/Memory额度。遗憾的是,
笔者看到了kind仓库中的这个ISSUE #1422
,也就是说kind截止目前(2024-1-2)也没有支持这个功能。
以上就是使用kind在MacOS上安装一个多节点集群的过程,其他操作系统的安装过程也是大差不差,具体可以看kind官文。
如果你有遇到问题请提出ISSUE,但也希望你能够先看一下官方kind文档。
参考
- kind官方文档
版权归原作者 码踏云端 所有, 如有侵权,请联系我们删除。