在这一篇中我们将使用kubeadm基于ubuntu22.04部署一个控制、工作节点分离的双节点集群用于测试,没有高可用加入,使用kubeadm的原因首先是它支持生产级部署,稳定性上没问题,而这里的测试环境也没有基础设施自动化相关的需求。注意,在部署k8s方面,官方文档已经非常详尽,此处不再做太多的细节说明,如果有细节问题请查看列出的官方参考,或者可以通过评论提出问题。

这里需要注意kubeadm的版本,它决定了k8s的版本,参考istio的Getting Started文档,里面指出了能够支持的k8s最新版本为1.28。所以我们的根参考文档是k8s1.28的文档:https://v1-28.docs.kubernetes.io/docs/setup/production-environment/tools/kubeadm/,注意链接中的v1-28字样,博客中所有官方文档链接都是1.28版本的

如果你从k8s官网进入文档,记得在文档右上角切换版本:

在这里插入图片描述

准备

有两个节点:

  • m,master节点,运行控制面组件
  • w,worker节点,运行应用负载

基础环境

参考Before you begin,这里仅列出容易出现问题的点:

  • 最低配置为2c2g
  • 集群内机器hostname、mac、product_uuid唯一,k8s利用后两者标识不同的节点
  • 必须关闭swap,因为cgroupv1不支持swap,kubeadm虽然已经包含支持swap的beat特性但默认关闭,并且默认情况下它检测到使用swap会退出,实际上,swap是内存昂贵时代的解决方案,以降低服务质量(换入换出会对程序性能产生很大的影响)来换取可用性,但以当今的服务量级,服务质量下降可能带来其他更多的问题,所以大多数情况下都不建议开启swap,内存不够可以增加,也不必再关注swap内存回收的细节,感兴趣可以阅读为什么 Linux 需要 Swapping
  • 在每个节点安装容器运行时,在本系列第一篇中已经部署了contianerd

在后面的安装k8s集群部分还有一些准备工作。

安装kubeadm和组件

在每个节点安装kubeadm、kubelet,在需要命令行客户端的节点安装kubectl,参考Installing kubeadm, kubelet and kubectl,因为是全新安装所以不必关注k8s组件版本兼容规则,需要注意三点:

  • 安装istio支持的1.28版本,使用1.28版本文档中的命令就会安装1.28的最新修订版本
  • 为kubelet指定cgroup driver为systemd,与容器运行时保持一致
  • 别遗漏命令sudo apt-mark hold kubelet kubeadm kubectl以锁定版本,否则自动升级会带来比较大的风险。

以上步骤中不太清晰的是配置kubelet的cgroup driver,需要在m节点创建配置文件kubeadm-config.yaml并在kubeadm初始化时使用,这个文件会被kubeadm传递成为所有节点的/var/lib/kubelet/config.yaml文件,并会保存为kube-systemnamespace下的configmap对象。可以从Configuring the kubelet cgroup driver文档获取最小配置,已经修改kubernetesVersion

kind: ClusterConfiguration
apiVersion: kubeadm.k8s.io/v1beta3
kubernetesVersion: v1.28.0
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd

使用配置文件的详细信息可以从Using kubeadm init with a configuration file文档中看到,如果执行命令kubeadm config print init-defaults可以看到输出中kubernetesVersion的值为1.28.0,虽然当前的实际版本是1.28.5

安装k8s集群

准备

主要是对网络、容器运行时和镜像的准备。

在本系列第一篇的基础环境部分介绍了测试环境的网络架构,在所有节点执行命令ip route show可以看到指向默认网关的接口为nat网络接口,kubeadm与其他k8s组件一样使用与默认网关关联接口的ip作为工作ip,对于这个ip的要求是:

  • 固定的ip,因为它会被自动写入到很多配置当中去
  • 节点间能够通过工作ip互通

网络配置文件/etc/netplan/00-installer-config.yaml示例:

# This is the network config written by 'subiquity'
network:
  ethernets:
    enp0s3:                    # 仅主机网络接口
      addresses:
        - 192.168.56.60/24
    enp0s8:                    # nat网络接口
      dhcp4: false             # 静态ip
      routes:                  # 默认网关
        - to: default
          via: 10.0.2.1
      addresses:
        - 10.0.2.51/24
      nameservers:             # dns
        addresses:
          - 8.8.8.8
  version: 2

另外,参考Troubleshooting kubeadm文档的Pods are not accessible via their Service IP部分可知,对于virtualbox,需要确保命令hostname -i能够返回一个路由可达的地址,具体的方法是将/etc/hosts文件中与主机名对应的127.0.0.1修改为该节点的工作ip,/etc/hosts部分示例:

127.0.0.1 localhost
10.0.2.51 ubuntu-dev60-k8sm1

执行命令kubeadm config images list可以看到kubeadm需要的镜像,其中pause镜像为registry.k8s.io/pause:3.9,所以需要执行命令sudo vim /etc/containerd/config.toml,修改配置文件中sandbox_image的值与之匹配。在本系列第一篇中已经为contianerd配置了对应仓库的mirror,kubeadm初始化时可以直接pull镜像,不用提前准备,当然也可以预先在每个节点执行命令sudo kubeadm config images pull拉取镜像,这样在初始化的时候能够更加快速的看到反馈。拉取至本地的镜像可以执行命令sudo crictl images list查看。

初始化控制平面m节点

在初始化控制平面节点之前,首先应该确定初始化命令的参数,之前已经为设置cgroup dirver准备了一个配置文件,不做高可用的话主要是考虑网络插件的诉求,此时所有节点上未添加cni插件配置,/etc/cni/net.d/目录为空

官方在Installing Addons文档中列出了不完全的网络插件列表,流行网络插件的对比可以参考rancher的文档CNI 网络插件,这里选择flannel,从项目主页可以看到它默认使用10.244.0.0/16作为pod cidr(包含在kube-flannel.yml文件中),插件的cidr必须与kubeadm中ClusterConfiguration中的对应设置保持一致,否则flannel pod无法启动。一个问题是flannel的默认cidr很容易看到,kubeadm却不容易(前面提到的打印初始化默认配置看不到),可以参考kubeadm Configuration (v1beta3)文档,其中的podSubnet配置对应kubeadm命令行参数--pod-network-cidr(文档中并没有提到两项配置的对应关系),可以看到其默认值是10.244.0.0/24,必须使之保持一致的话,修改哪一方都是可以的。还有一个问题,对于kubeadm来说参数--pod-network-cidr --config无法同时使用,否则会产生错误can not mix '--config' with arguments [pod-network-cidr]。这里选择在kubeadm-config.yaml中添加目前需要的配置,最终的配置内容为:

kind: ClusterConfiguration
apiVersion: kubeadm.k8s.io/v1beta3
kubernetesVersion: v1.28.0
networking:
  podSubnet: "10.244.0.0/16"
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd

现在,在m节点执行初始化命令:

sudo kubeadm init --config kubeadm-config.yaml

当看到这样的输出信息时:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.3.15:6443 --token b4ci5u.nwpagzl6cq4y035n \
        --discovery-token-ca-cert-hash sha256:cf300f9a479d5988c3d8a655530866d2abb69581812dae1626cad16dd3e381bb 

说明控制面节点已经初始化成功(不能等同于节点部署成功),接下来按照输出中提示的命令配置kubectl访问集群的凭证($HOME/.kube/config),完成后就可以执行命令kubectl get pods -A查看pod的状态。可以看到coredns pod因为网络插件未就绪而处于pending状态。接下来执行命令安装网络插件flannel,参考Deploying Flannel with kubectl,为避免网络缓慢,可以提前准备kube-flannel.yml文件:

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

flannel会在/etc/cni/net.d目录下创建网络配置。当看到所有的pod都处于running状态后,说明节点部署成功。

处理初始化失败

如果初始化过程失败,参考Clean up文档reset后再修复问题重新初始化,文档中命令假定root用户,如果用sudo提权,注意执行命令sudo sh -c "iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X"清理iptables,还有一些清理行为是包含在kubeadm命令输出中的,同样需要注意。

加入工作节点

现在可以在其他节点执行初始化打印中的join命令加入w节点了。

其余操作从Managed node labels开始根据情况自行处理即可,主要关注的是控制面节点隔离(禁止工作负载调度至控制面节点)。

安装容器管理工具kuboard

k8s的dashboard有些简陋,这里安装一个轻量的管理界面kuboard以简化对k8s的操作。参考安装 Kuboard v3 - 内建用户库,这里不使用docker,而是使用nerdctl(注意修改ip与挂载至容器的本地目录):

sudo nerdctl run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -p 10081:10081/tcp \
  -e KUBOARD_ENDPOINT="http://192.168.56.60:80" \
  -e KUBOARD_AGENT_SERVER_TCP_PORT="10081" \
  -v /home/ian/opt/kuboard/data:/data \
  eipwork/kuboard:v3

在这里插入图片描述

总结

虽然k8s的官方文档很详尽,但是想要一帆风顺也不容易。本篇因为没有使用高可用架构,相对简单一些,如果使用高可用,就需要使用一个负载均衡(例如kube-vip)来分发访问多个控制面节点的流量,更进一步的话可以把存储etcd集群放到外部(参考Options for Highly Available Topology)。

从部署过程可以看出,kubeadm无法自动化众多的准备工作,如果规模化使用,需要结合标准的操作系统镜像和ansible之类的自动化工具,可以尝试看看其他部署工具的方案。

k8s做了很多抽象,是一个复杂度很高的基础设施,在下一篇中会直接部署istio的demo应用,然后在下下篇中会对k8s相关的概念做一个整体的介绍,再然后才能谈得上体验istio。对于k8s,建议至少刷一遍官方文档。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐