使用 kind 搭建 K8s 多节点集群
CSDN 2024-10-06 09:07:03 阅读 72
Kind(Kubernetes in Docker)简介
<code>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-started
kind: 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 Sharing
extraMounts:
- hostPath: ~/node_volume # 需提前创建
containerPath: /node_volume
- hostPath: ~/node_volume/example_file
containerPath: /example_file
readOnly: true # 默认false
selinuxRelabel: false # 默认false。selinuxRelabel是一个linux内核安全模块,请自行查询此参数的用途
propagation: None # https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation
# 可选的端口映射配置,用于像节点容器传入流量
# 若使用Docker for Desktop,则必须配置
extraPortMappings:
- containerPort: 30080 # 作为Pod的hostPort
hostPort: 80
# listenAddress: "127.0.0.1" # 默认0.0.0.0
protocol: 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
sudo rm <path>
安装kubectl v1.27.3版本:
curl -LO "https://dl.k8s.io/release/v1.27.3/bin/darwin/arm64/kubectl"
sudo mv kubectl /usr/local/bin
sudo chmod +x /usr/local/bin/kubectl
kubectl version
该命令安装arm64架构的kubectl,其他架构请参考kubectl安装文档。
1.2 连接集群
kind在创建集群后会自动在本机的$HOME/.kube/config
处配置好kubeconfig文件。此时我们已经可以使用kubectl来连接并管理集群了。
kubectl cluster-info
# 查看宿主机上的节点容器列表
docker ps |grep test-1.27
# 查看使用的容器运行时(containerd)
docker exec -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之后,查看节点容器中的镜像:
$ docker exec -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: 80
targetPort: 8080
nodePort: 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官方文档
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。