0


使用 kind 搭建 K8s 多节点集群

在这里插入图片描述

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

主要用途包括:

  1. 本地开发‌:开发者可以使用Kind在本地快速搭建一个Kubernetes环境,模拟生产环境的各种场景,从而加速应用的开发和测试过程。
  2. 测试‌:由于Kind搭建的集群完全在本地运行,因此非常适合进行单元测试、集成测试等,确保应用在Kubernetes环境中的兼容性和稳定性。
  3. 教育和学习‌:对于学习和教学来说,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官方文档

本文转载自: https://blog.csdn.net/lilinhai548/article/details/141933955
版权归原作者 码踏云端 所有, 如有侵权,请联系我们删除。

“使用 kind 搭建 K8s 多节点集群”的评论:

还没有评论