k8s集群搭建
背景
实验环境准备
部署docker
设置使用国内Yum源
安装指定的Docker版本
安装Docker20.10.3
设置cgorup驱动使用systemd
启动后台进程
查看docker版本
部署kubeadm和kubelet
设置k8s YUM仓库
安装软件包
配置kubelet
设置内核参数
启动kubelet并设置开机启动
使用ipvs进行负载均衡
初始化集群部署master
导出所有默认的配置
修改集群创建参数
执行初始化操作
为kubectl准备kubeconfig文件
使⽤kubectl命令查看组件状态
处理unhealth的组件
使用kubectl获取node信息
部署网络插件
部署node节点
测试k8s集群
想要快速的体验Kubernetes的功能,官方提供了非常多的部署方案,可以使用官方提供的kubeadm以容器的方式运行Kubernetes集群,也可以使用二进制方式部署更有利于理解 Kubernetes的架构,我们先使用kubeadm快速的部署一个Kubernetes集群后。
注意:由于云平台的存在当前部署已经是k8s学习的初期阶段了,建议尽快开始k8s课程的深入学习。k8sv1.13版本发布后,kubeadm才正式进入GA,可以生产使用。目前k8s的对应镜像仓库,在国内阿里云也有了镜像站点,使用kubeadm部署k8s集群变得简单并且容易了很多,我们使用kubeadm带领大家快速部署k8sv1.21.14版本。
在上一节实验环境的基础上,我们如下来分配⻆色:
主机名 | Ip地址 | 描述 |
linux-node1.example.com | eth0:192.168.56.11 | k8s master/etcd节点 |
linux-node2.example.com | eth0:192.168.56.12 | k8s node节点 |
linux-node3.example.com | eth0:192.168.56.13 | k8s node节点 |
service网段 | 10.1.0.0/16 | |
Pod网段 | 10.2.0.0/16 |
首先需要在所有Kubernetes集群的节点中安装Docker和kubeadm。
[root@linux-node1 ~]# cd /etc/yum.repos.d/
[root@linux-node1 yum.repos.d]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
由于kubeadm对Docker的版本是有要求的,需要安装与Kubernetes匹配的版本,这个对应关系⼀般在每次发布的Changlog中可以找到。例如1.21.14的CHANGELOG中docker需求是 20版本;当前docker的版本可以通过下面的命令查看:
[root@linux-node1 ~]# yum list docker-ce.x86_64 --showduplicates |sort-r 已加载插件:fastestmirror 已安装的软件包 可安装的软件包 * updates: m
[root@linux-node1 ~]# yum -y install docker-ce-20.10.3-3.el7 docker-ce-cli-20.10.3-3.el7
[root@linux-node1 ~]# mkdir /etc/docker
[root@linux-node1 ~]# cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://dx5z2hy7.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
[root@linux-node1 ~]# systemctl enable docker && systemctl start docker
[root@linux-node1 ~]# docker --version
Docker version 19.03.8, build afacb8b
在k8s集群的所有节点上部署完毕docker后,还需要全部部署kubeadm和kubelet,其中kubeadm是管理⼯具,kubelet是⼀个服务,⽤于启动k8s对应的服务。
这⾥在官⽅⽂档的基础上修改为了国内阿⾥云的yum仓库
[root@linux-node1 ~]# vim /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yu
由于版本更新频繁,请指定对应的版本号,本⽂采⽤ 1.21.14版本,其它版本未经测试,如果不指定版本默认安装最新版本。
[root@linux-node1 yum.repos.d]# yum -y install kubelet-1.21.14 kubeadm-1.21.14 kubectl-1.21.14 ipvsadm
默认情况下, Kubelet不允许所在的主机存在交换分区,后期规划的时候,可以考虑在系统安装的时候不创建交换分区,针对已经存在交换分区的可以设置忽略禁⽌使⽤Swap的限 制,不然⽆法启动Kubelet。
[root@linux-node1 ~]# vim /etc/sysconfig/kubelet KUBELET_CGROUP_ARGS="--cgroup-driver=systemd" KUBELET_EXTRA_ARGS="--fail-swap-on=false"
在所有节点上关闭SWAP
[root@linux-node1 ~]# swapoff -a
[root@linux-node1 ~]# cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
使配置⽣效 [root@linux-node1 ~]# sysctl --system
注意,此时kubelet是⽆法正常启动的,可以查看/var/log/messages有报错信息,等待执⾏初始化之后即可正常,为正常现象;
[root@linux-node1 ~]# systemctl enable kubelet && systemctl start kubelet
在Kubernetes集群中Kube-Proxy组件负载均衡的功能,默认使⽤iptables,⽣产环境建议使⽤ipvs进⾏负载均衡。在所有节点启⽤ipvs模块
[root@linux-node1 ~]# vim /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
[root@linux-node1 ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
[root@linux-node1 ~]# source /etc/sysconfig/modules/ipvs.modules
以上步骤请在Kubernetes的所有节点上执⾏,本实验环境是需要在linux-node1 、linux-node2 、linux-node3这三台机器上均安装Docker 、kubeadm 、kubelet.
在所有节点上安装完毕后,在linux-node1这台Master节点上进⾏集群的初始化⼯作。
[root@linux-node1 ~]#kubeadm config print init-defaults > kubeadm.yaml
上⾯的命令会⽣成⼀个默认配置的kubeadm配置⽂件,然后在此基础上进⾏修改即可。
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.56.11 #修改为API Server的地址
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: linux-node1.example.com
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers #修改为阿⾥云镜像仓库
kind: ClusterConfiguration
kubernetesVersion: v1.21.14 #修改为具体的版本
networking:
dnsDomain: cluster.local
serviceSubnet: 10.1.0.0/16 #修改service的⽹络
podSubnet: 10.2.0.0/16 #新增Pod的⽹络
scheduler: {}
--- #下⾯有增加的三⾏配置,⽤于设置Kubeproxy使⽤LVS
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
[root@linux-node1 ~]# kubeadm init --config kubeadm.yaml
[init] Using Kubernetes version: v1.21.14
[preflight] Running pre-flight checks
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
[ERROR Mem]: the system RAM (972 MB) is less than the minimum 1700 MB
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher
如果遇到上⾯这样的报错,是因为在实验环境开启了交换分区,以及CPU的核数⼩于2造成的,可以使⽤ --ignore-preflight-errors=进⾏忽略。 --ignore-preflight-errors= :忽略运⾏时 的错误,例如上⾯⽬前存在[ERROR NumCPU]和[ERROR Swap],忽略这两个报错就是增加 --ignore-preflight-errors=NumCPU 和--ignore-preflight-errors=Swap的配置即可。 再次 执⾏初始化操作: ``` [root@linux-node1 ~]# swapoff -a [root@linux-node1 ~]# kubeadm init --config kubeadm.yaml --ignore-preflight-errors=NumCPU,Mem,Swap [init] Using Kubernetes version: v1.21.14 [preflight] Running pre-flight checks [WARNING NumCPU]: the number of available CPUs 1 is less than the required 2 [WARNING Mem]: the system RAM (972 MB) is less than the minimum 1700 MB [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [certs] Using certificateDir folder
"/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key
执⾏完毕后,会在当前输出下停留,等待下载Kubernetes组件的Docker镜像。根据你的⽹络情况,可以持续 1-5分钟,你也可以使⽤docker images查看下载的镜像。镜像下载完毕之后 ,就会进⾏初始操作:
这⾥省略了所有输出,初始化操作主要经历了下⾯ 15个步骤,每个阶段均输出均使⽤[步骤名称]作为开头:
* [init]:指定版本进⾏初始化操作
* [preflight] :初始化前的检查和下载所需要的 Docker镜像⽂件。
* [kubelet-start]:⽣成kubelet的配置⽂件”/var/lib/kubelet/config.yaml”,没有这个⽂件kubelet⽆法启动,所以初始化之前的kubelet实际上启动失败。
* [certificates]:⽣成Kubernetes使⽤的证书,存放在/etc/kubernetes/pki⽬录中。
* [kubeconfig] :⽣成 KubeConfig⽂件,存放在/etc/kubernetes⽬录中,组件之间通信需要使⽤对应⽂件。
* [control-plane]:使⽤/etc/kubernetes/manifest⽬录下的YAML⽂件,安装 Master组件。
* [etcd]:使⽤/etc/kubernetes/manifest/etcd.yaml安装Etcd服务。
* [wait-control-plane]:等待control-plan部署的Master组件启动。
* [apiclient]:检查Master组件服务状态。
* [uploadconfig]:更新配置
* [kubelet]:使⽤configMap配置kubelet。
* [patchnode]:更新CNI信息到Node上,通过注释的⽅式记录。
* [mark-control-plane]:为当前节点打标签,打了⻆⾊Master,和不可调度标签,这样默认就不会使⽤ Master节点来运⾏ Pod。
* [bootstrap-token]:⽣成token记录下来,后边使⽤kubeadm join往集群中添加节点时会⽤到
* [addons]:安装附加组件CoreDNS和kube-proxy 成功执⾏之后,你会看到下⾯的输出:
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.56.11:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash
sha256:a0272d589f79d9568bb79cf829493676156351f96237438b85ce32da3724b109 ```
如果执⾏失败,那意味着之前的操作存在问题,检查顺序如下: * 基础环境 * 主机名是否可以解析, SELinux, iptables是否关闭。 * 交换分区是否存在free -m查看 * 内核参数是否修 改、 IPVS是否修改(⽬前阶段不会造成失败)
基础软件
Docker是否安装并启动
Kubelet是否安装并启动
执⾏kubeadm是否有别的报错是否忽略
systemctl status kubelet查看kubelet是否启动
如果kubelet⽆法启动,查看⽇志有什么报错,并解决报错。
以上都解决完毕,需要重新初始化
kubeadm reset 进⾏重置(⽣产千万不要执⾏,会直接删除集群) 根据kubeadm reset 提升,清楚iptables和LVS 。 请根据上⾯输出的要求配置kubectl命令来访问集群。
kubectl默认会在执⾏的⽤户家⽬录下⾯的.kube⽬录下寻找config⽂件。这⾥是将在初始化时[kubeconfig]步骤⽣成的admin.conf拷⻉到.kube/config。
[root@linux-node1 ~]# mkdir -p $HOME/.kube [root@linux-node1 ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config [root@linux-node1 ~
在该配置⽂件中,记录了API Server的访问地址,所以后⾯直接执⾏kubectl命令就可以正常连接到API Server中。
[root@linux-node1 ~]# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Unhealthy Get "http://127.0.0.1:10252/healthz": dial tcp 127.0.0.1:10252: connect: connection refused
scheduler Unhealthy Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
etcd-0 Healthy {"health":"true"}
k8s集群状态提示Gethttp://127.0.0.1:10251/healthz:dial tcp 127.0.0.1:10251:connect: connection refused,这种情况是因为kube-controller-manager.yaml和kube-scheduler.yaml ⾥ ⾯配置了默认端⼝0。检查kube-controller-manager.yaml和kube-scheduler.yaml
[root@linux-node1 manifests]# cd /etc/kubernetes/manifests/
[root@linux-node1 manifests]# ls
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
#对这两个⽂件进⾏备份 ,创建备份⽬录
[root@linux-node1 manifests]# mkdir /backup
# 对⽂件进⾏备份操作
[root@linux-node1 manifests]# cp kube-controller-manager.yaml /backup/
[root@linux-node1 manifests]# cp kube-scheduler.yaml /backup/
编辑kube-controller-manager.yaml和kube-scheduler.yaml的配置⽂件,注视掉port=0的⾏,保存退出即可。
使⽤kubectl命令查看组件状态
[root@linux-node1 manifests]# kubectl get cs Warning: v1 ComponentStatus is deprecated in v1.19+ NAME STATUS MESSAGE ERROR controller-ma
知识说明:为什么上⾯的输出没有显示API Server组件的状态
因为API Server是Kubernetes集群的⼊⼝,所有和Kubernetes集群的交互都必须经过APIServer, kubectl命令也是连接到API Server上进⾏交互,所以如果能够正常使⽤kubectl执⾏ 命令,意味着API Server运⾏正常。
⽬前只有⼀个节点,⻆⾊是Master,状态是NotReady。
[root@linux-node1 ~]# kubectl get node NAME STATUS ROLES AGE VERSION linux-node1.example.com NotReady control-plane,master 19m v1.21.14
Master节点NotReady的原因就是因为没有使⽤任何的⽹络插件,此时Node和Master的连接还不正常。⽬前最流⾏的Kubernetes⽹络插件有Flannel 、Calico 、Canal,这⾥分别列举 了Canal和Flannel,你可以选择其中之⼀进⾏部署。 因为基础的Kubernetes集群已经配置完毕,后⾯的增加组件等操作,⼏乎都可以使⽤kubectl和⼀个YAML配置⽂件来完成。 【部 署Flannel⽹络插件】(推荐) 部署Flannel⽹络插件需要修改Pod的IP地址段,修改为和你初始化⼀直的⽹段,可以先下载Flannel的YAML⽂件修改后,再执⾏。
[root@linux-node1 ~]# git clone --depth 1 https://github.com/coreos/flannel.git
[root@linux-node1 ~]# cd flannel/Documentation/
[root@linux-node1 Documentation]# vim kube-flannel.yml
# 修改 "Network": "10.244.0.0/16"为"Network": "10.2.0.0/16",
net-conf.json: |
{
"Network": "10.2.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
部署Flannel
[root@linux-node1 Documentation]# kubectl create -f kube-flannel.yml
查看Pod状态,注意如果有出于pending状态的pod待flanel安装完成后就会变成running;
[root@linux-node1 Documentation]# kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-flannel kube-flannel-ds-zp4mf 1/1 Running 0 3m1s
kube-system coredns-59d64cd4d4-wxzjw 1/1 Running 0 31m
kube-system coredns-59d64cd4d4-zppgw 1/1 Running 0 31m
kube-system etcd-linux-node1.example.com 1/1 Running 1 31m
kube-system kube-apiserver-linux-node1.example.com 1/1 Running 1 31m
kube-system kube-controller-manager-linux-node1.example.com 1/1 Running 6 29m
kube-system kube-proxy-d4tsw 1/1 Running 1 31m
kube-system kube-scheduler-linux-node1.example.com 1/1 Running 5 28m
[root@linux-node1 Documentation]
所有Pod的状态都变成Running之后,这个时候再次获取Node,会发现节点变成了Ready状态。
[root@linux-node1 Documemtation]# kubectl get node
NAME STATUS ROLES AGE VERSION
linux-node1.example.com Ready control-plane,master 35m v1.21.1
kubeadm其实使⽤Kubernetes部署Kubernetes,这样就存在先有鸡还是先有蛋的问题,所以,我们⾸先⼿动部署了Docker和kubelet,然后kubeadm调⽤kubelet以静态Pod的⽅式部 署了Kubernetes集群中的其它组件。静态Pod在后⾯的章节会讲到。
Master节点部署完毕之后,就可以部署Node节点,⾸先请遵循部署Docker和kubeadm章节为Node节点部署安装好docker 、kubeadm和kubelet,此过程这⾥不再重复列出。
Master节点输出增加节点的命令
[root@linux-node1 Documentation]# kubeadm token create --print-join-command
kubeadm join 192.168.56.11:6443 --token 352g01.c3r8gvzog5i545hi --discovery-token-ca-cert-hash sha256:a0272d589f79d9568bb79cf82949367615635
1f96237438b85ce32da3724b109
[root@linux-node1 Documentation]#
在node节点执⾏注意如果节点有交换分区,需要增加--ignore-preflight-errors=Swap 。 部署linux-node2
[root@linux-node2 ~]# kubeadm join 192.168.56.11:6443 --token 61tumq.rnrs79270u4a2ofj --discovery-token-ca-cert-hash sha256:a0272d58
部署linux-node3
[root@linux-node3 ~]# kubeadm join 192.168.56.11:6443 --token 61tumq.rnrs79270u4a2ofj --discovery-token-ca-cert-hash sha256:a0272d58
这个时候kubernetes会使⽤DaemonSet在所有节点上都部署flannel和kube-proxy 。部署完毕之后节点即部署完毕。 DaemonSet的内容后⾯会讲解。
测试k8s集群
创建⼀个Pod的nginx应⽤
[root@linux-node1 ~]# kubectl create deployment nginx --image=nginx:alpine
deployment.apps/nginx created
[root@linux-node1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-54458cd494-9j7ql 0/1 ContainerCreating 0 10s
查看Pod详细信息 待Pod的状态为Running后,可以获取Pod的IP地址,这个IP地址是从Master节点初始化的--pod-network-cidr=10.2.0.0/16地址段中分配的。
测试nginx访问
[root@linux-node1 Documentation]# curl --head http://10.2.2.2
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Fri, 14 Oct 2022 05:56:27 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 18:48:00 GMT
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
测试扩容
[root@linux-node1 ~]# kubectl scale deployment nginx --replicas=2
deployment.extensions/nginx scaled
[root@linux-node1 Documentation]# kubectl get pod
STATUS
Running
Running
[root@linux-node1 ~]# kubectl expose deployment nginx --port=80
--type=NodePort
service/nginx exposed
[root@linux-node1 Documentation]# kubectl get service
CLUSTER-IP
ClusterIP
NodePort
测试service的ip
[root@linux-node1 Documentation]# curl --head http://10.1.200.119
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Fri, 14 Oct 2022 06:00:18 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 18:48:00 GMT
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
[root@linux-node1 Documentation]#
测试Nodeport,外部访问
这样看起来已经拥有了第⼀个k8s集群,接下来我们将开始k8s探索之旅。