Others · 2022年3月18日 0

如何搭建k8s集群

前言

最近正好在腾讯云白嫖了一台4核4G的服务器,于是又有了可以折腾的东西了。于是打算用两台服务器搭建k8s集群。为啥要在两台云服务器上搭呢?(因为折腾坏了可以一键重装,非常方便,结果一不小心踩了好多坑

安装

关闭swap

关闭swap防止影响性能,需要编辑/etc/fstab文件,注释掉下面这一行

/swapfile swap swap defaults 0 0

关闭SELinux

关闭SELinux以允许容器访问宿主机文件系统,需要编辑/etc/sysconfig/selinux文件,将SELINUX设置为disabled

SELINUX=disabled

配置防火墙

需要配置的端口如下:

组件 默认端口号
API Server 8080(HTTP非安全端口号) 6443(HTTPS安全端口号)
Controller Manager 10252
Scheduler 10251
kubelet 10250 10255(只读端口号)
etcd 2379(供客户端访问) 2380(供etcd集群内部节点直接访问)
集群DNS服务 53(TCP和UDP)

除此之外其他组件还需要开通某些端口,比如CNI网络插件需要179端口,镜像库需要5000端口。

安装docker

curl -fsSL https://mirrors.tencent.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
  "deb [arch=amd64] https://mirrors.tencent.com/docker-ce/linux/ubuntu/ \
 $(lsb_release -cs) \
stable"
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io

安装GPG证书

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add

添加apt源

cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
sudo apt update -y

安装kubelet、kubeadmkubectl

sudo apt install kubelet kubeadm kubectl

安装mater节点

修改kubeadm默认配置

kubeadm init命令和kubeadm join都可以通过指定配置文件修改默认参数的值。kubeadm config子命令提供了对这组功能的支持

  • kubeadm config print init-defaults:输出kubeadm init命令默认参数的内容

  • kubeadm config print join-defaults:输出kubeadm join命令默认参数的内容

  • kubeadm config migrate:可以对于新旧版本之间的配置文件进行转换

  • kubeadm config images list:输出所需镜像列表

  • kubeadm config images pull:拉取镜像到本地

kubeadm config print init-defaults > init-config.yaml

然后可以得到一份默认的yaml配置文件,然后大概需要修改这几个地方:

apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system: bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
……
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.0.16.4
  bindPort: 6443
……
apiServer:
  certSANs:
  - k8s.eastjun.xyz
  - 121.5.27.225
controlPlaneEndpoint: 121.5.27.225:6443
……
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.23.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 192.168.0.0/12
scheduler: {}
  • advertiseAddressAPI Server监听的地址,需要修改为网卡地址,或者0.0.0.0bindPortAPI Server监听的端口。

  • token需要进行修改,默认的配置文件中有一个默认的token,需要我们自己进行修改,或者可以直接删掉,然后它会生成一个随机的token

  • 国内环境无法访问k8s官方仓库,需要指定imageRepository为国内的地址,这里指定它为阿里的镜像仓库地址。

  • certSANs设置证书的IP地址和域名,这个要和Node加入集群时的地址一致,不然Node会觉得证书无效不让我们加入

  • controlPlaneEndpoint也要和Node加入集群时的地址一致,不然Node会尝试连接Master节点的网卡地址,而这个网卡的地址可能是内网地址,Node访问不到

  • 然后serviceSubnet可以设置Pod的IP地址范围。

实际上这份配置文件并不包含所有的选项,一份比较完整的配置文件可以参考这里

下载相关镜像

执行kubeadm config images list可以获取所需镜像的列表,为了加快kubeadm创建集群的过程,可以提前将所需镜像下载完成,可以执行kubeadm config images pulldocker pull命令下载镜像

kubeadm config images pull --config=init-config.yaml

使用kubeadm命令安装master节点

kubeadm init命令进行具体的安装操作之前首先会进行一系列的系统预检查,确保主机环境符合安装要求,如果检查失败就直接终止。用户可以通过kubeadm init phase preflight命令进行预检查的操作,确保系统就绪后再执行init操作。

kubernetes默认的cgroup驱动为systemd,而docker默认的cgroup驱动为cgroupfs,为了与kubernets保持一致,需要修改docker服务的配置文件为systemd,需要在daemon.json文件中设置:

{
   "exec-opts":["native.cgroupdriver=systemd"]
}

在一切准备就绪之后执行kubeadm init命令就可以初始化master节点,然后使用--config指定配置文件

kubeadm init --config=init-config.yaml

如果安装过程一切正常,则屏幕上会输出Your Kubernetes control-plane has initialized successfully!

master

然后需要为kubectl配置证书,才能访问Master,对于非root用户,可以将admin.conf配置文件复制到HOME目录的.kube子目录下:

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

对于root用户可以设置环境变量完成kubectl的配置:

export KUBECONFIG=/etc/kubernetes/admin.conf

然后可以使用kubectl命令行工具对Kubernetes集群进行访问和操作了:

kubectl get nodes

在这里master节点已经正常工作了,但集群中没有可用的Worker Node,并且缺乏容器网络的配置。然后需要安装Worker Node,这里需要使用到kubeadm init命令运行完之后显示的token。

将新的Node加入集群

在Node节点中需要安装好kubeadmkubelet(不需要安装kubectl)。在安装好kubeadmkubelet之后使用kubeadm join命令加入集群,可以执行Master节点安装完成之后的命令:

kubeadm join 121.5.27.225:6443 --token abcdef.0123456789abcdef \
       --discovery-token-ca-cert-hash sha256:d16648f17cd9e84a894c91e807577afd7989eff1ab2023faf86a6f6f0d002703

也可以通过配置文件加入集群,首先需要导出kubeadm join命令的默认配置文件:

kubeadm config print join-defaults > join-config.yaml

然后这份配置文件大概需要修改为这个样子这样子:

apiVersion: kubeadm.k8s.io/v1beta3
caCertPath: /etc/kubernetes/pki/ca.crt
discovery:
  bootstrapToken:
    apiServerEndpoint: 121.5.27.225:6443
    token: abcdef.0123456789abcdef
    unsafeSkipCAVerification: true
  timeout: 5m0s
  tlsBootstrapToken: abcdef.0123456789abcdef
kind: JoinConfiguration
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  imagePullPolicy: IfNotPresent
  name: vm-0-5-ubuntu
  taints: null

然后使用配置文件加入集群:

kubeadm join --config=join-config.yaml

如果不出意外会看到如下的输出:

nodes

然后在Master节点使用kubectl可以看到节点的信息:

kubectl get nodes

这里有一个Master节点和一个Pod节点:

notready

安装网络插件

在这一步可以看到节点都还是NotReady的状态,这是因为还没有安装CNI网络插件:

[root@VM-16-4-centos ~]# kubectl get nodes
NAME           STATUS     ROLES                 AGE     VERSION
node           NotReady   control-plane,master   5m34s   v1.23.4
vm-0-5-ubuntu  NotReady   <none>                 5m22s   v1.23.4

网络插件可以有多种选择,我这里使用Flannel CNI插件,运行下面的命令可以一键安装:

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

在运行成功之后再次查看Node,其状态会变成Ready:

[root@VM-16-4-centos eastjun]# kubectl get nodes
NAME           STATUS   ROLES                 AGE   VERSION
node           Ready   control-plane,master   18m   v1.23.4
vm-0-5-ubuntu  Ready   <none>                 18m   v1.23.4

踩坑

1.kubeadm init时卡在[wait-control-plane]

这个问题是因为advertiseAddress要指定网卡上显示的IP。如果网卡上的IP和公网IP不一致,优先选择网卡上的IP,或者0.0.0.0

2. kubeadm join时出现net/http: request canceled while waiting for connection

出问题的原因是腾讯云的IP是用了NAT转换的,在执行kubeadm init之后它给出的就是内网那个IP,而这两台云服务器不是同一个地区的,在内网不能互通。解决方法是在advertiseAddress中指定内网的地址,而在controlPlaneEndpoint中指定公网的地址

3. kubeadm join时出现x509: certificate is valid for 192.160.0.1, 10.0.16.4, not 121.5.27.225

如果在Master节点初始化时使用controlPlaneEndpoint指定了正确的IP是不会出现这个问题的。上一个问题的另一种解决方案是在执行kubeadm join命令时指定apiserver-advertise-address,告诉Node一个正确的地址。但是Node在加入集群时发现这个地址和证书上的地址不一致,然后告诉你证书上的地址是xxx,而你连的是xxx。解决方法是在init的时候在配置文件中添加certSANs指定其他IP。

4. 都做好了,但是执行kubectl get nodes -o wide时显示的是内网IP

因为两台服务器是两个不同地区的实例,内网IP不能互通,所以必然是要将其设置为公网IP,不然在kubectl exec的时候会连不上。我需要在Node节点上添加一个虚拟网卡,IP设置为Node节点的公网IP,然后Node加入集群的时候才会使用公网IP:

sudo ifconfig eth0:1 Node节点的公网IP up

Referer

《Kubernetes权威指南》

k8s集群异地云服务器(公网)搭建