环境准备
三台机都是采用centos7的操作系统,内核版本号是3.10.0-693.el7.x86_64
角色 |
IP |
kubernetes版本 |
master |
192.168.248.130 |
v1.24.3 |
node1 |
192.168.248.131 |
v1.24.3 |
node2 |
192.168.248.132 |
v1.24.3 |
由于K8S从1.24版本之后,开始弃用了docker。改用了containerd ,containerd是容器虚拟化技术,从docker中剥离出来,形成开放容器接口(OCI)标准的一部分。 containerd与docker相兼容,相比docker轻量很多,目前较为成熟。
主机间做信任
在master节点上生成秘钥文件,并把它上传到其他两台机上,做好免密登录,方便后续的操作。
执行ssh-copy-id root@192.168.248.129
命令实现免密登录,其他两台做同样的操作。
安装ansible工具
ansible
工具主要为了后续多台机器执行同样的命令,从而提供效率用的。安装方式也很简单,通过yum源安装即可。执行如下两条命令:
[root@master ~]# yum install epel-release -y [root@master ~]# yum -y install ansible
配置/etc/ansible/hosts
,该文件是存放要操作的主机,把上述三台机器加入一个组名字为k8s
,如下:
[k8s] 192.168.248.128 192.168.248.129 192.168.248.130
通过执行ansible命令测试连通性,如下图:
-m:是指定ansible的模块,ping是ansible其中一个模块,该模块主要是测试主机的连通性。
k8s:刚定义的组名
升级内核版本
检查当前 CentOS
系统内核版本 ,执行如下命令查看:
[root@localhost ~]# uname -sr Linux 3.10.0-1160.el7.x86_64
检查发现当前内核版本是3.10,
使用elrepo源升级内核
配置elrepo源,执行如下命令
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
查看最新版内核
执行如下命令查看最新的内核版本
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
内核版本说明:
- kernel-ml #主线版本,比较新
- kernel-lt #长期支持版本,比较旧
安装最新的内核版本
执行如下命令安装主线版本:
yum --enablerepo=elrepo-kernel install kernel-ml -y
设置系统默认内核
查看系统上的所有内核版本:
[root@localhost ~]# awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg 0 : CentOS Linux (5.18.14-1.el7.elrepo.x86_64) 7 (Core) 1 : CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core) 2 : CentOS Linux (0-rescue-9dad18ee9dde4729b1c6df225ce69c4a) 7 (Core) [root@localhost ~]#
设置默认内核为我们刚才升级的内核版本
cp /etc/default/grub /etc/default/grub-bak #备份 grub2-set-default 0 #设置默认内核版本 vi /etc/default/grub GRUB_DEFAULT=saved修改为GRUB_DEFAULT=0
重新创建内核配置
grub2-mkconfig -o /boot/grub2/grub.cfg
查看默认内核
grubby --default-kernel #/boot/vmlinuz-5.18.14-1.el7.elrepo.x86_64 grub2-editenv list #saved_entry=0
更新软件包并重启
yum makecache reboot
初始化
安装K8S之前需要对每台机系统进行一些设置,比如 关闭防火墙,selinux,swap,设置主机名,ip解析,时间同步 .
关闭防火墙
通过ansible
把三台机器的防火墙关闭,并设置开机不启动。执行如命令:
ansible k8s -m shell -a "systemctl stop ss" ansible k8s -m shell -a "systemctl disable firewalld "
关闭selinux
通过ansible
把三台机器的selinux永久关闭,执行如命令:
ansible k8s -m shell -a "sed -i 's/enforcing/disabled/' /etc/selinux/config"
关闭swap
执行swapoff -a
临时关闭,通过修改/etc/fstab文件实现永久关闭。执行如下命令
ansible k8s -m shell -a "sed -ri 's/.*swap.*/#&/' /etc/fstab"
修改主机名
分别对三台主机进行主机名的修改,执行如下的命令
# 根据规划设置主机名【master节点上操作】 hostnamectl set-hostname master # 根据规划设置主机名【node1节点操作】 hostnamectl set-hostname node1 # 根据规划设置主机名【node2节点操作】 hostnamectl set-hostname node2
修改hosts文件
在master节点上修改hosts文件,根据规划进行修改,如下:
192.168.248.130 master1 192.168.248.131 node2 192.168.248.132 node1
转发 IPv4 并让 iptables 看到桥接流量
通过运行 lsmod | grep br_netfilter 来验证 br_netfilter 模块是否已加载。
若要显式加载此模块,请运行 sudo modprobe br_netfilter。
为了让 Linux 节点的 iptables 能够正确查看桥接流量,请确认 sysctl 配置中的 net.bridge.bridge-nf-call-iptables 设置为 1。例如:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # 设置所需的 sysctl 参数,参数在重新启动后保持不变 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # 应用 sysctl 参数而不重新启动 sudo sysctl --system
ansible k8s -m copy -a "src=/etc/sysctl.d/k8s.conf dest=/etc/sysctl.d/k8s.conf"
执行 sysctl --system
命令使配置生效:
ansible k8s -m shell -a "sysctl --system"
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe br_netfilter
配置 ipvs模式
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 chmod 755 /etc/sysconfig/modules/ipvs.modules bash /etc/sysconfig/modules/ipvs.modules lsmod | grep -e ip_vs -e nf_conntrack
配置时间同步
使用yum命令安装ntpdate
,如下:
ansible k8s -m shell -a "yum install ntpdate -y"
配置NTP网络时间同步服务器地址为 ntp.aliyun.com
,执行如下命令:
ansible k8s -m shell -a "ntpdate ntp.aliyun.com"
安装containerd
下载安装包
在每台机器上都要部署containerd。执行如下命令下载最新containerd,如下:
wget https://download.fastgit.org/containerd/containerd/releases/download/v1.6.6/cri-containerd-cni-1.6.6-linux-amd64.tar.gz
如果出现无法建立 SSL 连接 加上--no-check-certificate
解压并安装
执行下面的命令解压containerd
安装包
tar -C / -zxvf cri-containerd-cni-1.6.6-linux-amd64.tar.gz
配置环境变量
配置环境变量,编辑用户目录下的bashrc
文件添加如下内容:
export PATH=$PATH:/usr/local/bin:/usr/local/sbin
并执行如下命令使环境变量立即生效:
source ~/.bashrc
启动并设置开机启动
执行如下命令启动containerd
,并设置开机启动
systemctl start containerd systemctl enable containerd
修改配置文件
执行如下命令先生成默认的配置文件,在此基础上进行相应的修改
mkdir /etc/containerd containerd config default > /etc/containerd/config.toml
- 修改SystemdCgroup的值为true
- 修改endpoint的值为https://registry.cn-hangzhou.aliyuncs.com
- 修改sandbox_image的值为registry.aliyuncs.com/google_containers/pause:3.7
验证安装是否成功
执行如下命令查看版本号,出现如下信息表明安装成功。
[root@master1 ~]# ctr version Client: Version: v1.6.6 Revision: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1 Go version: go1.17.11 Server: Version: v1.6.6 Revision: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1 UUID: c205638a-6c08-43a8-81a4-b15f97ef5cdc
通过拉取镜像和启动镜像测试containerd
是否安装成功。执行如下命令拉取镜像并创建容器:
ctr i pull docker.io/library/nginx:alpine #拉取容器 ctr c create --net-host docker.io/library/nginx:alpine nginx #创建容器 ctr task start -d nginx
如果启动容器出现如下报错,是由于 缺少 runc
并升级libseccomp
,libseccomp
需要高于2.4
版本。
containerd
在v1.6.4
版本以后使用v1.1.2
的runc
和v1.1.1
的cni
。
ctr: failed to create shim task: OCI runtime create failed: unable to retrieve OCI runtime error (open /run/containerd/io.containerd.runtime.v2.task/default/nginx/log.json: no such file or directory): fork/exec /
下载链接,下载之后,执行如下命令安装并查看版本号:
install -m 755 runc.amd64 /usr/local/sbin/runc runc -v
执行如下命令升级libseccomp
:
rpm -qa | grep libseccomp #查询原来的版本 rpm -e libseccomp-2.3.1-4.el7.x86_64 --nodeps #卸载原来的版本 #下载高版本的 wget http://rpmfind.net/linux/centos/8-stream/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm rpm -ivh libseccomp-2.5.1-1.el8.x86_64.rpm #安装
安装kubernetes
添加kubernetes源
在master节点上添加k8s软件源,并分发到其他两台机器上。在/etc/yum.repos.d/
目录下新增kubernetes.repo
。内容如下:
[kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
把kubernetes.repo文件分发到其他两台机器上,执行如下命令:
ansible k8s -m copy -a "src=/etc/yum.repos.d/kubernetes.repo dest=/etc/yum.repos.d/kubernetes.repo"
查询kubeadm的版本
[root@master yum.repos.d]# yum list kubeadm 可安装的软件包 kubeadm.x86_64 1.24.3 kubernetes
安装
在master节点下执行如下命令安装相应的软件:
yum install -y kubelet-1.24.3 kubeadm-1.24.3 kubectl-1.24.3
生成默认配置并修改相应的参数
通过如下命名生成一个默认的配置文件:
kubeadm config print init-defaults > kubeadm-init.yaml
根据自己的环境修改对应的参数:
apiVersion: kubeadm.k8s.io/v1beta3 bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.248.130 #master节点IP bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock #containerd容器路径 imagePullPolicy: IfNotPresent name: master1 taints: null --- apiServer: timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta3 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controllerManager: {} dns: {} etcd: local: dataDir: /var/lib/etcd imageRepository: registry.aliyuncs.com/google_containers #阿里云容器源地址 kind: ClusterConfiguration kubernetesVersion: 1.24.3 networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 #pod的IP网段 serviceSubnet: 10.96.0.0/12 scheduler: {}
初始化
执行如下命令进行初始化:
# kubeadm config images list --config kubeadm-init.yaml #根据配置文件列出镜像 kubeadm init --config=kubeadm-init.yaml --v=6
--config:指定根据那个配置文件进行初始
--v:指定日志级别,越高越详细
初始化成功后,会出现以下信息
...省略... 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.248.130:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:e9e29c804f92193928f37ca157b73a7ad77e7929314db98855b3ba6e2ce2273d
按照初始化成功提示信息,做如下操作:
mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config
接下来执行kubectl
就可以看到node
了
[root@master1 .kube]# kubectl get node NAME STATUS ROLES AGE VERSION master1 Ready control-plane 55m v1.24.3
查看k8s各部件启动情况,执行如下命令:
kubectl get pod --all-namespaces -o wide
通过观察发现coredns
部件没有运行成功,通过如下命令查看原因:
describe pod coredns-74586cf9b6-c2ddb --namespace=kube-system
根据官方的解析是没有部署CNI,coredns是不会启动的。
node节点配置
node节点安装kubeadm
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF
安装相关组件
yum install -y kubelet-1.24.3 kubeadm-1.24.3 --disableexcludes=kubernetes
添加join命令
kubeadm join 192.168.248.130:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:e9e29c804f92193928f37ca157b73a7ad77e7929314db98855b3ba6e2ce2273d
如果我们后续需要添加node节点时,可以到master节点执行下面的命令获取token
相关信息
[root@master1 ~]# kubeadm token create --print-join-command kubeadm join 192.168.248.130:6443 --token ydqnz1.6b0q5ntkvos9z2ir --discovery-token-ca-cert-hash sha256:c0b6f7fb38c7c9764084beb7dd26c9acef027ae6b7d2673572b4c2e3a0dfd6cb
如果添加某台节点异常了,修改后可以执行 kubeadm reset
的命令,然后在重新join加入
网络配置
coredns还没启动,因为还没有安装网络插件,接下来安装网络插件,可以在该文档中选择我们自己的网络插件,这里安装flannel
wget http://down.i4t.com/k8s1.24/kube-flannel.yml
根据需求修改网卡配置,我这里ens33为主的:
containers: - name: kube-flannel image: quay.io/coreos/flannel:v0.12.0-amd64 command: - /opt/bin/flanneld args: - --ip-masq - --kube-subnet-mgr - --iface=ens33 # 如果是多网卡的话,指定内网网卡的名称
在kubeadm.yaml文件中设置了podSubnet网段,同时在flannel中网段也要设置相同的。 (我这里默认就是相同的配置)
执行部署
kubectl apply -f kube-flannel.yml
CNI插件问题
默认情况下containerd也会有一个cni插件,但是我们已经安装Flannel了,我们需要使用Flannel的cni插件,需要将containerd里面的cni配置文件进行注释,否则2个配置会产生冲突 。
因为如果这个目录中有多个 cni 配置文件,kubelet 将会使用按文件名的字典顺序排列的第一个作为配置文件,所以前面默认选择使用的是 containerd-net 这个插件。
mv /etc/cni/net.d/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist.bak systemctl restart containerd kubelet
接下来我们所有的pod都可以正常运行了
如果flannel插件启动失败,请检查kubelet的配置文件是否配置正确,如下:
#/etc/sysconfig/kubelet KUBELET_EXTRA_ARGS="--container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
配置好之后,需要重启kubelet和containerd的服务:
systemctl restart containerd kubelet
验证
验证dns是否正常能解析和pod之间。这里新建一个测试的yaml文件,内容如下:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:alpine name: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nginx type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30001 --- apiVersion: v1 kind: Pod metadata: name: busybox namespace: default spec: containers: - name: busybox image: abcdocker9/centos:v1 command: - sleep - "3600" imagePullPolicy: IfNotPresent restartPolicy: Always
执行下面命令,创建pod
kubectl apply -f test.yaml
使用nslookup查看是否能返回地址
[root@master1 ~]# kubectl exec -it busybox -- nslookup kubernetes Server: 10.96.0.10 Address: 10.96.0.10#53 Name: kubernetes.default.svc.cluster.local Address: 10.96.0.1 [root@master1 ~]#
测试nginx svc以及Pod内部网络通信是否正常 ,分别在三台机器上进行下面操作
ping 10.104.115.26 #nginx svc ip ping 10.244.1.2 #podIP
如果成功ping同说明node跟pod的网络已经打通了。否则检查kube-proxy
的模式是否正确。
nodes/集群内部 无法访问ClusterIP
默认情况下,我们部署的kube-proxy
通过查看日志,能看到如下信息:Flag proxy-mode="" unknown,assuming iptables proxy
原因分析:
并没有正确使用ipvs模式
解决方法:
1、 在master
上修改kube-proxy
的配置文件,添加mode
为ipvs
。
[root@master1 ~]# kubectl edit cm kube-proxy -n kube-system ipvs: excludeCIDRs: null minSyncPeriod: 0s scheduler: "" strictARP: false syncPeriod: 30s kind: KubeProxyConfiguration metricsBindAddress: 127.0.0.1:10249 mode: "ipvs"
删除原来的POD,会自动重启kube-proxy 的pod
[root@k8s-master ~]# kubectl get pod -n kube-system | grep kube-proxy |awk '{system("kubectl delete pod "$1" -n kube-system")}'
扩展
在使用过程中发现kubectl 命令不能补全,使用起来很不方便。为了提高使用kubectl命令工具的便捷性,介绍一下kubectl命令补全工具的安装。
1、安装bash-completion:
yum install -y bash-completion source /usr/share/bash-completion/bash_completion
2、 应用kubectl的completion到系统环境:
echo "source <(kubectl completion bash)" >> ~/.bashrc
3、效果展示
问题记录
nodes/集群内部 无法访问ClusterIp
k8s节点部署成功后,通过在node节点上ping ClusterIp,发现不同,检查所有的部件都正常运行。
默认情况下,我们部署的kube-proxy通过查看日志,能看到如下信息:Flag proxy-mode="" unknown,assuming iptables proxy
原因分析:
并没有正确使用ipvs模式
解决方法
在master上修改kube-proxy的配置文件,添加mode 为ipvs。
[root@master1 ~]# kubectl edit cm kube-proxy -n kube-system ipvs: excludeCIDRs: null minSyncPeriod: 0s scheduler: "" strictARP: false syncPeriod: 30s kind: KubeProxyConfiguration metricsBindAddress: 127.0.0.1:10249 mode: "ipvs"
删除原来的POD,会自动重启kube-proxy 的pod
执行crictl images有错误警告
WARN[0000] image connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead. ERRO[0000] unable to determine image API version: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory"
解决方法
cat <<EOF> /etc/crictl.yaml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOF