搭建K8S集群(kubeadm篇)
一、K8S概述
K8S是当下最火热的容器运行时编排工具,不仅仅提供了用户应用的容器镜像运行解决方案,还提供了路由网关、水平扩展、多副本容灾等能力。在Kubernetes项目中,master节点由负责api服务的kube-apiserver、负责调度的kube-scheduler、负责编排的kebu-controller-manager三者组成。node节点上,最核心的部分是kubelet组件。kubelet主要负责同容器运行时(比如Docker项目)交互,而交互依赖的是CRI(Container Runtime Interface)的远程调用接口。这个接口定义了容器运行时的各项核心操作。具体的容器运行时,则通过OCI这个容器标准,把CRI请求翻译成对Linux系统的底层调用。
话不多说,我们用最简单的方式,即kubeadm来搭建一个K8S集群吧。
二、如何使用kubeadm搭建集群
2.1 机器准备
我们需要准备3台机器,配置是4核8G,提前做好部署规划和网络规划。考虑到云上机器的网络条件较好,我这里用的是腾讯云的机器,读者们也可以使用3台2核4G的机器来完成搭建。
每台机器都需要关闭防火墙,配置好DNS域名解析,并且时间上已配置同步。
- master节点
- node1节点
- node2节点
2.2 准备程序包
由于我们本次使用的是kubeadm工具搭建集群,我们先要下载相关的程序包。但是!由于大中华网络等原因,部分包下载会有问题。那怎么办呢,我们找一台海外的机器来下载这部分程序包即可。
安装kubeadm所需的程序包有以下几个
- kubelet
- kubeadm
- kubectl
- kubernetes-cni
- cri-tools
# 安装yum-utils工具,这样我们就可以将包下载到本地
yum install -y yum-utils
# 配置yum源,让我们能够下载相关程序包
cat >> /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=http://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=http://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
# 将相关程序包下载 kubelet kubeadm kubectl kubernetes-cni cri-tools
yumdownloader kubelet kubeadm kubectl kubernetes-cni cri-tools
# 打包这几个rpm程序包,上传到我们的集群机器上去
tar zcf k8s-deploy.tgz *.rpm
备注: 作者知道有些同学可能还没有海外的服务器,这几个服务的包我已经打包好放在网盘上,大家可以直接下载使用。https://share.weiyun.com/g8sbwcWA
2.3 安装kubeadm
我们已经有了相关软件包了,安装就很简单了
# 解压软件包
tar xf k8s-deploy.tgz
# 执行安装
yum localinstall -y *.rpm
2.4 下载镜像
最早期的时候,K8S集群是直接部署在裸金属服务器上面的,这个部署过程有一系列繁琐的操作(如手动生成配置证书等操作),非常的不友好。后面呢大家考虑,既然K8S能力这么强大,那为何不把kube-apiserver、kube-controller-manager、kube-scheduler这些都做成容器镜像,然后通过K8S直接管理起来呢。事实上,kubeadm就是这样做的。但是这里有一点需要注意的是,并不是每个组件都事宜做成容器镜像的,比方说像kubelet。因为kubelet需要与宿主机打交道,比方说配置宿主机网络、存储系统等。假如kubelet是一个容器,那么其运行在自己的Namespace中,是很难对宿主机进行操作的。因此,kubelet是需要手动在宿主机上安装的。
我们开始下载K8S组件的容器镜像,糟糕这里似乎有被大中华的网络拦截了。这里我们就需要依赖阿里云镜像仓库,这里有我们所需的全部镜像,我们可以从阿里云镜像仓库下载镜像,然后打tag将镜像改成kubeadm所需的即可。
# 查看kubeadm部署集群所需的镜像
kubeadm config images list
#k8s.gcr.io/kube-apiserver:v1.23.1
#k8s.gcr.io/kube-controller-manager:v1.23.1
#k8s.gcr.io/kube-scheduler:v1.23.1
#k8s.gcr.io/kube-proxy:v1.23.1
#k8s.gcr.io/pause:3.6
#k8s.gcr.io/etcd:3.5.1-0
#k8s.gcr.io/coredns/coredns:v1.8.6
# 下载所需镜像并修改tag,这里的coredns我们稍后单独处理
for item in `kubeadm config images list | egrep -v "coredns|grep"` ; do image=` echo $item | sed -e "s@k8s.gcr.io@registry.aliyuncs.com/google_containers@g"`; docker pull $image ; docker tag $image `echo $image | sed -e "s@registry.aliyuncs.com/google_containers@k8s.gcr.io@g"` ; docker rmi $image ; done ;
# 下载coredns镜像
for item in `kubeadm config images list | egrep "coredns" | grep -v grep ` ; do image=` echo $item | sed -e "s@k8s.gcr.io/coredns@registry.aliyuncs.com/google_containers@g"` ; docker pull $image ; docker tag $image `echo $image | sed -e "s@registry.aliyuncs.com/google_containers@k8s.gcr.io/coredns@g"` ; docker rmi $image ; done ;
# 查看我们下载的所有镜像,此时看看是不是和我们通过kubeadm config images list查询出来的一样啦
docker images
2.5 部署master节点
到了这里,我们就可以使用kubeadm来部署master节点。部署命令非常简单,只需要执行kubeadm init
即可。部署完成之后,出现如下提示就说明kubeadm执行完成了。
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 IP:6443 --token ltfaw0.yci1z7zqdrll2ixp \
--discovery-token-ca-cert-hash sha256:145415d491d67daeb13910ffb49e5a8608863225a13cfdc794b85cc5aca46972
在这里可能有些同学会碰到kubelet相关的异常,通过执行journalctl -xeu kubelet
可以看到,最常见的就是kubelet提示“kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"”,这是什么意思呢?
意思就是说docker使用的cgroup驱动和kubelet使用的驱动不一致,我们知道cgroup全称为Linux Control Group,是用来控制一个进程组使用系统资源的上限。kubelet是通过CRI这个远程调用接口来操作容器运行时(即Docker),驱动不一致会导致相关限制能力无法执行。所以,我们需要修改Docker(建议,当然也可以修改kubelet)的cgroup驱动。具体如下:
# 修改docker的配置文件
cat /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 内核重新加载进程配置
systemctl daemon-reload
# 重启docker进程
systemctl restart docker
# 检查docker的cgroup驱动
docker info
2.6 部署网络插件
此时我们部署好了K8S集群的master节点,根据输出提示export KUBECONFIG=/etc/kubernetes/admin.conf
在机器上执行,然后我们通过kubectl get po -n kube-system
检查各个Pod的运行情况。突然发现咋不对劲呢,怎么有些Pod始终处于Pending状态呢?
[root@VM-62-206-centos ~]# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64897985d-9nrqf 0/1 Pending 0 31s
coredns-64897985d-ms4jr 0/1 Pending 0 31s
etcd-vm-62-206-centos 1/1 Running 0 35s
kube-apiserver-vm-62-206-centos 1/1 Running 0 35s
kube-controller-manager-vm-62-206-centos 1/1 Running 0 37s
kube-proxy-zkxln 1/1 Running 0 31s
kube-scheduler-vm-62-206-centos 1/1 Running 0 35s
其实这是正常的,DNS和什么相关,和网络相关对吧。我们现在都还没有网络插件,肯定是有问题啊。话不多说,我们立马把网络插件部署上去,在这里我们使用的网络插件是weave
。
# 部署网络插件,非常简单一条命令就可以搞定
# 执行完之后需要等一段时间,因为在下载镜像
kubectl apply -n kube-system -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
这里可能有些同学在部署过程中会碰到,网络插件weave在启动的过程在提示“CrashLoopBackOff”,我们打开日志检查
kubectl logs weave-net-k966t -c weave -n kube-system
# Network 10.32.0.0/12 overlaps with existing route 10.0.0.0/8 on host
我们从这里看到了啥,是不是说weave需要配置10.32.0.0/12这个网段的路由表,但是和现有机器上面的路由表冲突了。怎么办呢,其实比较简单的解决办法是把现有冲突的网段调整一下。调整完之后,我们再打印下Pod运行情况,可以看到Pod全部都正常运行了。
kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64897985d-9nrqf 1/1 Running 0 92m
coredns-64897985d-ms4jr 1/1 Running 0 92m
etcd-vm-62-206-centos 1/1 Running 0 92m
kube-apiserver-vm-62-206-centos 1/1 Running 0 92m
kube-controller-manager-vm-62-206-centos 1/1 Running 0 92m
kube-proxy-zkxln 1/1 Running 0 92m
kube-scheduler-vm-62-206-centos 1/1 Running 0 92m
weave-net-k966t 2/2 Running 11 (21m ago) 59m
2.7 部署node节点
部署node节点比较简单,我们在node节点上面安装好docker-ce、kubeadm、上传相关镜像后,只需要将部署master节点系统提示的命令复制过去即可。
# 执行部署node节点命令
kubeadm join IP:6443 --token ltfaw0.yci1z7zqdrll2ixp --discovery-token-ca-cert-hash sha256:145415d491d67daeb13910ffb49e5a8608863225a13cfdc794b85cc5aca46972
此时我们等一段时间,等待weave插件在node节点上面安装完成,就可以看到整个集群Pod均运行情况。
kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64897985d-9nrqf 1/1 Running 0 130m
coredns-64897985d-ms4jr 1/1 Running 0 130m
etcd-vm-62-206-centos 1/1 Running 0 130m
kube-apiserver-vm-62-206-centos 1/1 Running 0 130m
kube-controller-manager-vm-62-206-centos 1/1 Running 0 130m
kube-proxy-ftr7m 1/1 Running 0 30m
kube-proxy-mcxt5 1/1 Running 0 29m
kube-proxy-zkxln 1/1 Running 0 130m
kube-scheduler-vm-62-206-centos 1/1 Running 0 130m
weave-net-9rpsv 2/2 Running 0 30m
weave-net-dd9nr 2/2 Running 0 29m
weave-net-k966t 2/2 Running 11 (58m ago) 97m
2.8 一些收尾工作
到目前为止,我们已经部署好一个非生产环境的K8S集群,做做实验还是绰绰有余的。不过,大家有没有发现,kubectl
命令只有在master节点上管用,在其他的node节点似乎不起作用,始终提示“The connection to the server localhost:8080 was refused - did you specify the right host or port?”。这个如何修复呢,其实很简单,我们只需要把master节点的/etc/kubernetes/admin.conf
拷贝到node节点的对应位置,在执行export命令即可。
scp /etc/kubernetes/admin.conf root@node_ip:/etc/kubernetes/admin.conf
export KUBECONFIG=/etc/kubernetes/admin.conf
三、控制器模式下运行Pod实例
现在我们已经有了完整可用的K8S集群,我们就开始部署一个简答的Nginx服务吧。
3.1 编写YAML文件
我已经编写好一个最简单的案例文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
3.2 运行应用
我们执行kubectl apply -f nginx.yaml
来将我们编写好的YAML提交到K8S,使用apply
操作的好处在于,K8S可以自动识别到文件的变化,并根据对象的变化自动执行响应的操作(增加或者减少副本数量、修改应用镜像等)。
过了几分钟,我们可以看到应用顺利运行起来了。
kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-5fcc5d8c6d-6fr2b 1/1 Running 0 12m
nginx-deployment-5fcc5d8c6d-79r2w 1/1 Running 0 11m