在开始之前,部署kubernetes集群机器需要满足以下几个条件:
三台机器,操作系统 centos7.7(mini)
硬件配置:2gbram,2vcpu+,硬盘30gb+
集群中所有机器之间网络互通,且可访问外网。
采用nat网络模型(依自己情况而定)
角色
ip
master
192.168.50.128
node0
node1
192.168.50.131
node2
192.168.50.132
软件
版本
docker
19.03.12
kubernetes
1.18.6
etcd
3.4.9
主机
安装组件
kube-apiserver,kube-controller-manager,kube-scheduler,etcd
kubelet,kube-proxy,etcd
master节点设置:
node1从节点设置:
node2从节点设置:
根据自己的节点命名情况来设置即可。
所有的节点都要添加hosts解析记录
在master1节点生成密钥对,并分发给其他的所有主机。
分发公钥
通过下载kernel image的rpm包进行安装。
centos7:<code>http://elrepo.org/linux/kernel/el7/x86_64/rpms/</code>

编写shell脚本升级内核
注意:一定要重启机器
验证内核版本
第一条是临时关闭,当然也可以使用第二条永久关闭,后者手动在<code>/etc/fstab</code>文件中将<code>swap</code>挂载所在的行注释掉即可。
使其立即生效
所有的节点均采用阿里云官网的base和epel源
将上面的第5-8步骤写成shell脚本自动化快速完成
在其他的节点执行此脚本跑一下即可。
<code>etcd</code> 是一个分布式键值存储系统,kubernetes使用<code>etcd</code>进行状态和数据存储,因此我们需要提前准备好<code>etcd</code>,不过为解决<code>etcd</code>单点故障问题,应采用集群方式部署,这里使用3台组建集群。
为了节约资源利用,我这里复用了两个node节点,这样子这三台主机便可组建一个集群。当然,建议是独立于k8s集群之外部署,毕竟数据很重要。
etcd节点名称
etcd-01
etcd-02
etcd-03
在kubernetes中,使用<code>openssl</code>生成证书会及其麻烦,如果我们可以把预先的证书机构、使用期等时间写在json文件里面会更加高效和自动化。而<code>cfssl</code>就是这样的一款工具,<code>cfssl</code>采用go语言编写,是一个开源的证书管理工具,cfssljson用来从cfssl程序获取json输出,并将证书,密钥,csr和bundle写入文件中。
在master节点操作:
授权并重命名:
移动到环境变量<code>/usr/local/bin</code>目录下
由于kubernetes各组件需要使用x509证书对通信进行加密和认证,所以需要创建一套ca(certificate autority),是自签名的根证书,用来签名后续需要创建的其它证书;
这里创建的ca是一个私有的内部认证中心,这个认证中心也需要一个ca证书和相应的ca私钥,ca私钥需要妥善保管,任何拥有它的人,都可以充当ca颁发证书。
再次强调一下,ca证书的请求json文件是集群所有节点共享的,只需要创建一个,它后续创建的所有其它子ca证书的基础,子ca证书都会根据这里config中的<code>profile</code>段来生成证书的相关信息;
ca-config.json 这个配置文件只是告诉我们颁发有什么功能的证书,它用于配置证书的使用场景(profile)和具体参数(usage、过期时间、服务端认证、客户端认证、加密等)。 default是默认策略,指定证书默认有效期是10年; profiles是定义使用场景,这里只是kubernetes,其实可以定义多个场景,分别指定不同的过期时间,使用场景等参数,后续签名证书时使用某个profile; signing: 表示该证书可用于签名其它证书,生成的ca.pem证书中的ca=true; server auth: 表示client 可以用该ca 对server 提供的证书进行校验; client auth: 表示server 可以用该ca 对client 提供的证书进行验证。
gencert:生成新的key(密钥)和签名证书 --initca:初始化一个新ca
<code>hosts</code>字段中ip为所有etcd节点的集群内部通信ip,有几个etcd节点,就写多少个ip。当然,为方便后期扩容可以多些几个预留的ip。
<code>gencert</code>: 生成新的key(密钥)和签名证书 <code>-initca</code>:初始化一个新ca <code>-ca</code>:指明ca的证书 <code>-ca-key</code>:指明ca的私钥文件 -<code>config</code>:指明请求证书的json文件 <code>-profile</code>:与<code>config</code>中的<code>profile</code>对应,是指根据<code>config</code>中的<code>profile</code>段来生成证书的相关信息
将前面两步创建的证书都分发给其他etcd节点。
写一个shell脚本,先在目标主机创建存放etcd证书的目录,接着复制证书
补充:事实上只需要分发<code>ca.pem</code>公钥即可,<code>ca-key.pem</code>是私钥,很多组件不需要,除非你确保使用它,你才分发到服务器上面,以免造成私钥泄露。不过我们不需要考虑太多,所以把私钥也分发到了服务器上面。
以下在节点1操作,部署完成后,将节点1生成的所有的文件拷贝到节点2和节点3
这里解释一下配置
配置选项
选项说明
<code>etcd_name</code>
节点名称,如果<code>etcd_initial_cluster_state="new"</code>这个值为<code>new</code>,哪么<code>etcd_name</code>的参数值必须位于<code>etcd_initial_cluster</code>列表中
<code>etcd_data_dir</code>
指定节点的数据存储目录(包括:节点id、集群id、集群初始化配置、snapshot文件等),如果未指定,会写在当前目录
<code>etcd_listen_peer_urls</code>
与集群其它成员之间的通信地址
<code>etcd_listen_client_urls</code>
监听本地端口,对外提供服务的地址
<code>etcd_initial_advertise_peer_urls</code>
通告给集群其它节点,本地的对等url地址
<code>etcd_advertise_client_urls</code>
客户端url,用于通告集群的其余部分信息
<code>etcd_initial_cluster</code>
集群中的所有信息节点
<code>etcd_initial_cluster_token</code>
集群的token,整个集群中保持一致
<code>etcd_initial_cluster_state</code>
初始化集群状态,默认为<code>new</code>
说明一下etcd服务启动几个选项的意义:
<code>--cert-file</code>
客户端与服务器之间tls证书文件的路径
<code>--key-file</code>
客户端与服务器之间tls密钥文件的路径
<code>--peer-cert-file</code>
对等服务器tls证书文件的路径
--peer-key-file`
对等服务器tls密钥文件的路径
<code>--trusted-ca-file</code>
签名client证书的ca证书,用于验证client证书
<code>--peer-trusted-ca-file</code>
签名对等服务器证书的ca证书。
节点1的配置文件和systemd启动脚本都设置好了,所以现在传输一下节点2和节点3的服务配置
其他另外节点2和节点3分别修改etcd.conf配置文件中的节点名称和当前服务器ip
节点2的etcd配置文件
节点3的etcd配置文件
在master节点执行一个脚本来。
查看集群状态
如果打印的每个etcd节点显示都为<code>healthy</code>,说明集群部署成功。如有问题就查messages日志
查看集群成员
所有node节点都部署docker服务
方法:浏览器打开<code>mirrors.aliyun.com</code>网站,找到docker-ce,即可看到镜像仓库yum源
写个脚本执行方便
列出所有可以安装的版本
这里我们安装18.09版本的docker-ce
查看版本号,检测docker是否安装成功
上面的这种查看docker client的版本的。建议使用下面这种方法查看docker-ce版本号,这种方法把docker的client端和server端的版本号查看的一清二楚。
默认的镜像仓库地址是docker官方的,国内访问异常缓慢,因此更换为个人阿里云的源。
由于重新加载docker仓库源,所以需要重启docker
我们操作的流程是
制作集群证书
部署<code>kube-apiserver</code>组件
部署<code>kube-controller-manager</code>组件
部署<code>kube-scheduler</code>组件
现在我们创建一套kubernetes集群的根ca证书。用于签发所有的k8s组件。
将上面临时目录生成的证书都复制在kubernetes的证书目录下:
kubernetes现托管在github上面,我们可以看到kubernetes任何版本的更新、下载等信息
点击右侧的<code>releases</code>按钮,即可看到k8s版本,可以看到目前已经发布了671次版本。
目前最新的文档版本是1.18.5。不过这节课我演示的是1.18.4版本。
只需要下载一个server包就够了,包含了master和worker node二进制文件
详情介绍:<code>https://github.com/kubernetes/kubernetes/blob/master/changelog/changelog-1.18.md</code>
下载链接:<code>https://dl.k8s.io/v1.18.4/kubernetes-server-linux-amd64.tar.gz</code>
考虑到科学上网问题,因此给大家介绍一个链接:<code>https://storage.googleapis.com/kubernetes-release/release/v1.18.4/kubernetes-server-linux-amd64.tar.gz</code>
kubernetes证书路径是<code>/etc/kubernetes/ssl</code> 配置文件路径是<code>/etc/kubernetes/cfg</code> 二进制可执行程序包直接放在环境变量<code>/usr/local/bin</code> 日志路径是<code>/var/log/kubernetes</code>
创建<code>kube-apiserver</code>配置文件
为了使用eof保留换行符,所以要写两个<code>\\</code>
配置文件详细解释如下:
<code>--logtostderr=false</code>
输出日志到文件中(文件路径由<code>--log-dir</code>指定),不输出到标准错误控制台
<code>--v=2</code>
指定输出日志的级别
<code>--advertise-address</code>
向集群成员通知 apiserver 消息的 ip 地址,这个地址必须能够被集群中其他成员访问,如果 ip 地址为空,将会使用 <code>--bind-address</code>,如果未指定<code>--bind-address</code>,将会使用主机的默认接口地址
<code>--etcd-servers</code>
连接的 etcd 服务器列表 , 形式为(<code>scheme://ip:port</code>),使用逗号分隔
<code>--etcd-cafile</code>
用于etcd 通信的 ssl ca 文件
<code>--etcd-certfile</code>
用于 etcd 通信的的 ssl 证书文件
<code>--etcd-keyfile</code>
用于 etcd 通信的 ssl 密钥文件
<code>--service-cluster-ip-range</code>
service网络地址分配 ,cidr 表示的 ip 范围,服务的 cluster ip 将从中分配, 一定不要和分配给 nodes 和 pods 的 ip 范围产生重叠
<code>--bind-address</code>
监听 --seure-port 的 ip 地址,被关联的接口必须能够被集群其它节点和 cli/web 客户端访问,如果为空,则将使用所有接口(<code>0.0.0.0</code>)
<code>--secure-port=6443</code>
用于监听具有认证授权功能的 https 协议的端口,默认值是6443
<code>--allow-privileged</code>
是否启用授权功能
--service-node-port-range
service使用的端口范围
<code>--default-not-ready-toleration-seconds</code>
表示 notready状态的容忍度秒数
<code>--default-unreachable-toleration-seconds</code>
表示 unreachable状态的容忍度秒数:
<code>--max-mutating-requests-inflight=2000</code>
在给定时间内进行中可变请求的最大数量,当超过该值时,服务将拒绝所有请求,0 值表示没有限制(默认值 200)
<code>--default-watch-cache-size=200</code>
默认监视缓存大小,0 表示对于没有设置默认监视大小的资源,将禁用监视缓存
<code>--delete-collection-workers=2</code>
用于 deletecollection 调用的工作者数量,这被用于加速 namespace 的清理( 默认值 1)
<code>--enable-admission-plugins</code>
资源限制的相关配置
<code>--authorization-mode</code>
在安全端口上进行权限验证的插件的顺序列表,以逗号分隔的列表,包括:alwaysallow,alwaysdeny,abac,webhook,rbac,node.(默认值 "alwaysallow")
<code>--enable-bootstrap-token-auth</code>
启用此选项以允许 'kube-system' 命名空间中的<code>'bootstrap.kubernetes.io/token'</code> 类型密钥可以被用于 tls 的启动认证
<code>--token-auth-file</code>
声明bootstrap token文件
<code>--kubelet-certificate-authority</code>
证书 authority 的文件路径
<code>--kubelet-client-certificate</code>
用于 tls 的客户端证书文件路径
<code>--kubelet-client-key</code>
用于 tls 的客户端证书密钥文件路径
<code>--tls-private-key-file</code>
包含匹配<code>--tls-cert-file</code>的 x509 证书私钥的文件
--service-account-key-file
包含 pem 加密的 x509 rsa 或 ecdsa 私钥或公钥的文件,用于验证 serviceaccount 令牌,如果设置该值,--tls-private-key-file 将会被使用,指定的文件可以包含多个密钥,并且这个标志可以和不同的文件一起多次使用
<code>--audit-log-maxage</code>
基于文件名中的时间戳,旧审计日志文件的最长保留天数
<code>--audit-log-maxbackup</code>
旧审计日志文件的最大保留个数
<code>--audit-log-maxsize</code>
审计日志被轮转前的最大兆字节数
<code>--audit-log-path</code>
如果设置,表示所有到apiserver的请求都会记录到这个文件中,‘-’表示写入标准输出
当集群开启了 tls 认证后,每个节点的 kubelet 组件都要使用由 apiserver 使用的 ca 签发的有效证书才能与 apiserver 通讯;此时如果节点多起来,为每个节点单独签署证书将是一件非常繁琐的事情; tls bootstrapping 功能就是让 node节点上的kubelet组件先使用一个预定的低权限用户连接到 apiserver,然后向 apiserver 申请证书,kubelet 的证书由 apiserver 动态签署;
把上面的token值拿下来,后面的照着写就行。
上面的变量引用符号<code>$</code>前面加上转义符<code>\</code>,这是在使用eof写入文件需要注意的地方。
kube-controller-manager(k8s控制器管理器)是一个守护进程,它通过kube-apiserver监视集群的共享状态(kube-apiserver收集或监视到的一些集群资源状态,供kube-controller-manager或其它客户端watch), 控制器管理器并尝试将当前的状态向所定义的状态迁移(移动、靠近),它本身是有状态的,会修改集群状态信息,如果多个控制器管理器同时生效,则会有一致性问题,所以kube-controller-manager的高可用,只能是主备模式,而kubernetes集群是采用租赁锁实现leader选举,需要在启动参数中加入 <code>--leader-elect=true</code>。
选项意义
<code>--leader-elect</code>
高可用时启用选举功能。这里只有一个controller-manager,所以不需要启用选举功能
<code>--master</code>
通过本地非安全本地端口8080连接apiserver
监控地址
<code>--allocate-node-cidrs</code>
是否应在node节点上分配和设置pod的cidr
<code>--cluster-cidr</code>
controller manager在启动时如果设置了--cluster-cidr参数,那么为每个没有设置spec.podcidr的node节点生成一个cidr地址,并用该cidr地址设置节点的spec.podcidr属性,防止不同的节点的cidr地址发生冲突
集群services 的cidr范围
<code>--cluster-signing-cert-file</code>
指定用于集群签发的所有集群范围内证书文件(根证书文件)
<code>--cluster-signing-key-file</code>
指定集群签发证书的key
<code>--root-ca-file</code>
如果设置,该根证书权限将包含service acount的toker secret,这必须是一个有效的pem编码ca 包
<code>--service-account-private-key-file</code>
包含用于签署service account token的pem编码rsa或者ecdsa私钥的文件名
<code>--experimental-cluster-signing-duration</code>
证书签发时间
调度器的职责主要是为新创建的pod在集群中寻找最合适的node,并将pod调度到node上,scheduler调度器运行在master节点,它的核心功能是监听apiserver来获取节点上为空的pod,然后为pod创建一个binding指示pod应该调度到哪个节点上,调度结果写入apiserver。
所有组件都已经启动成功,通过kubectl工具查看当前集群组件状态:
看到第二列的状态值都是<code>healthy</code>,说明master节点组件运行正常。
对于我们这里的二进制部署的一主多从,在企业中适合测试环境,因此为了更多的复用机器资源,主master节点也应该作为node节点跑pod。
下面依然在master这个节点上操作,让其再成为节点
复制二进制包
将kubernetes解压的二进制包程序<code>kubelet,kube-proxy</code>复制到本地环境变量路径下。
配置文件解释说明
<code>--hostname-override</code>
用来配置该节点在集群中显示的主机名,kubelet设置了<code>-–hostname-override</code>参数后,<code>kube-proxy</code>也需要设置,否则会出现找不到node的情况
<code>--container-runtime</code>
指定容器运行时引擎
<code>--network-plugin</code>
启用cni网络插件
<code>--kubeconfig</code>
kubelet作为客户端使用的kubeconfig认证文件,此文件是由kube-controller-mananger生成的
<code>--bootstrap-kubeconfig</code>
指定令牌认证文件
<code>--config</code>
指定kubelet配置文件
<code>--cert-dir</code>
设置<code>kube-controller-manager</code>生成证书和私钥的目录
<code>--image-pull-progress-deadline</code>
镜像拉取进度最大时间,如果在这段时间拉取镜像没有任何进展,将取消拉取,默认:1m0s
<code>--pod-infra-container-image</code>
每个pod中的<code>network/ipc</code>名称空间容器将使用的镜像
简单说几个比较重要的选项配置意义
<code>address</code>
kubelet 服务监听的地址
<code>port: 10250</code>
kubelet 服务的端口,默认 <code>10250</code>
<code>readonlyport</code>
没有认证/授权的只读 kubelet 服务端口 ,设置为 0 表示禁用,默认 `10255
<code>clusterdns</code>
dns 服务器的ip地址列表
<code>clusterdomain</code>
集群域名, kubelet 将配置所有容器除了主机搜索域还将搜索当前域
生成 kubelet bootstrap kubeconfig 配置文件
拷贝到配置文件路径<code>/etc/kubernetes/cfg</code>
cni,全名叫做:容器网络接口。是cncf旗下的一个项目,由一组用于配置容器的网络接口的规范和库组成。cni主要用于解决容器网络互联的配置并支持多种网络模型。
此命令可以看到所有请求,所有为<code>pending</code>状态,则是需要批准的。
把上面的命令的<code>name</code>字段的值拿过来。
查看节点
注意:这里的<code>status</code>状态值还是<code>notready</code>,是因为网络插件还没有部署好。接着往下即可。
kube-proxy是什么,这里就不得不提前说下service,service是一组pod的抽象集合,它相当于一组pod的负载均衡器,负责将请求分发到对应的pod,kube-proxy就是负责service的实现的,当请求到达service时,它通过label关联到后端并转发到某个pod;kube-proxy提供了三种负载均衡模式:用户空间、iptables、ipvs,我们采用的是iptables负载均衡模式。
简单说一下上面配置的选项意义
选项配置
clientconnection
与kube-apiserver交互时的参数设置
burst: 200
临时允许该事件记录值超过qps设定值
kubeconfig
kube-proxy 客户端连接 kube-apiserver 的 kubeconfig 文件路径设置
qps: 100
与kube-apiserver交互时的qps,默认值5
bindaddress
kube-proxy监听地址
healthzbindaddress
用于检查服务的ip地址和端口
metricsbindaddress
metrics服务的ip地址和端口。默认:127.0.0.1:10249
clustercidr
kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 或 --masquerade-all 选项后 kube-proxy 才会对访问 service ip 的请求做 snat
hostnameoverride
参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 node,从而不会创建任何 ipvs 规则;
创建证书请求文件
生成证书
kube-proxy是作为kube-apiserver的客户端,由于我们启用了tls,所以需要认证访问,这里我们需要使用到之前生成的证书。
拷贝到配置文件指定的路径下:
在执行kubectl exec、run、logs 等命令时,apiserver会转发到kubelet。这里定义 rbac规则,授权apiserver调用kubelet api"
flannel是 coreos 团队针对 kubernetes 设计的一个覆盖网络(overlay network)工具,其目的在于帮助每一个使用 kuberentes 的 coreos 主机拥有一个完整的子网。 flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于<code>linux tun/tap</code>,使用udp封装ip包来创建overlay网络,并借助etcd维护网络的分配情况
事实上很多用户都不能成功,因为国内网络受限,所以可以这样子来做。 修改hosts文件,加上如下解析记录
编辑镜像源,默认的镜像地址我们修改一下。把yaml文件中所有的<code>quay.io</code>修改为 <code>quay-mirror.qiniu.com</code>
此时保存保存退出。在master节点执行此命令。
这样子就可以成功拉取flannel镜像了。当然你也可以直接使用我提供给大家的<code>kube-flannel.yml</code>文件
查看flannel是否正常
如果你想查看flannel这些pod运行是否正常,使用如下命令:
注意:稍等1-3分钟后,如果第三字段<code>status</code>不是处于<code>running</code>状态的话,并且<code>status</code>字段数值一直在渐渐变大,说明flannel是异常的,需要排查问题所在。
目前节点状态是<code>ready</code>,表示集群节点现在是可用的。
如果有以下报错:
或者是
上面的这些都表示是网络问题不能拉取镜像,我这里给大家提前准备了flannel的镜像。导入一下就可以了。
coredns用于集群中pod解析service的名字,kubernetes基于coredns用于服务发现功能。
安装coredns1.6.7(目前较新版本)。如果之前修改了podip的网段,那么这里需要自行修改此文件的clusterip参数。其他可保持不变
查看pod状态
只要能出结果,解析就是没有问题的。
在master节点操作,把文件远程复制给node节点
在node1节点上操作
修改为<code>--hostname-override-=node1</code>
修改为<code>hostnameoverride: node1</code>
下面的是在<code>master</code>节点操作的
上面的<code>condition</code>为<code>pending</code>状态的表示将要被加入集群的节点。所以记录前面的<code>name</code>字段
稍等两分钟
按照上面的前五步继续执行即可。做完之后如下所示:
至此,二进制单节点集群部署已经完成,接下来我们可以测试一下集群是否可用。
现在我们在kubernetes集群中创建一个nginx的pod,验证是否能正常运行。
在master节点执行一下步骤:
现在我们查看pod和service
打印的结果中,前半部分是pod相关信息,后半部分是service相关信息。我们看<code>service/nginx</code>这一行可以看出service暴漏给集群的端口是<code>30249</code>。记住这个端口。
然后从pod的详细信息可以看出此时pod在<code>node2</code>节点之上。node2节点的ip地址是<code>192.168.50.132</code>
那现在我们访问一下。打开浏览器(建议火狐浏览器),访问地址就是:http://192.168.50.132:30249
先把dashboard的配置文件下载下来。由于我们之前已经添加了hosts解析,因此可以下载。
默认dashboard只能集群内部访问,修改service为nodeport类型,暴露到外部:
大概在此文件的32-44行之间,修改为如下:
运行此yaml文件
主要是看<code>status</code>这一列的值,如果是<code>running</code>,并且<code>restarts</code>字段的值为0(只要这个值不是一直在渐渐变大),就是正常的,目前来看是没有问题的。我们可以继续下一步。
查看此dashboard的pod运行所在的节点
从上面可以看出,<code>kubernetes-dashboard-9774cc786-ccvcf</code>运行所在的节点是<code>node2</code>上面,并且暴漏出来的端口是<code>30001</code>,所以访问地址是: https://192.168.50.132:30001
用火狐浏览器访问,访问的时候会让输入token,从此处可以查看到token的值。
把上面的token值输入进去即可进去dashboard界面。
不过现在我们虽然可以登陆上去,但是我们权限不够还查看不了集群信息,因为我们还没有绑定集群角色,同学们可以先按照上面的尝试一下,再来做下面的步骤
再次使用输出的token登陆dashboard即可。