手把手从0到1:搭建Kubernetes集群

搭建 k8s 集群网上很多教程,如果是手工部署或者实验环境可以直接使用 MiniKube 或者 Kind,来在本地启动简单的 Kubernetes 集群进行后面的学习即可。如果是使用 MiniKube 的话,阿里云还维护了一个国内版的 MiniKube,这对于在国内的同学来说会比较友好。

如果还不太了解什么是K8s的话,可以参考一下这个帖子:Kubernetes(k8s)生产环境最佳实践

下面介绍使用 kubeadm 这个 Kubernetes 半官方管理工具的工作原理。kubeadm 的初衷就是让 Kubernetes 集群的部署不再让人头疼,而且发展比较成熟,关于各种问题网上都有对应的文章来解决,我们就来使用它部署一个完整的 Kubernetes 集群。

准备工作

首先准备三台虚拟机,或者是三台服务器,我是从企鹅☁️上买的三个轻量服务器,还挺便宜,但是后来看文档才知道,这所谓的轻量服务器原来就是k8s上的容器,所以我这属于是在 k8s 的容器里上搭建 k8s 集群了,搁这搁这呢。为什么我肯定这个提供的就是一个有官方镜像 linux 的容器呢,具体是因为我买了后发现他们所谓的内网在不同账号下是不能互通的,也就是说不同账号的轻量服务器分配到了不同的 node 上,内网ip只能在同一个 node 上互通,不同的node之间想互通只能去配置路由,并且配置属于自己的二层网络。所以这听起来就知道是容器了。

在本次部署中,我准备的机器配置如下:

2 核 CPU、 4 GB 内存(三台);80 GB 磁盘;Centos 7.6;内网互通;外网访问权限不受限制。

这里的内网互通我是直接通过 iptables 来进行配置的,因为三台服务器公网ip可以互通,但是内网ip是不互通的,在 k8s 中默认是用内网ip来交互的,所以我只能用如下命令来进行配置。

sudo iptables t nat A OUTPUT d <另外服务器的内网ip> j DNAT todestination <另外服务器的外网ip>

保证每个节点能内网ip都 ping 通其他节点就行了。

安装 kubeadm 和 Docker

所有节点安装Docker/kubeadm/kubelet

安装 docker

$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo $ yum y install dockerce18.06.1.ce3.el7 $ systemctl enable docker && systemctl start docker $ docker \version Docker version 18.06.1\ce, build e68fc7a

配置一下镜像地址

\# cat > /etc/docker/daemon.json << EOF { “registry-mirrors”: \[“https://b9pmyelo.mirror.aliyuncs.com”\] } EOF

添加 k8s 的 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

安装kubeadm,kubelet和kubectl

yum install y kubelet1.18.0 kubeadm1.18.0 kubectl1.18.0 systemctl enable kubelet

K8S集群还未拉起,故这里的kubelet是无法启动的,等master初始化时会自动拉起

替换 k8s 所需组件的 docker 镜像

因为国内的镜像都拉不回来关于 k8s 所需组件的,所以需要替换一下镜像

查看 kubeadm 所需要的镜像列表:

$ kubeadm config images list I1108 19:54:40.085559 2997 version.go:252\] remote version is much newer: v1.22.3; falling back to: stable1.18 W1108 19:54:40.592794 2997 configset.go:202\] WARNING: kubeadm cannot validate component configs for API groups \[kubelet.config.k8s.io kubeproxy.config.k8s.io\] k8s.gcr.io/kubeapiserver:v1.18.20 k8s.gcr.io/kubecontrollermanager:v1.18.20 k8s.gcr.io/kubescheduler:v1.18.20 k8s.gcr.io/kubeproxy:v1.18.20 k8s.gcr.io/pause:3.2 k8s.gcr.io/etcd:3.4.3\0 k8s.gcr.io/coredns:1.6.7

编写拉取shell,这里脚本里替换成所需要的组件版本就行了

$ vim ./pull\_k8s\_images.sh set \o errexit set \o nounset set \o pipefail ##这里定义版本按照上面得到的列表自己改一下版本号 KUBE\_VERSION\=v1.18.20 KUBE\_PAUSE\_VERSION\=3.2 ETCD\_VERSION\=3.4.3\0 DNS\_VERSION\=1.6.7 ##这是原始仓库名最后需要改名成这个 GCR\_URL\=k8s.gcr.io ##这里就是写你要使用的仓库 DOCKERHUB\_URL\=registry.aliyuncs.com/google\_containers ##这里是镜像列表新版本要把coredns改成coredns/coredns images\=( kube\proxy:${KUBE\_VERSION} kube\scheduler:${KUBE\_VERSION} kube\controllermanager:${KUBE\_VERSION} kube\apiserver:${KUBE\_VERSION} pause:${KUBE\_PAUSE\_VERSION} etcd:${ETCD\_VERSION} coredns:${DNS\_VERSION} ) ##这里是拉取和改名的循环语句 for imageName in ${images\[@\]} ; do docker pull $DOCKERHUB\_URL/$imageName docker tag $DOCKERHUB\_URL/$imageName $GCR\_URL/$imageName docker rmi $DOCKERHUB\_URL/$imageName done

执行shell

$ chmod +x ./pull\_k8s\_images.sh $ ./pull\_k8s\_images.sh

部署 k8s master 节点

因为我的版本是 1.18.20 的版本,所以关于 kubeadm 的配置文件 config,内容如下

vim ./kubeadm/kubeadm.yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration controllerManager: extraArgs: horizontal\podautoscaleruserestclients: “true” horizontal\podautoscalersync\period: “10s” node\monitorgraceperiod: “10s” apiServer: extraArgs: runtime\config: “api/all=true” kubernetesVersion: “stable-1.18”

这里的文件中 apiVersion 字段要根据不同的 k8s 进行调整,具体可以看看官网,因为不同的版本api不同,会报错~

具体可以看看这个:https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/

kubeadm 初始化安装 k8s

kubeadm init config ./kubeadm/kubeadm.yaml

最后安装完毕后会有提示:

\[addons\] Applied essential addon: CoreDNS \[addons\] Applied essential addon: 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 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 <master\_id>:<master\_port> token <join\_token> discoverytokencacerthash <join\_cert\_hash>

这个 kubeadm join 命令,就是用来给这个 Master 节点添加更多工作节点(Worker)的命令。我们在后面部署 Worker 节点的时候马上会用到它,所以找一个地方把这条命令记录下来。

此外,kubeadm 还会提示我们第一次使用 Kubernetes 集群所需要的配置命令:

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

而需要这些配置命令的原因是:Kubernetes 集群默认需要加密方式访问。所以,这几条命令,就是将刚刚部署生成的 Kubernetes 集群的安全配置文件,保存到当前用户的.kube 目录下,kubectl 默认会使用这个目录下的授权信息访问 Kubernetes 集群。如果不这么做的话,我们每次都需要通过 export KUBECONFIG 环境变量告诉 kubectl 这个安全配置文件的位置。

我个人更倾向于使用 export KUBECONFIG 环境变量告诉 kubectl 这个安全配置文件的位置,因为当 k8s 发生错误重新启动的时候,可会找不到配置文件

所以

$ vim /etc/profile 在文件最后添加 export KUBECONFIG\=/etc/kubernetes/admin.conf $ source /etc/profile

现在,我们就可以使用 kubectl get 命令来查看当前唯一一个节点的状态了

$ kubectl get nodes NAME STATUS ROLES AGE VERSION master NotReady master 1d v1.18.0

在调试 Kubernetes 集群时,最重要的手段就是用 kubectl describe 来查看这个节点(Node)对象的详细信息、状态和事件(Event),我们来试一下:

$ kubectl describe node master Conditions: Ready False KubeletNotReady runtime network not ready: NetworkReady\=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

通过 kubectl describe 指令的输出,我们可以看到 NodeNotReady 的原因在于,我们尚未部署任何网络插件。另外,我们还可以通过 kubectl 检查这个节点上各个系统 Pod 的状态,其中,kube-system 是 Kubernetes 项目预留的系统 Pod 的工作空间(Namepsace,注意它并不是 Linux Namespace,它只是 Kubernetes 划分不同工作空间的单位):

$ kubectl get pods n kubesystem NAME READY STATUS RESTARTS AGE coredns\78fcdf6894j9s52 0/1 Pending 0 1h coredns\78fcdf6894jm4wf 0/1 Pending 0 1h etcd\master 1/1 Running 0 2s kube\apiservermaster 1/1 Running 0 1s kube\controllermanagermaster 0/1 Pending 0 1s kube\proxyxbd47 1/1 NodeLost 0 1h kube\schedulermaster 1/1 Running 0 1s

可以看到,CoreDNS、kube-controller-manager 等依赖于网络的 Pod 都处于 Pending 状态,即调度失败。这当然是符合预期的:因为这个 Master 节点的网络尚未就绪。

部署网络插件

在 Kubernetes 项目“一切皆容器”的设计理念指导下,部署网络插件非常简单,只需要执行一句 kubectl apply 指令,以 Weave 为例:

$ kubectl apply -f “https://cloud.weave.works/k8s/net?k8s-version=

$(kubectl version | base64 | tr -d ‘\n’)”

serviceaccount/weave-net created

http://clusterrole.rbac.authorization.k8s.io/weave-net

created

http://clusterrolebinding.rbac.authorization.k8s.io/weave-net

created

http://role.rbac.authorization.k8s.io/weave-net

created

http://rolebinding.rbac.authorization.k8s.io/weave-net

created

daemonset.apps/weave-net created

部署完成后查看所有的 pod 状态

$ kubectl get pods n kubesystem NAME READY STATUS RESTARTS AGE coredns\78fcdf6894j9s52 1/1 Running 0 1d coredns\78fcdf6894jm4wf 1/1 Running 0 1d etcd\master 1/1 Running 0 9s kube\apiservermaster 1/1 Running 0 9s kube\controllermanagermaster 1/1 Running 0 9s kube\proxyxbd47 1/1 Running 0 1d kube\schedulermaster 1/1 Running 0 9s weave\netcmk27 2/2 Running 0 19s

可以看到,所有的系统 Pod 都成功启动了,而刚刚部署的 Weave 网络插件则在 kube-system 下面新建了一个名叫 weave-net-cmk27 的 Pod,一般来说,这些 Pod 就是容器网络插件在每个节点上的控制组件。

除此之外我想让pod被三个节点调度,因为k8s中默认master是不进行调度pod的,也就是此节点上不会部署pod,这个挺浪费

$ kubectl describe node master Name: master Roles: master Taints: node\role.kubernetes.io/master:NoSchedule

可以看到,Master 节点默认被加上了http://node-role.kubernetes.io/master:NoSchedule这样一个“污点”,其中“键”是http://node-role.kubernetes.io/master,而没有提供“值”。

这个污点是保证 master 不会被pod调度到

所以直接删除这个 taints:

$ kubectl taint nodes all noderole.kubernetes.io/master

部署 k8s 的 worker 节点

首先按照上面的部署“安装 kubeadm 和 Docker”

第二步,因为我希望这三个节点随便哪个都能当 master 节点来使用,所以按照“替换 k8s 所需组件的 docker 镜像”把所有master需要的组件镜像都拿来了

第三步,复制master中的 /etc/kubernetes/admin.conf 到 worker 节点的同样路径下,然后 export KUBECONFIG 环境变量

除此之外我发现在 worker join 集群的时候会出现错误:

\[ERROR FileContentprocsysnetbridgebridgenfcalliptables\]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1

解决方法:

echo “1” >/proc/sys/net/bridge/bridge-nf-call-iptables

最后在 woker 节点添加进入集群命令:

就是之前 master 节点提示的 join 命令

查看节点

$ kubectl get nodes NAME STATUS ROLES AGE VERSION vm\20\4\centos Ready <none> 141m v1.18.0 vm\20\6\centos Ready master 7h5m v1.18.0 vm\20\9\centos Ready <none> 169m v1.18.0 \# workder 节点添加 role `kubectl label nodes` vm204centos `kubernetes.io/role=worker “kubectl label nodes` vm209centos `kubernetes.io/role=worker`

因为在k8s中根据 namespace 请求pod会请求host,我不希望请求 vm-20-4-centos 的时候会找不到解析的域名,所以我在没个node节点中还添加了以下的配置:

cat >> /etc/hosts << EOF 10.0.20.4 vm20\4\centos 10.0.20.6 vm20\6\centos 10.0.20.9 vm20\9\centos EOF 将桥接的IPv4流量传递到iptables的链 $ cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge\nfcallip6tables = 1 net.bridge.bridge\nfcalliptables = 1 EOF $ sysctl \system # 生效

大功告成,enjoy~~~

关于 k8s 的玩法我个人有以下几个目标:

关于 k8s 的可视化,可以给用户提供一个可视化的 Web 界面来查看当前集群的各种信息关于 k8s 的网络插件,可以尝试各种常用的网络插件,看看他们二层网络是怎么工作原理,理解 k8s 的 CNI关于 k8s 的持久性存储是怎么实现的,看看 pvc 和 pv关于 k8s 中对象 operator 是怎么工作的,实现细节是如何的

这里先定一个小目标

作者:Blackbinbin 链接:https://www.cnblogs.com/blackbinbin/p/15530154.html

由于现在许多公司都希望在生产中使用Kubernetes,因此有必要考虑一些最佳实践。在本文中,我们将讨论一些Kubernetes的最佳实践。这里呢可以参考一下这个:Kubernetes(k8s)生产环境最佳实践

我是架构师小于哥

专注于分享技术开发小技巧,职场经验,科技资讯方面的知识,希望我的分享能够帮助到大家哈

    THE END
    喜欢就支持一下吧
    点赞14 分享
    评论 抢沙发
    头像
    欢迎您留下宝贵的见解!
    提交
    头像

    昵称

    取消
    昵称表情代码图片

      暂无评论内容