温馨提示:若将此教程作为搭建K8s集群的参考,建议先纵览所有流程,因为本文所展示并非最简步骤,而是按照本人的安装步骤组织,其中穿插了本人踩过的坑。所以为求思路清晰,提高搭建效率,建议首先纵览一遍!
文章目录
- 1.准备工作——搭建分布式虚拟机集群
- 1.1安装VMware workstation
- 1.2安装虚拟机CentOS 7
- 1.3虚拟机克隆
- 2.搭建K8s集群
- 2.1安装kubeadm,kubelet(master和node都需要)
- 2.2 安装docker(master和node都需要)
- 2.3虚拟机克隆
- 2.4 kubeadm配置以及Master节点安装
- 2.5 Node安装并加入集群
- 3 安装网络插件
- 3.1 安装flannel
- 3.2更换网络插件为calico
1.准备工作——搭建分布式虚拟机集群
1.1安装VMware workstation
此处略去XXX个字以及XXX张图!
1.2安装虚拟机CentOS 7
- 在VMware workstation中创建虚拟机
- 此处略去XXX个字!
- 问题记录
- 虚拟机无法访问外网,网络需要配置为
NAT
;编辑/etc/sysconfig/networ-scripts/
目录下的ifcfg-ens33
文件,修改其中的ONBOOT=no
为ONBOOT=yes
。然后重启即可。 - 此时
yum
源可以正常使用,安装网络工具net-tools
,就可以使用ifconfig
查看网络配置。
yum install -y net-tools
1.3虚拟机克隆
- 形成一个
master
和两个node
的模式。当然也可以在一个集群上做安装和配置,等到需要差异化配置之前再进行克隆,后者更高效。
2.搭建K8s集群
我们最终搭建的集群及其配置情况如下表所示:
hostname | OS | IP | plug-ins |
k8s-master | CentOS 7.6 | 192.168.140.134 | docker-1.13.1; kubelet-1.18.3; kubeadm-1.18.3;kubectl-1.18.0 |
k8s-node1 | CentOS 7.6 | 192.168.140.136 | docker-1.13.1; kubelet-1.18.3; kubeadm-1.18.3 |
k8s-node2 | CentOS 7.6 | 192.168.140.135 | docker-1.13.1; kubelet-1.18.3; kubeadm-1.18.3 |
2.1安装kubeadm,kubelet(master和node都需要)
关闭防火墙
systemctl disable firewalld
systemctl stop firewalld
禁用SELinux
setenforce 0
vi /etc/sysconfig/selinux
## 设置SELINUX=enforcing 为 SELINUX=disabled
reboot #使修改生效
配置yum
源
在目录/etc/yum.repo.d/
下创建文件kubernetes.repo
,在其中添加如下内容:
[kubernetes]
name=Kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled = 1
gpgcheck = 1
gpgkey = http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/yum-package-key.gpg
在此处踩了一个很大又很傻逼的坑,我是在虚拟机中配置的,在配置yum
源镜像时,将字母“l”
写成了数字“1”
,集群搭建进度就被拖慢了半天!
安装kubelet
和kubeadm
yum install -y kubelet kubeadm
启动kubelet
服务并使能开机启动:
systemctl start kubelet
systemctl enable kubelet
2.2 安装docker(master和node都需要)
配置yum
源
yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo
yum clean all
yum makecache
yum update -y
安装
yum install docker -y
开启docker
服务并使能开机启动
systemctl start docker
systemctl enable docker
2.3虚拟机克隆
我选择进行到这一步之后再进行虚拟机克隆,避免在每台虚拟机上进行重复的安装工作。此时形成了一个master
两个node
的局面,但其实此时三台虚拟机的配置情况完全相同。
细心的读者在这一步应该会注意到,还需要在master几点上安装kubectl
组件,但其实在之前安装kubeadm
和kubelet
的过程中,kubectl
已经被默认安装了,所以此处无需另外的操作。
2.4 kubeadm配置以及Master节点安装
在这一步,我们想做的事情就是借kubeadm
在一台节点上做初始化,使其能够承担k8s集群中master
的角色。所以主要使用到的工具是kubeadm
,那么先要对它所有了解,否则如果稀里糊涂按照教程运行一堆指令之后,运行结果正确是万幸,不正确的话便不知从何下手做改正。kubeadm
相关指令了解
kubeadm init ## 启动一个 Kubernetes 主节点
kubeadm join ## 启动一个 Kubernetes 工作节点并且将其加入到集群
kubeadm upgrade ## 更新一个 Kubernetes 集群到新版本
kubeadm config ## 如果使用 v1.7.x 或者更低版本的 kubeadm 初始化集群,您需要对集群做一些配置以便使用 kubeadm upgrade 命令
kubeadm token ## 管理 kubeadm join 使用的令牌
kubeadm reset ## 还原 kubeadm init 或者 kubeadm join 对主机所做的任何更改
kubeadm init
的参数
--apiserver-advertise-address string
## API Server将要广播的监听地址。如指定为 `0.0.0.0` 将使用缺省的网卡地址。
--apiserver-bind-port int32 缺省值: 6443
## API Server绑定的端口
--apiserver-cert-extra-sans stringSlice
## 可选的额外提供的证书主题别名(SANs)用于指定API Server的服务器证书。可以是IP地址也可以是DNS名称。
--cert-dir string 缺省值: "/etc/kubernetes/pki"
## 证书的存储路径。
--config string
## kubeadm配置文件的路径。警告:配置文件的功能是实验性的。
--cri-socket string 缺省值: "/var/run/dockershim.sock"
## 指明要连接的CRI socket文件
--dry-run
## 不会应用任何改变;只会输出将要执行的操作。
--feature-gates string
## 键值对的集合,用来控制各种功能的开关。可选项有:
Auditing=true|false (当前为ALPHA状态 - 缺省值=false)
CoreDNS=true|false (缺省值=true)
DynamicKubeletConfig=true|false (当前为BETA状态 - 缺省值=false)
-h, --help
## 获取init命令的帮助信息
--ignore-preflight-errors stringSlice
## 忽视检查项错误列表,列表中的每一个检查项如发生错误将被展示输出为警告,而非错误。 例如: 'IsPrivilegedUser,Swap'. 如填写为 'all' 则将忽视所有的检查项错误。
--kubernetes-version string 缺省值: "stable-1"
## 为control plane选择一个特定的Kubernetes版本。
--node-name string
## 指定节点的名称。
--pod-network-cidr string
## 指明pod网络可以使用的IP地址段。 如果设置了这个参数,control plane将会为每一个节点自动分配CIDRs。
--service-cidr string 缺省值: "10.96.0.0/12"
## 为service的虚拟IP地址另外指定IP地址段
--service-dns-domain string 缺省值: "cluster.local"
## 为services另外指定域名, 例如: "myorg.internal".
--skip-token-print
## 不打印出由 `kubeadm init` 命令生成的默认令牌。
--token string
## 这个令牌用于建立主从节点间的双向受信链接。格式为 [a-z0-9]{6}\.[a-z0-9]{16} - 示例: abcdef.0123456789abcdef
--token-ttl duration 缺省值: 24h0m0s
## 令牌被自动删除前的可用时长 (示例: 1s, 2m, 3h). 如果设置为 '0', 令牌将永不过期。
在了解完kubeadm
的指令和相关参数后,我们就可以在k8s-master
节点上做配置了。在进行kubeadm
初始化时,需要指定多项参数,包括k8s
的版本信息等,我们使用到的命令如下:
初始化master节点
kubeadm init --kubernetes-version=v1.18.0 \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=192.168.140.134
由于master
正常工作,所需的组件较多,而且各组件都以pod
的形式运行在节点之上,所以初始化的过程中,系统就会自动到默认的仓库拉取所需组件的镜像,可惜的是默认仓库的链接国内网络无法访问,所以就会爆出如下图的错误:
拉取镜像
尽管如此,我们依然可以曲线救国。首先要清楚该过程中拉取的镜像都有哪些,包括apiserver
、etcd
、scheduler
、controller-manager
、kube-proxy
、pause
、coredns
,但是默认的源来自k8s.gcr.io
,不能访问。为此,下文展示了使用国内阿里云的镜像源来拉去镜像的脚本。值得注意的是,需要手动配置各组件的版本,并匹配pause
,etcd
,coredns
对应的版本、版本出错的话,配置过程依然不能完成。此处我有一个确认版本的方法,就是输入kubeadm init
指令后,等待错误信息打印到终端,按照错误信息中的提示,选择对应的镜像版本。
images=( # 下面的镜像应该去除"k8s.gcr.io/"的前缀,版本换成上面获取到的版本
kube-apiserver:v1.18.0
kube-controller-manager:v1.18.0
kube-scheduler:v1.18.0
kube-proxy:v1.18.0
pause:3.2
etcd:3.4.3-0
coredns:1.6.7
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done
按照以上脚本,我们就可以下载所需的景象了,查看成功拉取的镜像:
重新开始初始化
kubeadm init --kubernetes-version=v1.18.0 \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=192.168.140.134
等待一段时间后,Kubernetes
的Master
安装成功,显示如下信息:
按照提示执行下面的命令,复制配置文件到普通的用户home目录下:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
这样就在Master
上安装了Kubernetes
,但是在集群内还是没哟可用的工作节点Node
,并缺乏对容器网络的配置。这里需要注意的是kubeadm init
命令执行完成后几行提示信息,其中包括了加入节点的指令(kubeadm join
)和所需的Token
。
此时,可以使用命令kubectl get -n kube-system configmap
验证一下ConfigMap
:
可以看到其中生成了名为kubeadm-config
的ConfigMap
对象。使用指令kubectl get node
验证集群,可以看到集群中现在已经有了一个节点:
2.5 Node安装并加入集群
此前,我们已经完成了在node
上安装kubeadm
和kubelet
的工作,且开启并设置了node
节点上的docker
和kubelet
服务开机自启动。
加入node1
在k8s-node1
上运行如下指令将其加入集群:
kubeadm join 192.168.140.134:6443 --token a3mtet.9kpd8pol4fpxif6u \
--discovery-token-ca-cert-hash sha256:a144bd098133691cc8e68bda61dcc10741d573696c6a2fd55a5e0b36272db1cb
以上信息来自master初始化完成的最后几行打印信息,是非常重要的信息,在node节点加入集群式做安全验证等使用。可以看到添加成功:
在master
上运行kubectl get nodes
,可以看到集群中此时已经有两个节点:
加入node2
为kubeadm join
命令生成配置文件,创建文件join-config.json
,内容如下:
运行指令kubeadm join --cnotallow=join-config.json
,可以看到下图,加入成功。
此时在master
中使用指令kubectl get nodes
查看集群中的节点已经达到三个:
至此,k8s集群就搭建成功,但我们可以看到多有节点的STATUS均为NotReady
,这是因为还没安装网络插件。此外,node节点的ROLES为<none>
3 安装网络插件
3.1 安装flannel
这一步同样需要选用对应的网络插件版本。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml
运行结束后,可以看到k8s-master
处于Ready
状态而其他节点依然处于NotReady
:
观察系统中所有pod的状态,并没有完全处于running状态。
查看k8s-node1
节点描述信息:
kubectl describe node k8s-node1
KubeletNotReady
runtime network not ready: NetworkReady=false
reason:NetworkPluginNotReady
message:docker: network plugin is not ready: cni config uninitialized
为此我换了一种网络插件,期待能够消除异常。首先卸载刚刚安装的flannel
网络插件:
kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml
3.2更换网络插件为calico
重现安装calio
网络插件:
kubectl apply -f https://docs.projectcalico.org/v3.14/manifests/calico.yaml
可以看到应用成功:
在此声明,可以选择的网络插件有很多中,除了flannel,calico,还包括weave,cilium,Contiv-VPP等。
但是在更换网络插件之后,node节点依然处于NotReady
状态,为了查找原因,我查看一个处于ConatinerCreating
状态的pod
:
kubectl describe pod kube-proxy-n98pw -n kube-system
可以得到如下反馈信息:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 59m default-scheduler Successfully assigned kube-system/kube-proxy-n98pw to k8s-node1
Warning FailedCreatePodSandBox 51m (x4 over 53m) kubelet, k8s-node1 Failed to create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.2": Get https://k8s.gcr.io/v1/_ping: dial tcp 64.233.189.82:443: connect: connection refused
Warning FailedCreatePodSandBox 16m (x12 over 58m) kubelet, k8s-node1 Failed to create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.2": Get https://k8s.gcr.io/v1/_ping: dial tcp 74.125.203.82:443: connect: connection refused
Warning FailedCreatePodSandBox 11m (x38 over 62m) kubelet, k8s-node1 Failed to create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.2": Get https://k8s.gcr.io/v1/_ping: dial tcp 74.125.204.82:443: connect: connection refused
Warning FailedCreatePodSandBox <invalid> (x5 over 25s) kubelet, k8s-node1 Failed to create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.2": Get https://k8s.gcr.io/v1/_ping: dial tcp 74.125.203.82:443: connect: connection refused
重点内容如下:
原来是在k8s-node1
和k8s-node2
节点上没有拉取pause:3.2
和kube-proxy:v1.18.0
两个镜像,我们按照上文拉取镜像并重新tag的方法,在这两个节点上拉取所需的镜像。就可以看到非正常状态的pod由ContainerCreating
状态变为(Init:ImagePullBackOff)
,再变为Running
状态,最终达到的效果就是,所有pod处于Running
状态:
以及所有的节点处于Ready
状态:
至此,我们终于完成了使用kubeadm
在三台虚拟机节点上搭建k8s集群的工作。
感受:虽然教程很多,但是感觉该踩的坑一个也没有少,不管高级的还是低级的错误。而且Google到的答案往往不是我们想要的,这时就应该静下心定位为题出现的位置,根据系统的报错一个个消灭问题,当然请教身边的大佬是个很高效的方法(在此致谢宇哥)。消灭问题的过程,不仅可以完善集群搭建,也可以增长经验。最后,投入了两天的集群搭建工作终于收尾了,也欢迎大家来交流!