云原生探索系列(四):centos7+kubeadm安装k8s-1.21 详细教程

734 阅读20分钟

前言

前端时间一直再看Go基础语法,有点头晕目眩,缓一缓,先安装k8s,为k8s学习搭建基础环境。

环境介绍

采用VMware Fusion+centos7虚拟机,Docker作为容器运行环境,版本20.10.24,kubernetes版本为1.21。

机器名ipcpu和内存
k8s-master10.0.0.1002核4g
k8s-node0110.0.0.1012核4g
k8s-node0210.0.0.1022核4g

搭建虚拟机的过程就不说了,比较简单,网上很多教程。下面内容都是基于以及搭建好centos7虚拟环境来进行的。

修改主机名称

分别设置三台虚拟机的主机名称:

sudo hostnamectl set-hostname 新的主机名

新的主机名分别是k8s-master、k8s-node01、k8s-node02。
检查是否修改成功,执行如下命令:

hostnamectl status

配置IP

分别给三台机器设置固定ip,执行如下命令:

vim /etc/sysconfig/network-scripts/ifcfg-eth0

修改为自己指定IP即可。
执行下面命令,重启网络生效:

systemctl restart network

配置hosts解析

分别在三台机器上执行如下命令:

cat >> /etc/hosts << EOF
10.0.0.100 k8s-master
10.0.0.101 k8s-node01
10.0.0.102 k8s-node02
EOF

执行如下命令,验证是否可以正常解析:

ping -c 4 k8s-master
ping -c 4 k8s-node01
ping -c 4 k8s-node02

在 ping 命令中, -c 选项用于指定要发送的 ICMP 报文数量,即要发起的 ping 请求次数。在 -c 后面可以跟一个数字,表示发送 ICMP 报文的次数。 所以, ping -c 4 k8s-node01 中的 -c 4 意思是发起对主机 k8s-node01 的 ICMP ping 请求,并且指定发送 4 个 ICMP 报文,即发送 4 次 ping 请求。这样可以让 ping 命令发送多次请求以测试主机的连通性和响应时间。
如果解析正常,会输出如下内容:

PING k8s-node02 (10.0.0.102) 56(84) bytes of data.
64 bytes from k8s-node02 (10.0.0.102): icmp_seq=1 ttl=64 time=1.54 ms
64 bytes from k8s-node02 (10.0.0.102): icmp_seq=2 ttl=64 time=1.50 ms
64 bytes from k8s-node02 (10.0.0.102): icmp_seq=3 ttl=64 time=1.13 ms
64 bytes from k8s-node02 (10.0.0.102): icmp_seq=4 ttl=64 time=1.55 ms

--- k8s-node02 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms

当然,还有另外一种验证方式,执行如下命令:

getent hosts k8s-master
getent hosts k8s-node01
getent hosts k8s-node02

解析成功的话会输出如下内容:

10.0.0.100      k8s-master
10.0.0.101      k8s-node01
10.0.0.102      k8s-node02

关闭防火墙

CentOS 7 默认启动了防火墙服务 (firewalld.service),而Kubernetes的Master与工作Node之间会有大量的网络通信。安全的做法是在防火墙上配置各组件需要相互通信的端口号,这里我们先采用简单办法,关闭防火墙,执行如下命令

systemctl stop firewalld && systemctl disable firewalld

关闭SELinux

分别在三台机器上执行如下命令:

vim /etc/sysconfig/selinux

将SELINUX=enforcing修改为 SELINUX=disabled,让容器可以读取主机文件系统。
修改后,查看状态进行验证:

getenforce

关闭系统交换分区

kubeadm需要关闭Linux的swap系统交换区,执行如下命令:

swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab

输入如下命令,验证是否已关闭:

free

安装docker

执行如下命令,下载docker源:

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

执行如下命令,列出docker所有版本:

yum list docker-ce --showduplicates

执行如下命令,安装指定docker版本:

yum install docker-ce-20.10.24 docker-ce-cli-20.10.24 -y

启动docker并设置开机启动:

systemctl enable docker && systemctl start docker

执行如下命令,配置国内源优化下载速度:

cat > /etc/docker/daemon.json << EOF
{
   "registry-mirrors": ["https://mw86j9k8.mirror.aliyuncs.com"]
}
EOF

执行如下命令,设置docker驱动为systemd,保持与k8s一致:

vim /etc/docker/daemon.json

增加如下内容:

{
   "registry-mirrors": ["https://mw86j9k8.mirror.aliyuncs.com"],
   "exec-opts": ["native.cgroupdriver=systemd"]
}

最后,执行如下命令重新启动:

systemctl restart docker

可以输入如下命令,验证docker是否安装成功:

docker info

配置yum源

分别在三台机器上,执行如下命令:

cat > /etc/yum.repos.d/kubernetes.repo << EOF
[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
EOF

执行如下命令,清除更新yum缓存:

yum clean all
yum -y makecache

安装kubeadm、kubelet和kubectl

执行如下命令,查看可安装版本;

yum list kubelet --showduplicates | sort -r

执行如下命令安装kubeadm、kubelet和kubectl:

yum install -y kubelet-1.21.0 kubeadm-1.21.0 kubectl-1.21.0

kubeadm将使用kubelet服务以容器方式部署和启动Kubernetes的主要服务,所以需要先启动kubelet服务。运行systemctl start命令启动kubelet 服务,并设置为开机自启动:

systemctl start kubelet && systemctl enable kubelet

输入如下命令,查看版本:

kubelet --version

为了加快kubeadm创建集群的过程,可以预先将所需镜像下载完 成。可以通过如下命令查看镜像列表

kubeadm config images list

执行后,会输出如下内容:

k8s.gcr.io/kube-apiserver:v1.19.16
k8s.gcr.io/kube-controller-manager:v1.19.16
k8s.gcr.io/kube-scheduler:v1.19.16
k8s.gcr.io/kube-proxy:v1.19.16
k8s.gcr.io/pause:3.2
k8s.gcr.io/etcd:3.4.9-1
k8s.gcr.io/coredns:1.7.0

可以看到我们需要下载这些镜像,未下载之前,输入docker images是没有这些镜像的

在 CentOS 上安装 Kubernetes 的过程中,配置 /etc/sysctl.d/k8s.conf 文件并设置以下内核参数是一个重要的步骤。具体来说,这些配置项的作用如下:

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

iptables

三台机器分别执行如下命令:

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

加载配置 :使配置生效,可以通过以下命令立即应用配置:

sysctl --system

验证配置 :确保配置已成功应用,可以通过以下命令检查:

sysctl net.bridge.bridge-nf-call-ip6tables
sysctl net.bridge.bridge-nf-call-iptables

应该看到输出为 1 ,表示配置已生效。

  1. net.bridge.bridge-nf-call-ip6tables = 1

    • 作用 :这个设置确保了 IPv6 流量通过 iptables 进行过滤。当流量经过 Linux 内核的桥接接口时,这个参数指示内核调用 ip6tables 进行处理。
    • 原因 :尽管 Kubernetes 默认使用的是 IPv4,但在某些场景下(如双栈网络或未来可能的 IPv6 支持),需要确保内核能够正确处理 IPv6 流量。
  2. net.bridge.bridge-nf-call-iptables = 1

    • 作用 :这个设置确保了 IPv4 流量通过 iptables 进行过滤。当流量经过 Linux 内核的桥接接口时,这个参数指示内核调用 iptables 进行处理。
    • 原因 :Kubernetes 网络插件(如 Flannel、Calico 等)通常依赖于 iptables 规则来管理网络流量和隔离。因此,需要确保桥接流量能够被 iptables 处理。

为什么需要这些配置

Kubernetes 集群中的网络组件(例如 kube-proxy 和网络插件)大量依赖 iptables 规则来实现服务发现、负载均衡、Pod 网络通信等功能。特别是在使用基于桥接的网络插件时,如果没有这两个配置项,桥接流量将不会被 iptables 处理,从而导致网络策略和安全规则无法生效。这可能会导致一些网络问题,例如:

  • Pod 之间的通信问题
  • 服务无法访问
  • 网络策略不生效 配置这些内核参数是为了确保 Kubernetes 集群中的网络流量能够正确地通过 iptables 进行处理,以确保网络策略和安全规则能够正常生效。这是 Kubernetes 安装过程中确保网络正常运行的重要步骤之一。

修改kubeadm的默认配置,国外源变为国内源

执行如下命令,获取默认配置:

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

然后,复制一份:

cp init.default.yaml init-config.yaml

修改init-config.yaml配置,修改镜像仓库地址,默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。找到imageRepository,

imageRepository: registry.aliyuncs.com/google_containers

然后,我们执行如下命令下载镜像:

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

等待下载完成,再次输入docker images查看,

REPOSITORY                                                        TAG        IMAGE ID       CREATED       SIZE
registry.aliyuncs.com/google_containers/kube-apiserver            v1.21.0    4d217480042e   3 years ago   126MB
registry.aliyuncs.com/google_containers/kube-proxy                v1.21.0    38ddd85fe90e   3 years ago   122MB
registry.aliyuncs.com/google_containers/kube-scheduler            v1.21.0    62ad3129eca8   3 years ago   50.6MB
registry.aliyuncs.com/google_containers/kube-controller-manager   v1.21.0    09708983cc37   3 years ago   120MB
registry.aliyuncs.com/google_containers/pause                     3.4.1      0f8457a4c2ec   3 years ago   683kB
registry.aliyuncs.com/google_containers/etcd                      3.4.13-0   0369cf4303ff   3 years ago   253MB

这一步可能会报如下错误:

failed to pull image "registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0": output: Error response from daemon: pull access denied for registry.aliyuncs.com/google_containers/coredns/coredns, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

可以输入下面命令进行解决:

docker pull coredns/coredns:1.8.0
docker tag coredns/coredns:1.8.0 registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0
docker rmi -f coredns/coredns:1.8.0

部署kubernetes Master节点

执行如下命令:

kubeadm init \
  --apiserver-advertise-address=10.0.0.100 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.21.0 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16 \
  --ignore-preflight-errors=all

执行成功后,注意最后,会生成集群加入命令,如下:

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

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.0.100:6443 --token ijffbx.o5kl11dn3iifcaaz \
    --discovery-token-ca-cert-hash sha256:b15dae4a130a6510669291eb80bc1fbe4cff22922905f01dced5b303258ce573
  • apiserver-advertise-address 地址必须是master机器的IP
  • kubernetes-version 指定k8s版本
  • image-repository 指定容器镜像的存储库地址。在该示例中,使用阿里云容器镜像服务。
  • service-cidr指定服务网络的 CIDR 范围。该范围用于分配给 Kubernetes 服务的 IP 地址。
  • pod-network-cidr指定 Pod 网络的 CIDR 范围。该范围用于分配给集群中每个 Pod 的 IP 地址。
  • ignore-preflight-errors=NumCPU,Mem 用于初始化 Kubernetes 集群并忽略内存大小限制

没有记住初始化master节点时集群加入命令,也可执行下面命令获取:

kubeadm token create --print-join-command

node节点加入master节点

分别在k8s-node01和k8s-node02机器上执行如下命令,

kubeadm join 10.0.0.100:6443 --token ijffbx.o5kl11dn3iifcaaz \
    --discovery-token-ca-cert-hash sha256:b15dae4a130a6510669291eb80bc1fbe4cff22922905f01dced5b303258ce573

执行成功后,在master机器上执行如下命令:

kubectl get nodes

会看到如下输出:

NAME                    STATUS     ROLES                  AGE     VERSION
k8s-node01              NotReady   <none>                 118m    v1.21.0
k8s-node02              NotReady   <none>                 3h15m   v1.21.0

可以看到各节点均为NotReady状态,这是因为没有安装CNI网络插件.
执行如下命令,查看pod状态:

kubectl get pods -n kube-system

不出意外的话,可以看到croedns的状态为Pending。kubeadm初步安装完成的集群不具备网络功能,任何Pod(包括自带的CoreDNS)都无法正常工作

查看集群状态

执行如下命令:

kubectl get cs

正常,应该输出如下内容:

NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-0               Healthy   {"health":"true"}

或许你会遇到下面的错误:

scheduler            Unhealthy   Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
controller-manager   Unhealthy   Get "http://127.0.0.1:10252/healthz": dial tcp 127.0.0.1:10252: connect: connection refused

解决方案,执行如下命令,分别将文件中的port=0这一行注释掉(使用#来注释):

vim /etc/kubernetes/manifests/kube-controller-manager.yaml
vim /etc/kubernetes/manifests/kube-scheduler.yaml

再次检查状态,就正常了。

安装网络插件

执行如下命令:

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

这里需要代理,不然镜像大概率下载失败,我连了代理还是下载失败,像下面这样

kubectl get po  -A  -owide

输出如下内容:

kube-flannel   kube-flannel-ds-24sbb                0/1     Init:1/2            0          24s    10.0.0.101   k8s-node01   <none>           <none>
kube-flannel   kube-flannel-ds-fdw6g                0/1     Init:1/2            0          52m    10.0.0.100   k8s-master   <none>           <none>
kube-flannel   kube-flannel-ds-jlpmj                0/1     Init:ErrImagePull   0          52m    10.0.0.102   k8s-node02   <none>           <none>
kube-system    coredns-545d6fc579-k8gjk             0/1     Pending             0          114m   <none>       <none>       <none>           <none>
kube-system    coredns-545d6fc579-lqwr8             0/1     Pending             0          114m   <none>       <none>       <none>           <none>
kube-system    etcd-k8s-master                      1/1     Running             0          114m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-apiserver-k8s-master            1/1     Running             0          114m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-controller-manager-k8s-master   1/1     Running             0          74m    10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-proxy-ddsbg                     1/1     Running             0          114m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-proxy-vpn5l                     1/1     Running             0          96m    10.0.0.102   k8s-node02   <none>           <none>
kube-system    kube-proxy-z9w7j                     1/1     Running             0          96m    10.0.0.101   k8s-node01   <none>           <none>
kube-system    kube-scheduler-k8s-master            1/1     Running             0          73m    10.0.0.100   k8s-master   <none>           <none>

通过下面命令,看看pod的详细信息:

kubectl describe po -n kube-flannel kube-flannel-ds-24sbb

通过输出内容,可以看到需要下面2个镜像:

docker.io/flannel/flannel-cni-plugin:v1.4.1-flannel1
docker.io/flannel/flannel:v0.25.4

当然你也可以通过kube-flannel.yml来查看,搜索image

我是怎么解决的呢,在hub.docker.com/官网下载这两个镜像,虚…

rz

上传完成后,执行如下命令:

docker load -i flannel.tar.gz
docker load -i flannel-0254.tar.gz

然后删除原来pod,执行如下命令:

kubectl delete po -n kube-flannel kube-flannel-ds-24sbb kube-flannel-ds-fdw6g kube-flannel-ds-jlpmj

再次执行下面命令,查看状态;

kubectl  get po  -A  -owide

可以看到输出正常了:

NAMESPACE      NAME                                 READY   STATUS    RESTARTS   AGE    IP           NODE         NOMINATED NODE   READINESS GATES
kube-flannel   kube-flannel-ds-299f9                1/1     Running   0          35s    10.0.0.100   k8s-master   <none>           <none>
kube-flannel   kube-flannel-ds-2f9zq                1/1     Running   0          5s     10.0.0.102   k8s-node02   <none>           <none>
kube-flannel   kube-flannel-ds-z24qf                1/1     Running   0          34s    10.0.0.101   k8s-node01   <none>           <none>
kube-system    coredns-545d6fc579-k8gjk             1/1     Running   0          125m   10.244.2.3   k8s-node02   <none>           <none>
kube-system    coredns-545d6fc579-lqwr8             1/1     Running   0          125m   10.244.2.2   k8s-node02   <none>           <none>
kube-system    etcd-k8s-master                      1/1     Running   0          125m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-apiserver-k8s-master            1/1     Running   0          125m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-controller-manager-k8s-master   1/1     Running   0          85m    10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-proxy-ddsbg                     1/1     Running   0          125m   10.0.0.100   k8s-master   <none>           <none>
kube-system    kube-proxy-vpn5l                     1/1     Running   0          107m   10.0.0.102   k8s-node02   <none>           <none>
kube-system    kube-proxy-z9w7j                     1/1     Running   0          107m   10.0.0.101   k8s-node01   <none>           <none>
kube-system    kube-scheduler-k8s-master            1/1     Running   0          84m    10.0.0.100   k8s-master   <none>           <none>

kubectl命令补全

执行如下命令:

echo "source <(kubectl completion bash)" >> ~/.bash_profile
source .bash_profile

常见报错

执行kubectl get nodes,报错The connection to the server 10.0.0.100:6443 was refused - did you specify the right host or port?
出现这个问题的原因是kubectl命令需要使用kubernetes-admin来运行

在master节点上执行如下命令,将master节点中的/etc/kubernetes/admin.conf文件拷贝到从节点相同目录下:

scp -rp /etc/kubernetes/admin.conf  root@10.0.0.101:/etc/kubernetes/
scp -rp /etc/kubernetes/admin.conf  root@10.0.0.102:/etc/kubernetes/

在msater和node节点上分别执行如下命令:

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile

执行如下命令,立即生效:

source ~/.bash_profile

最后

经过努力,我终于完成了环境搭建工作。虽然耗费了我整整一天的时间,但在这个过程中遇到了许多问题并上网查找资料,还请教过运维的同事。值得庆幸的是,今天我成功地搭建起了这个k8s环境。接下来,我将投入更多精力进行深入研究和学习。