Skip to content

Kubeadm部署K8S

节点准备

所有主机均需操作

主机名配置

bash
$ hostnamectl set-hostname xxxx

主机名与IP地址的解析

bash
$ vi /etc/hosts

xxx.xxx.xxx.mm1 master1
xxx.xxx.xxx.nn1 node1
xxx.xxx.xxx.nn2 node2

防火墙配置

bash
# 关闭防火墙
$ systemctl stop firewalld
$ systemctl disbale firewalld

# 或
$ systemctl disbale --now firewalld

# 查看状态
$ firewall-cmd --state
not running

SELINUX配置

bash
$ sed -i s#SELINUX=enforcing#SELINUX=disabled# /etc/selinux/config
$ sestatus

时间同步

bash
# crontab -e
0 */1 * * * /usr/sbin/ntpdate time1.aliyun.com
# crontab -l

升级内核操作

其他系统需要自行解决

建议更新,有些软件要求高版本的内核,才能完全使用其功能

Linux 内核分两种:官方内核(通常是内核开发人员用)和各大 Linux 发行版内核(一般用户常用)

关于Linux内核版本号

bash
$ uname -r

如:

bash
3.10.0-1127.19.1.el7.x86_64

查询得到的版本号为:3.10.0-1127.19.1.el7.x86_64

第一个组数字:3, 主版本号

第二个组数字:10, 次版本号,当前为稳定版本,一般这个数字为偶数表示稳定,奇数表示在开发版本,通常这样的不做生产使用。

第三个组数字:0, 修订版本号

第四个组数字:1127.19.1,表示发型版本的补丁版本

el7:则表示我正在使用的内核是 RedHat / CentOS 系列发行版专用内核 ,centos7

x86_64:采用的是适用64位的CPU的操作系统

CentOS 允许使用 ELRepo,这是一个第三方仓库,可以将内核升级到最新版本

导入该源的秘钥

bash
$ rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

启用该源仓库

bash
$ rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm

查看有哪些内核版本可供安装

bash
$ yum --disablerepo="*" --enablerepo="elrepo-kernel" list available

安装主线版本,该版本比较激进,慎重选择

bash
$ yum --enablerepo=elrepo-kernel install kernel-ml -y

安装长期稳定版本,稳定可靠

bash
$ yum --enablerepo=elrepo-kernel install kernel-lt -y

设置 GRUB 默认的内核版本

设置grub2默认引导为0

bash
$ grub2-set-default 0

重新生成grub2引导文件

bash
$ grub2-mkconfig -o /boot/grub2/grub.cfg

更新后重启,使升级的内核生效

bash
$ reboot

配置内核路由转发及网桥过滤

添加网桥过滤机内核转发配置文件

bash
$ vi /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0

net.bridge.bridge-nf-call-ip6tables = 1:这个参数设置为 1,表示在 Linux 内核中启用 IPv6 的网络地址转换 (NAT) 功能,允许 iptables 调用 ip6tables 进行 IPv6 数据包的处理。

net.bridge.bridge-nf-call-iptables = 1:这个参数设置为 1,表示在 Linux 内核中启用 iptables 的网络地址转换 (NAT) 功能,允许 iptables 进行网络数据包的处理和转发。

net.ipv4.ip_forward = 1:这个参数设置为 1,表示启用 Linux 内核的 IP 转发功能,允许 Linux 主机作为一个路由器来转发 IP 数据包。

vm.swappiness = 0:这个参数设置为 0,表示将内核对交换空间(swap)的使用降到最低。较低的 swappiness 值将更多的内存保留在物理内存中,而不是将其交换到磁盘上的交换空间

加载br_netfilter模块

此步如果直接让配置生效,会有报错,所以需要加载相关模块

bash
$ modprobe br_netfilter

查看是否加载

bash
$ lsmod | grep br_netfilter
br_netfilter           22256  0 
bridge                151336  1 br_netfilter

配置生效

bash
$ sysctl -p /etc/sysctl.d/k8s.conf
# 或
$ sysctl --system

安装ipset及ipvsadm

不是必须,1.18+建议安装

在k8s中Service有两种代理模型,一种是基于iptables的,一种是基于ipvs,两者对比ipvs的性能要高,如果想要使用ipvs模型,需要手动载入ipvs模块

安装ipset及ipvsadm

bash
$ yum -y install ipset ipvsadm

配置ipvsadm模块加载方式

bash
$ cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
EOF

授权

bash
$ chmod 755 /etc/sysconfig/modules/ipvs.modules

执行脚本

bash
$ /etc/sysconfig/modules/ipvs.modules

验证ipvs模块

bash
$ lsmod | grep -e ip_vs -e nf_conntrack_ipv4

关闭swap分区

k8s 1.28+可以开启,但是初始化可能有问题

建议关闭

bash
# 永远关闭,需重启
$ vi /etc/fstab
# 注释掉swap行

# 临时关闭
$ swapoff -a

容器运行时准备

所有主机安装

k8s1.20+对容器运行时接口做了标准化,不管什么容器运行时都要能与k8s对接,docker通过cri-dockerd方式来对接的

Docker-ce

在线安装

加yum源

bash
$ wget http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

安装docker

bash
$ yum install -y docker-ce

离线安装

二进制安装

解压二进制包

bash
$ tar -xf docker-19.03.9.tgz
$ mv docker/* /usr/bin && rm -rf docker

systemd管理docker

bash
$ cat > /etc/systemd/system/docker.service << EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target
EOF
离线yum源安装

通过yum install -y --downloadonly方式下载后上传到离线服务器

或自建本地yum源,直接yum进行安装,安装参考 在线安装,只不是添加yum换成了配置本地yum源

启动

bash
$ systemctl enable --now docker

修改cgroup方式

创建或修改/etc/docker/daemod.json

bash
$ vi /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"]
}
bash
$ systemctl restart docker

cri-dockerd

Mirantis/cri-dockerd · 发行版

yum安装

bash
$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.14/cri-dockerd-0.3.14-3.el7.x86_64.rpm
$ yum install -y cri-dockerd-0.3.14-3.el7.x86_64.rpm

修改service文件

bash
$ vi /usr/lib/systemd/system/cri-docker.service
ExecStart=/usr/bin/cri-dockerd --pod-infra-container-image=registry.k8s.io/pause:3.9 --container-runtime-endpoint fd://
# ExecStart=/usr/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.k8s.io/pause:3.9

启动

bash
$ systemctl start cri-docker
$ systemctl enable cri-docker

启动后会产生socket:/var/run/cri-dockerd.sock,后续k8s集群就使用这个socket

Containerd 安装

containerd · Github:https://github.com/containerd/containerd/releases

下载cri-containerd

bash
# amd
$ wget https://github.com/containerd/containerd/releases/download/v1.7.22/cri-containerd-1.7.22-linux-amd64.tar.gz
# arm
$ wget https://github.com/containerd/containerd/releases/download/v1.7.22/cri-containerd-1.7.22-linux-arm64.tar.gz

解压

cri-containerd压缩包里所有相关资源都是按目录层级存放的,因此解压到/目录即可

bash
# amd
$ tar -xf cri-containerd-1.7.22-linux-amd64.tar.gz -C /
# arm
$ tar -xf cri-containerd-1.7.22-linux-arm64.tar.gz -C /

配置文件生成及修改

bash
$ mkdir /etc/containerd
$ containerd config default > /etc/containerd/config.toml
$ vi /etc/containerd/config.toml
sandbox_image = "registry.k8s.io/pause:3.8" # pause:3.8修改为pause:3.9

启动及设置开机自启

bash
$ systemctl enable --now containerd

版本验证

bash
$ containerd --version

runc准备

runc · GitHub:https://github.com/opencontainers/runc/releases

下载libseccomp

bash
$ wget https://github.com/opencontainers/runc/releases/download/v1.2.0-rc.3/libseccomp-2.5.5.tar.gz

解压

bash
$ tar -xf libseccomp-2.5.5.tar.gz

编译安装

bash
# 进入目录
$ cd libseccomp-2.5.5
# 安装编译依赖
$ yum install -y gperf
# 配置 编译安装
$ ./configure
$ make && make install
# 校验,一般会在/usr/local/lib/libseccomp.so
$ find / -name "libseccomp.so"

查看原来runc的位置

bash
$ which runc
/usr/local/sbin/runc

下载runc

bash
# amd
$ wget https://github.com/opencontainers/runc/releases/download/v1.2.0-rc.3/runc.amd64
# arm
$ wget https://github.com/opencontainers/runc/releases/download/v1.2.0-rc.3/runc.arm64

替换

bash
# 给予执行权限
$ chmod +x runc.amd64 # chmod +x runc.arm64
# 删除原有的runc
$ rm -rf `which runc`
# 替换
$ mv runc.amd64 /usr/local/sbin/runc # mv runc.arm64 /usr/local/sbin/runc

验证

bash
$ runc
# 会出现帮助信息
$ runc --version
# 会出现版本信息

k8S安装

软件及版本说明

软件版本安装位置作用
kubeadm1.29.0集群所有主机初始化集群、管理集群等
kubelet1.29.0集群所有主机接收api-server指令,对pod生命周期进行管理
kubectl1.29.0集群所有主机集群应用命令行管理工具

yum安装

kubernetes yum源准备

使用k8s社区yum源

bash
$ vi/etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key
# exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni

集群软件安装

所有节点均可以安装

bash
# 默认安装
$ yum install -y kubelet kubeadm kubectl

# 查看指定版本
$ yum list kubelet.x86_64 --showduplicates | sort -r
$ yum list kubeadm.x86_64 --showduplicates | sort -r
$ yum list kubectl.x86_64 --showduplicates | sort -r

# 安装指定版本
$ yum install -y kubelet-1.29.0-150500.1.1 kubeadm-1.29.0-150500.1.1 kubectl-1.29.0-150500.1.1

配置kubelet

为了实线docker使用的cgroupdriver与kubelet使用的cgroup的一致性,建议修改如下内容

bash
$ vi /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

高版本,对于DEB类包管理系统位置可能在/etc/default/kubelet

设置kubectl为开启自启即可,这里还没有生成配置文件,待集群初始化后再启动

bash
$ systemctl enable kubelet

集群镜像准备

bash
$ kubeadm config images list
$ kubeadm config images list --kubernetes-version=v1.29.0

registry.k8s.io/kube-apiserver:v1.29.0
registry.k8s.io/kube-controller-manager:v1.29.0
registry.k8s.io/kube-scheduler:v1.29.0
registry.k8s.io/kube-proxy:v1.29.0
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.10-0
registry.k8s.io/coredns/coredns:v1.11.1

# 下载镜像
$ kubeadm config images pull
# 如果是其他容器运行时 或 有多个容器运行时 时需要指定socket
$ kubeadm config images pull --cri-socket unix:///var/run/cri-dockerd.sock
# 指定源 
$ kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers

集群初始化

导出默认配置文件【这里作为记录,和下面的kubeadm init是两种方式】

bash
$ kubeadm config print init-defaults > kubeadm-config.yaml
$ vi kubeadm-config.yaml
# 调整:
# localAPIEndpoint:
# 	advertiseAddress: master1节点IP
# 	bindPort: 6443
# nodeRegistration:
# 	criSocket: 容器运行时socket
# 	name: master1节点名称
# 	taints: 是否增加污点,不增加忽略即可
# imageRepository: 仓库地址
# kubernetesVersion: k8s版本
# networking
# 	dnsDomain: 默认的域名
# 	serviceSubnet: 10.96.0.0/12 默认的
# 	podSubnet: Pod所在网段,10.244.0.0/16
# cgroupDriver: systemd

初始化

bash
$ kubeadm init \
--config kubeadm-config.yaml \
--upload-certs  \
--v=9

建议

bash
$ kubeadm init \
--config kubeadm-config.yaml \
--upload-certs

--config:这个参数指定了一个配置文件,该文件包含了 kubeadm init 所需的所有配置信息。这个文件可以定义 API 服务器的地址、Pod 网络插件的配置、使用的镜像仓库等。使用配置文件可以确保每次初始化集群时都使用相同的配置,从而更容易地复制和管理集群。

--upload-certs:这个参数告诉 kubeadm 在初始化过程中生成的证书将被上传到 kubeadm-certs Secret 中,在集群的 kube-system 命名空间中。这允许在之后加入控制平面节点或工作节点时,自动下载并使用这些证书,而无需手动复制它们。这是一个方便的选项,因为它简化了添加新节点到集群的过程。

--v=9:这个参数设置了日志的详细级别。v=9 表示非常详细的日志输出,包括大量的调试信息。这对于诊断问题或了解 kubeadm 在初始化过程中执行的具体操作非常有用。然而,在日常使用中,你可能不需要这么详细的日志,因为它会产生大量的输出。

containerd可忽略--cri-socket

bash
$ kubeadm init \
  --kubernetes-version=v1.29.0 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.10.160

ontainerd写上--cri-socket

bash
$ kubeadm init \
  --kubernetes-version=v1.29.0 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.10.160 \
  --cri-socket unix:///var/run/containerd/containerd.sock

使用docker作为容器运行时,写上--cri-socket

bash
$ kubeadm init \
  --kubernetes-version=v1.29.0 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.10.160 \
  --cri-socket unix:///var/run/cri-dockerd.sock

--pod-network-cidr=10.244.0.0/16:方便在部署网络插件的时候的网段与这里保持一致

其他参考

bash
$ kubeadm init \
  --apiserver-advertise-address=192.168.10.160 \
  --apiserver-bind-port=6443 \
  --kubernetes-version=v1.29.0 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=192.168.3.0/24 \
  --service-dns-domain=cluster.local \
  --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers \
  --ignore-preflight-errors=swap \
  --cri-socket=unix:///var/run/cri-dockerd.sock

--apiserver-advertise-address:这个参数指定了 Kubernetes API 服务器的地址,即 API 服务器对外暴露的地址。这个地址应该是集群中所有节点都能访问到的地址,通常是一个公网 IP 或者内网中的某个节点的 IP。

--apiserver-bind-port:这个参数指定了 Kubernetes API 服务器的绑定端口,默认是 6443。这个端口用于 API 服务器的内部通信和外部访问。

--kubernetes-version:这个参数指定了要安装的 Kubernetes 的版本,这里是 v1.29.0。请确保选择的版本与你的操作系统和其他组件兼容。

--pod-network-cidr:这个参数指定了 Pod 网络的 CIDR 范围。在 Kubernetes 集群中,Pod 之间的通信需要通过 Pod 网络进行,而这个参数就是用来定义 Pod 网络的 IP 地址范围。【注意此项需要与网络插件内的地址一致】

--service-cidr:这个参数指定了 Service 网络的 CIDR 范围。Service 是 Kubernetes 中的一个抽象,它定义了一个逻辑集合的 Pods 以及访问这些 Pods 的策略。这个范围用于分配 Service 的虚拟 IP 地址。

--service-dns-domain:这个参数指定了集群内 DNS 服务的域名后缀。Kubernetes 集群中的 Service 可以通过 <service-name>.<namespace>.svc.<cluster-domain> 的形式进行 DNS 解析。

--image-repository:这个参数指定了拉取 Kubernetes 镜像时使用的镜像仓库地址。由于 Google 的官方镜像仓库可能在国内访问较慢或不稳定,这里使用了阿里云提供的镜像仓库。

--ignore-preflight-errors:这个参数用于忽略初始化前的检查错误,忽略关于 swap 分区(交换空间)的检查。默认情况下,kubeadm 会检查系统中是否启用了 swap,因为 Kubernetes 推荐禁用 swap 以提高集群的稳定性。如果确定需要启用 swap,可以使用这个参数来忽略这个检查。

--cri-socket:这个参数指定了容器运行时的 socket 路径。在 Kubernetes 中,容器运行时负责容器的创建和管理。请注意,从 Kubernetes 1.20 开始,kubeadm 默认使用 containerd 作为容器运行时,因此如果使用的是 containerd不需要设置这个参数

输出样例

bash
...

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 192.168.10.160:6443 --token abcdef.0123456789abcdef \
	--discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890

参见输出内容,执行如下脚本,准备配置文件,有配置文件kubectl才能访问到k8s集群

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

此时使用以下命令,就能看到节点了

bash
$ kubectl get nodes

此时是NotReady的状态,部署网络插件后就会Ready

添加节点

添加Master节点

同步证书等

bash
$ scp -r /etc/kubernetes/pki/ root@master2:/etc/kubernetes/
$ scp -r /etc/kubernetes/pki/ root@master3:/etc/kubernetes/

删除不需要的证书密钥

bash
$ cd /etc/kubernetes/pki/
$ rm -rf apiserver*
$ rm -rf etcd/peer.*
$ rm -rf etcd/server.*

使用containerd容器运行时可以不指定socket

bash
$ kubeadm join 192.168.10.160:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890 \
  --control-plane

使用非containerd容器运行时需要指定容器运行时的socket

bash
$ kubeadm join 192.168.10.160:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890  \
  --control-plane \
  --cri-socket unix:///var/run/cri-dockerd.sock

低一点的版本可能需要增加--certificate-key配置,如果需要且初始化的时候没有输出/没有记录,可以考虑重新生成

$ kubeadm join 192.168.10.160:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890 \
  --control-plane \
  --certificate-key 107397fb9f4b5ee3c6b2656282ced2b9846cff21738a89e29a9ef04a3c50652b \

添加Worker节点

使用containerd容器运行时可以不指定socket

bash
$ kubeadm join 192.168.10.160:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890

使用非containerd容器运行时需要指定容器运行时的socket

bash
$ kubeadm join 192.168.10.160:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:abcdefghijklmnopqrstuvwxyz12345678901234567891234567891234567890 \
  --cri-socket unix:///var/run/cri-dockerd.sock

部署网络插件

calico

k8s节点超过10个推荐使用

Calico · GitHub:https://github.com/projectcalico/calico

Kubernetes 上的 Calico:https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart

安装

bash
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/tigera-operator.yaml

查看是否成功

bash
$ kubectl get pods -n tigera-operator

配置calico

bash
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/custom-resources.yaml

注意这个配置不要直接使用,调整custom-resources.yaml资源清单的spec.calicoNetwork.blockSize.cidr与初始化时指定的--pod-network-cidr一致即可

yaml
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    ipPools:
    - blockSize: 26
      cidr: 10.244.0.0/16
      encapsulation: VXLANCrossSubnet
      natOutgoing: Enabled
      nodeSelector: all()
---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
  name: default
spec: {}
bash
$ kubectl create -f custom-resources.yaml

成功后会创建新的命名空间calico-system,相关容器运行好了之后,查看节点就正常了

bash
$ kubectl get nodes
$ kubectl get cs
$ kubectl get svc -n kube-system
# 根据查询的dns ip尝试域名解析
$ dig -t a www.baidu.com @xxx.xxx.xxx.xxx

Flannel

Flannel · GitHub:https://github.com/flannel-io/flannel

适合小规模的k8s集群

安装

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

建议:

下载

bash
$ wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

调整ConfigMap:kube-flannel-cfg的net-conf.json的配置

json
net-conf.json: |
{
  "Network": "10.244.0.0/16",
  "EnableNFTables": false,
  "Backend": {
    "Type": "vxlan"
  }
}

Network调整成初始化时指定的--pod-network-cidr的值即可

在应用

bash
$ kubectl apply -f kube-flannel.yml

删除时网卡还在可以在每个节点:

bash
$ ip link delete flannel.1

查看

bash
$ ip link show

查看网络类型

bash
$ ethtool -i flannel.1

Cilium

Cilium · GitHub:https://github.com/cilium/cilium

多集群推荐,需要关注他对系统的要求、内核的要求等:系统要求 · Cilium 1.16.1