- 第一部分 k8s概念和架构
- 第二部分 从零搭建k8s集群
- 创建一个 Master 节点
- 将一个 Node 节点加入到当前集群中
- 二进制方式部署k8s集群
- 关闭防火墙
- 关闭selinux
- 永久关闭
- 临时关闭
- 关闭swap
- 临时
- 永久关闭
- 根据规划设置主机名【master节点上操作】
- 根据规划设置主机名【node1节点操作】
- 在master添加hosts
- 将桥接的IPv4流量传递到iptables的链
- 生效
- 时间同步
- 第三部分 k8s核心概念
- 获取kubectl的命令
- 获取某个命令的介绍和使用
- 对象类型:对象的一组键值对,使用冒号结构表示
- yaml 也允许另一种写法,将所有键值对写成一个行内对象
- Kubernetes核心技术Pod
- 存活检查,如果检查失败,将杀死容器,根据Pod的restartPolicy【重启策略】来操作
- 就绪检查,如果检查失败,Kubernetes会把Pod从Service endpoints中剔除
- 第四部分 搭建集群监控平台系统
- 第五部分 从零搭建高可用k8s集群
- 第六部分 在集群环境部署项目
第一部分 k8s概念和架构
Kubernetes简介
bilibili尚硅谷K8S视频:https://www.bilibili.com/video/BV1GT4y1A756 中文官网:https://kubernetes.io/zh 中文社区:https://www.kubernetes.org.cn/
K8S主要讲的就是Kubernetes,首先Kubernetes首字母为K,末尾为s,中间一共有8个字母,所以简称K8s
k8s概述
kubernetes,简称K8s,是用8 代替8 个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署,规划,更新,维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的。
总结:
- k8s是谷歌在2014年发布的容器化集群管理系统
- 使用k8s进行容器化应用部署
- 使用k8s利于应用扩展
-
K8S功能
自动装箱
自我修复(自愈能力)
当容器失败时,会对容器进行重启
当所部署的Node节点有问题时,会对容器进行重新部署和重新调度
当容器未通过监控检查时,会关闭此容器直到容器正常运行时,才会对外提供服务
如果某个服务器上的应用不响应了,Kubernetes会自动在其它的地方创建一个
水平扩展
通过简单的命令、用户UI 界面或基于CPU 等资源使用情况,对应用容器进行规模扩大或规模剪裁
当我们有大量的请求来临时,我们可以增加副本数量,从而达到水平扩展的效果
当黄色应用过度忙碌,会来扩展一个应用
服务发现
用户不需使用额外的服务发现机制,就能够基于Kubernetes 自身能力实现服务发现和负载均衡
对外提供统一的入口,让它来做节点的调度和负载均衡, 相当于微服务里面的网关?
滚动更新
可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新
添加应用的时候,不是加进去就马上可以进行使用,而是需要判断这个添加进去的应用是否能够正常使用版本回退
可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退
类似于Git中的回滚密钥和配置管理
在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
存储编排
自动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要
存储系统可以来自于本地目录、网络存储(NFS、Gluster、Ceph 等)、公共云存储服务批处理
K8S架构组件
完整架构图
架构细节
K8S架构主要包含两部分:Master(主控节点)和 node(工作节点)
master节点架构图
Node节点架构图
k8s 集群控制节点,对集群进行调度管理,接受集群外用户去集群操作请求; master:主控节点
- API Server:集群统一入口,以restful风格进行操作,同时交给etcd存储
- 提供认证、授权、访问控制、API注册和发现等机制
- scheduler:节点的调度,选择node节点应用部署
- controller-manager:处理集群中常规后台任务,一个资源对应一个控制器
- etcd:存储系统,用于保存集群中的相关数据
- API Server:集群统一入口,以restful风格进行操作,同时交给etcd存储
- Work node:工作节点
- Kubelet:master派到node节点代表,管理本机容器
- 一个集群中每个节点上运行的代理,它保证容器都运行在Pod中
- 负责维护容器的生命周期,同时也负责Volume(CSI) 和 网络(CNI)的管理
- kube-proxy:提供网络代理,负载均衡等操作
- Kubelet:master派到node节点代表,管理本机容器
- 容器运行环境【Container Runtime】
- 容器运行环境是负责运行容器的软件
- Kubernetes支持多个容器运行环境:Docker、containerd、cri-o、rktlet以及任何实现Kubernetes CRI (容器运行环境接口) 的软件。
-
K8S核心概念
Pod
Pod是K8s中最小的单元
- 一组容器的集合
- 共享网络【一个Pod中的所有容器共享同一网络】
-
Volume
声明在Pod容器中可访问的文件目录
- 可以被挂载到Pod中一个或多个容器指定路径下
-
Controller
确保预期的pod副本数量【ReplicaSet】
- 无状态应用部署【Deployment】
- 无状态就是指,不需要依赖于网络或者ip
- 有状态应用部署【StatefulSet】
- 有状态需要特定的条件
- 确保所有的node运行同一个pod 【DaemonSet】
-
Deployment
定义一组Pod副本数目,版本等
- 通过控制器【Controller】维持Pod数目【自动回复失败的Pod】
- 通过控制器以指定的策略控制版本【滚动升级、回滚等】
Service
- 定义一组pod的访问规则
- Pod的负载均衡,提供一个或多个Pod的稳定访问地址
- 支持多种方式【ClusterIP、NodePort、LoadBalancer】
Label
Namespace
命名空间,逻辑隔离
- 一个集群内部的逻辑隔离机制【鉴权、资源】
- 每个资源都属于一个namespace
- 同一个namespace所有资源不能重复
-
API
我们通过Kubernetes的API来操作整个集群
同时我们可以通过 kubectl 、ui、curl 最终发送 http + json/yaml 方式的请求给API Server,然后控制整个K8S集群,K8S中所有的资源对象都可以采用 yaml 或 json 格式的文件定义或描述
如下:使用yaml部署一个nginx的pod
完整流程
通过Kubectl提交一个创建RC(Replication Controller)的请求,该请求通过APlserver写入etcd
- 此时Controller Manager通过API Server的监听资源变化的接口监听到此RC事件
- 分析之后,发现当前集群中还没有它所对应的Pod实例
- 于是根据RC里的Pod模板定义一个生成Pod对象,通过APIServer写入etcd
- 此事件被Scheduler发现,它立即执行执行一个复杂的调度流程,为这个新的Pod选定一个落户的Node,然后通过API Server讲这一结果写入etcd中
- 目标Node上运行的Kubelet进程通过APiserver监测到这个”新生的Pod.并按照它的定义,启动该Pod并任劳任怨地负责它的下半生,直到Pod的生命结束
- 随后,我们通过Kubectl提交一个新的映射到该Pod的Service的创建请求
- ControllerManager通过Label标签查询到关联的Pod实例,然后生成Service的Endpoints信息,并通过APIServer写入到etod中,
接下来,所有Node上运行的Proxy进程通过APIServer查询并监听Service对象与其对应的Endponts信息,建立一个软件方式的负载均衡器来实现Service访问到后端Pod的流量转发功能
第二部分 从零搭建k8s集群
搭建K8S集群前置知识
搭建k8s环境平台规划
单master集群
多master集群
多个master节点,管理多个node节点,同时中间多了一个负载均衡的过程
服务器硬件配置要求
测试环境
master:2核 4G 20G
node: 4核 8G 40G生产环境
master:8核 16G 100G
node: 16核 64G 200G
目前生产部署Kubernetes集群主要有两种方式kubeadm
kubeadm是一个K8S部署工具,提供kubeadm init 和 kubeadm join,用于快速部署Kubernetes集群
官网地址:点我传送二进制包
从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
Kubeadm降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署Kubernetes集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。Kubeadm部署集群
kubeadm 是官方社区推出的一个用于快速部署kubernetes 集群的工具,这个工具能通过两条指令完成一个kubernetes 集群的部署:
创建一个Master 节点kubeadm init
将Node 节点加入到当前集群中$ kubeadm join
安装要求
在开始之前,部署Kubernetes集群机器需要满足以下几个条件
一台或多台机器,操作系统为Centos7.X
- 硬件配置:2GB或更多GAM,2个CPU或更多CPU,硬盘30G
- 集群中所有机器之间网络互通
- 可以访问外网,需要拉取镜像
- 禁止swap分区
kubeadm方式部署k8s集群
kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。
这个工具能通过两条指令完成一个kubernetes集群的部署: ```bash创建一个 Master 节点
kubeadm init
将一个 Node 节点加入到当前集群中
kubeadm join
使用kubeadm方式搭建K8s集群主要分为以下几步
- 准备三台虚拟机,同时安装操作系统CentOS 7.x
- 对三个安装之后的操作系统进行初始化操作
- 在三个节点安装 docker kubelet kubeadm kubectl
- 在master节点执行kubeadm init命令初始化
- 在node节点上执行 kubeadm join命令,把node节点添加到当前集群
- 配置CNI网络插件,用于节点之间的连通【失败了可以多试几次】
- 通过拉取一个nginx进行测试,能否进行外网测试
<a name="GcwGU"></a>
### 安装要求
在开始之前,部署Kubernetes集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多【注意master需要两核】
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止swap分区
<a name="MukY6"></a>
### 准备环境
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655457843670-36c0a201-ef4c-428a-bfcd-88dec92cc268.png#clientId=uc7df39d4-25e4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=170&id=u373457a1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=213&originWidth=317&originalType=binary&ratio=1&rotation=0&showTitle=false&size=12610&status=done&style=none&taskId=u490d62a8-c52a-45b8-8102-25d89223246&title=&width=253.6)<br />然后开始在每台机器上执行下面的命令
```bash
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 关闭selinux
# 永久关闭
sed -i 's/enforcing/disabled/' /etc/selinux/config
# 临时关闭
setenforce 0
# 关闭swap
# 临时
swapoff -a
# 永久关闭
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 根据规划设置主机名【master节点上操作】
hostnamectl set-hostname k8smaster
# 根据规划设置主机名【node1节点操作】
hostnamectl set-hostname k8snode1
# 根据规划设置主机名【node2节点操作】
hostnamectl set-hostname k8snode2
# 在master添加hosts
cat >> /etc/hosts << EOF
192.168.177.130 k8smaster
192.168.177.131 k8snode1
192.168.177.132 k8snode2
EOF
# 将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 生效
sysctl --system
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
安装Docker/kubeadm/kubelet
所有节点安装Docker/kubeadm/kubelet ,Kubernetes默认CRI(容器运行时)为Docker,因此先安装Docker
安装Docker
首先配置一下Docker的阿里yum源
cat >/etc/yum.repos.d/docker.repo<<EOF
[docker-ce-edge]
name=Docker CE Edge - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/\$basearch/edge
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
然后yum方式安装docker
# yum安装
yum -y install docker-ce
# 查看docker版本
docker --version
# 启动docker
systemctl enable docker
systemctl start docker
配置docker的镜像源
cat >> /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
然后重启dockersystemctl restart docker
添加kubernetes软件源
然后我们还需要配置一下yum的k8s软件源
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
由于版本更新频繁,这里指定版本号部署:
# 安装kubelet、kubeadm、kubectl,同时指定版本
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
# 设置开机启动
systemctl enable kubelet
部署Kubernetes Master【master节点】
在 192.168.177.130 执行,也就是master节点
kubeadm init --apiserver-advertise-address=192.168.177.130 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.18.0 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址,【执行上述命令会比较慢,因为后台其实已经在拉取镜像了】,我们 docker images 命令即可查看已经拉取的镜像
当我们出现下面的情况时,表示kubernetes的镜像已经安装成功
使用kubectl工具 【master节点操作】
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
执行完成后,我们使用下面命令,查看我们正在运行的节点kubectl get nodes
能够看到,目前有一个master节点已经运行了,但是还处于未准备状态
下面我们还需要在Node节点执行其它的命令,将node1和node2加入到我们的master节点上
加入Kubernetes Node【Slave节点】
下面我们需要到 node1 和 node2服务器,执行下面的代码向集群添加新节点
执行在kubeadm init输出的kubeadm join命令:
注意,以下的命令是在master初始化完成后,每个人的都不一样!!!需要复制自己生成的
kubeadm join 192.168.177.130:6443 --token 8j6ui9.gyr4i156u30y80xf \
--discovery-token-ca-cert-hash sha256:eda1380256a62d8733f4bddf926f148e57cf9d1a3a58fb45dd6e80768af5a500
默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,操作如下:
kubeadm token create --print-join-command
当我们把两个节点都加入进来后,我们就可以去Master节点 执行下面命令查看情况kubectl get node
部署CNI网络插件
上面的状态还是NotReady,下面我们需要网络插件,来进行联网访问
# 下载网络插件配置
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
默认镜像地址无法访问,sed命令修改为docker hub镜像仓库。
# 添加
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
##①首先下载v0.13.1-rc2-amd64 镜像
##参考博客:https://www.cnblogs.com/pyxuexi/p/14288591.html
##② 导入镜像,命令,,特别提示,3个机器都需要导入,3个机器都需要导入,3个机器都需要导入,3个机器都需要导入,重要的事情说3遍。不然抱错。如果没有操作,报错后,需要删除节点,重置,在导入镜像,重新加入才行。本地就是这样操作成功的!
docker load < flanneld-v0.13.1-rc2-amd64.docker
#####下载本地,替换将image: quay.io/coreos/flannel:v0.13.1-rc2 替换为 image: quay.io/coreos/flannel:v0.13.1-rc2-amd64
# 查看状态 【kube-system是k8s中的最小单元】
kubectl get pods -n kube-system
运行后的结果
运行完成后,我们查看状态可以发现,已经变成了Ready状态了
如果上述操作完成后,还存在某个节点处于NotReady状态,可以在Master将该节点删除
# master节点将该节点删除
##20210223 yan 查阅资料添加###kubectl drain k8snode1 --delete-local-data --force --ignore-daemonsets
kubectl delete node k8snode1
# 然后到k8snode1节点进行重置
kubeadm reset
# 重置完后在加入
kubeadm join 192.168.177.130:6443 --token 8j6ui9.gyr4i156u30y80xf --discovery-token-ca-cert-hash sha256:eda1380256a62d8733f4bddf926f148e57cf9d1a3a58fb45dd6e80768af5a500
测试kubernetes集群
我们都知道K8S是容器化技术,它可以联网去下载镜像,用容器的方式进行启动
在Kubernetes集群中创建一个pod,验证是否正常运行:
# 下载nginx 【会联网拉取nginx镜像】
kubectl create deployment nginx --image=nginx
# 查看状态
kubectl get pod
如果我们出现Running状态的时候,表示已经成功运行了
下面我们就需要将端口暴露出去,让其它外界能够访问
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看一下对外的端口
kubectl get pod,svc
能够看到,我们已经成功暴露了 80端口 到 30529上
我们到我们的宿主机浏览器上,访问如下地址
http://192.168.177.130:30529/
发现我们的nginx已经成功启动了
到这里为止,我们就搭建了一个单master的k8s集群
二进制方式部署k8s集群
步骤
- 创建多台虚拟机,安装Linux系统
- 操作系统的初始化
- 为etcd 和 apiserver 自签证书
- 部署etcd集群
- 部署master组件【安装docker、kube-apiserver、kube-controller-manager、kube-scheduler、etcd】
- 部署node组件【安装kubelet、kube-proxy、docker、etcd】
- 部署集群网络
准备虚拟机
首先我们准备了两台虚拟机,来进行安装测试操作系统的初始化
然后我们需要进行一些系列的初始化操作 ```go关闭防火墙
systemctl stop firewalld systemctl disable firewalld
关闭selinux
永久关闭
sed -i ‘s/enforcing/disabled/‘ /etc/selinux/config
临时关闭
setenforce 0
关闭swap
临时
swapoff -a
永久关闭
sed -ri ‘s/.swap./#&/‘ /etc/fstab
根据规划设置主机名【master节点上操作】
hostnamectl set-hostname k8s_2_master
根据规划设置主机名【node1节点操作】
hostnamectl set-hostname k8s_2_node1
在master添加hosts
cat >> /etc/hosts << EOF 192.168.177.140 k8s_2_master 192.168.177.141 k8s_2_node1 EOF
将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF
生效
sysctl —system
时间同步
yum install ntpdate -y ntpdate time.windows.com
<a name="g8TmJ"></a>
### 部署Etcd集群
Etcd是一个分布式键值存储系统,Kubernetes使用Etcd进行数据存储,所以先准备一个Etcd数据库,为了解决Etcd单点故障,应采用集群方式部署,这里使用3台组建集群,可容忍一台机器故障,当然也可以使用5台组件集群,可以容忍2台机器故障。
<a name="G4yMv"></a>
### 自签证书
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655525428805-763642ce-6778-47df-929f-647599d028c8.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u453074ac&margin=%5Bobject%20Object%5D&name=image.png&originHeight=431&originWidth=1119&originalType=url&ratio=1&rotation=0&showTitle=false&size=204509&status=done&style=none&taskId=u0f21c399-eebd-4a59-b307-18d52709919&title=)<br />这个https证书,其实就是服务器颁发给网站的,代表这是一个安全可信任的网站。而在我们K8S集群的内部,其实也是有证书的,如果不带证书,那么访问就会受限<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655525449570-26aee781-5d20-4f6c-b06b-77292dbf1597.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=207&id=u027c678b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=373&originWidth=621&originalType=url&ratio=1&rotation=0&showTitle=false&size=35943&status=done&style=none&taskId=u0a988d2d-677d-4c85-aa64-3190aea6d2a&title=&width=345)<br />同时在集群内部 和 外部的访问,我们也需要签发证书<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655525463909-34c07544-0675-4876-b867-759635bb01e0.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=200&id=u8a9353e4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=417&originWidth=877&originalType=url&ratio=1&rotation=0&showTitle=false&size=53423&status=done&style=none&taskId=u152a18ae-20c7-4e25-b5dd-f0ca60fb140&title=&width=421.4000244140625)<br />如果我们使用二进制的方式,那么就需要自己手动签发证书。<br />自签证书:我们可以想象成在一家公司上班,然后会颁发一个门禁卡,同时一般门禁卡有两种,一个是内部员工的门禁卡,和外部访客门禁卡。这两种门禁卡的权限可能不同,员工的门禁卡可以进入公司的任何地方,而访客的门禁卡是受限的,这个门禁卡其实就是自签证书<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655525504757-9aa9b76f-64dd-44db-8a80-c0c680a2b362.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u90943c3c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=245&originWidth=568&originalType=url&ratio=1&rotation=0&showTitle=false&size=41193&status=done&style=none&taskId=u112899e6-f652-416f-b10b-3321b225523&title=)
<a name="BuMBi"></a>
### 准备cfssl证书生成工具
cfssl是一个开源的证书管理工具,使用json文件生成证书,相比openssl 更方便使用。找任意一台服务器操作,这里用Master节点。
```go
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
Kubeadm和二进制方式对比
Kubeadm方式搭建K8S集群
- 安装虚拟机,在虚拟机安装Linux操作系统【3台虚拟机】
- 对操作系统初始化操作
- 所有节点安装Docker、kubeadm、kubelet、kubectl【包含master和slave节点】
- 安装docker、使用yum,不指定版本默认安装最新的docker版本
- 修改docker仓库地址,yum源地址,改为阿里云地址
- 安装kubeadm,kubelet 和 kubectl
- k8s已经发布最新的1.19版本,可以指定版本安装,不指定安装最新版本
yum install -y kubelet kubeadm kubectl
- 在master节点执行初始化命令操作
kubeadm init
- 默认拉取镜像地址 K8s.gcr.io国内地址,需要使用国内地址
- 安装网络插件(CNI)
kubectl apply -f kube-flannel.yml
- 在所有的node节点上,使用join命令,把node添加到master节点上
-
二进制方式搭建K8S集群
安装虚拟机和操作系统,对操作系统进行初始化操作
- 生成cfssl 自签证书
- ca-key.pem、ca.pem
- server-key.pem、server.pem
- 部署Etcd集群
- 部署的本质,就是把etcd集群交给 systemd 管理
- 把生成的证书复制过来,启动,设置开机启动
- 为apiserver自签证书,生成过程和etcd类似
- 部署master组件,主要包含以下组件
- apiserver
- controller-manager
- scheduler
- 交给systemd管理,并设置开机启动
- 如果要安装最新的1.19版本,下载二进制文件进行安装
- 部署node组件
- docker
- kubelet
- kube-proxy【需要批准kubelet证书申请加入集群】
- 交给systemd管理组件- 组件启动,设置开机启动
- 批准kubelet证书申请 并加入集群
- 部署CNI网络插件
-
第三部分 k8s核心概念
Kubernetes集群管理工具kubectl
kubectl是Kubernetes集群的命令行工具,通过kubectl能够对集群本身进行管理,并能够在集群上进行容器化应用的安装和部署。
命令格式如下kubectl [command] [type] [name] [flags]
参数 command:指定要对资源执行的操作,例如create、get、describe、delete
- type:指定资源类型,资源类型是大小写敏感的,开发者能够以单数 、复数 和 缩略的形式
例如:
kubectl get pod pod1
kubectl get pods pod1
kubectl get po pod1
- name:指定资源的名称,名称也是大小写敏感的,如果省略名称,则会显示所有的资源,例如
kubectl get pods
获取某个命令的介绍和使用
kubectl get —help
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655526637417-6f2e64c4-313c-4cf5-acf3-e77115aa73a2.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=402&id=u62d96587&margin=%5Bobject%20Object%5D&name=image.png&originHeight=503&originWidth=672&originalType=binary&ratio=1&rotation=0&showTitle=false&size=41991&status=done&style=none&taskId=uef308d81-4fe8-4a7f-a10c-716e084251b&title=&width=537.6)
<a name="d6u0S"></a>
### 部署命令
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655526657197-b914e95c-a933-44fa-a326-cfcafc70d64c.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=214&id=u5ff61631&margin=%5Bobject%20Object%5D&name=image.png&originHeight=267&originWidth=749&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27923&status=done&style=none&taskId=u8dd6f7ab-9d59-444f-83d5-72b629f5728&title=&width=599.2)
<a name="Y402K"></a>
### 集群管理命令
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655526675424-81fc398f-64fa-46a8-90e1-3b6b86818edd.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=343&id=u64a1eedb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=429&originWidth=534&originalType=binary&ratio=1&rotation=0&showTitle=false&size=28813&status=done&style=none&taskId=u18a7c38d-8566-4af5-be76-9b4c31442f1&title=&width=427.2)
<a name="hcrvT"></a>
### 故障和调试命令
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655526696238-93802299-3123-46a1-907e-bdc59781ecbb.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=366&id=u13c35ab8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=458&originWidth=875&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38004&status=done&style=none&taskId=ucb20d5e4-83ea-4513-972b-4513a046e3e&title=&width=700)
<a name="v1Phz"></a>
### 其它命令
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655526721087-44322cfd-26c5-4276-9402-bfaa672296d9.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=466&id=uae30d44b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=582&originWidth=685&originalType=binary&ratio=1&rotation=0&showTitle=false&size=56252&status=done&style=none&taskId=u5bb07d30-5ae3-49a5-938a-df9b7c3fb20&title=&width=548)
<a name="dU0qh"></a>
### 目前使用的命令
```go
# 创建一个nginx镜像
kubectl create deployment nginx --image=nginx
# 对外暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看资源
kubectl get pod, svc
Kubernetes集群YAML文件详解
k8s 集群中对资源管理和资源对象编排部署都可以通过声明样式(YAML)文件来解决,也就是可以把需要对资源对象操作编辑到YAML 格式文件中,我们把这种文件叫做资源清单文件,通过kubectl 命令直接使用资源清单文件就可以实现对大量的资源对象进行编排部署了。一般在我们开发的时候,都是通过配置YAML文件来部署集群的。
YAML文件:就是资源清单文件,用于资源编排
YAML文件介绍
YAML概述
YAML :仍是一种标记语言。为了强调这种语言以数据做为中心,而不是以标记语言为重点。
YAML 是一个可读性高,用来表达数据序列的格式。
YAML 基本语法
- 使用空格做为缩进
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 低版本缩进时不允许使用Tab 键,只允许使用空格
- 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
- 使用 —- 表示新的yaml文件开始
YAML 支持的数据结构
对象
键值对的集合,又称为映射(mapping) / 哈希(hashes) / 字典(dictionary) ```go对象类型:对象的一组键值对,使用冒号结构表示
name: Tom age: 18
yaml 也允许另一种写法,将所有键值对写成一个行内对象
hash: {name: Tom, age: 18}
<a name="nLJI4"></a>
#### 数组
```go
# 数组类型:一组连词线开头的行,构成一个数组
People
- Tom
- Jack
# 数组也可以采用行内表示法
People: [Tom, Jack]
YAML文件组成部分
控制器的定义
被控制的对象
属性说明
如何快速编写YAML文件
一般来说,我们很少自己手写YAML文件,因为这里面涉及到了很多内容,我们一般都会借助工具来创建
使用kubectl create命令
这种方式一般用于资源没有部署的时候,我们可以直接创建一个YAML配置文件
# 尝试运行,并不会真正的创建镜像
kubectl create deployment web --image=nginx -o yaml --dry-run
或者我们可以输出到一个文件中kubectl create deployment web --image=nginx -o yaml --dry-run > hello.yaml
然后我们就在文件中直接修改即可
使用kubectl get命令导出yaml文件
可以首先查看一个目前已经部署的镜像kubectl get deploy
然后我们导出 nginx的配置kubectl get deploy nginx -o=yaml --export > nginx.yaml
然后会生成一个 nginx.yaml 的配置文件
Kubernetes核心技术Pod
Pod概述
Pod是K8S系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,也是在K8S上运行容器化应用的资源对象,其它的资源对象都是用来支撑或者扩展Pod对象功能的,比如控制器对象是用来管控Pod对象的,Service或者Ingress资源对象是用来暴露Pod引用对象的,PersistentVolume资源对象是用来为Pod提供存储等等,K8S不会直接处理容器,而是Pod,Pod是由一个或多个container组成。
Pod是Kubernetes的最重要概念,每一个Pod都有一个特殊的被称为 “根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。
Pod基本概念
- 最小部署的单元
- Pod里面是由一个或多个容器组成【一组容器的集合】
- 一个pod中的容器是共享网络命名空间
- Pod是短暂的
-
Pod存在的意义
创建容器使用docker,一个docker对应一个容器,一个容器运行一个应用进程
- Pod是多进程设计,运用多个应用程序,也就是一个Pod里面有多个容器,而一个容器里面运行一个应用程序
- Pod的存在是为了亲密性应用
- 两个应用之间进行交互
- 网络之间的调用【通过127.0.0.1 或 socket】
- 两个应用之间需要频繁调用
Pod是在K8S集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。同时Pod对多容器的支持是K8S中最基础的设计理念。在生产环境中,通常是由不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。
Pod是K8S集群中所有业务类型的基础,可以把Pod看作运行在K8S集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8S的业务主要可以分为以下几种
- 长期伺服型:long-running
- 批处理型:batch
- 节点后台支撑型:node-daemon
- 有状态应用型:stateful application
上述的几种类型,分别对应的小机器人控制器为:Deployment、Job、DaemonSet 和 StatefulSet (后面将介绍控制器)
Pod实现机制
主要有以下两大机制
- 共享网络
-
共享网络
容器本身之间相互隔离的,一般是通过 namespace 和 group 进行隔离,那么Pod里面的容器如何实现通信?
首先需要满足前提条件,也就是容器都在同一个namespace之间
关于Pod实现原理,首先会在Pod会创建一个根容器: pause容器,然后我们在创建业务容器 【nginx,redis 等】,在我们创建业务容器的时候,会把它添加到 info容器 中
而在 info容器 中会独立出 ip地址,mac地址,port 等信息,然后实现网络的共享
完整步骤如下
通过 Pause 容器,把其它业务容器加入到Pause容器里,让所有业务容器在同一个名称空间中,可以实现网络共享
共享存储
Pod持久化数据,专门存储到某个地方中
使用 Volumn数据卷进行共享存储,案例如下所示
Pod镜像拉取策略
我们以具体实例来说,拉取策略就是 imagePullPolicy
拉取策略主要分为了以下几种IfNotPresent:默认值,镜像在宿主机上不存在才拉取
- Always:每次创建Pod都会重新拉取一次镜像
-
Pod资源限制
也就是我们Pod在进行调度的时候,可以对调度的资源进行限制,例如我们限制 Pod调度是使用的资源是 2C4G,那么在调度对应的node节点时,只会占用对应的资源,对于不满足资源的节点,将不会进行调度
示例
我们在下面的地方进行资源的限制
这里分了两个部分 request:表示调度所需的资源
-
Pod重启机制
因为Pod中包含了很多个容器,假设某个容器出现问题了,那么就会触发Pod重启机制
重启策略主要分为以下三种 Always:当容器终止退出后,总是重启容器,默认策略 【nginx等,需要不断提供服务】
- OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
- Never:当容器终止退出,从不重启容器 【批量任务】
Pod健康检查
通过容器检查,原来我们使用下面的命令来检查kubectl get pod
但是有的时候,程序可能出现了 Java 堆内存溢出,程序还在运行,但是不能对外提供服务了,这个时候就不能通过 容器检查来判断服务是否可用了
这个时候就可以使用应用层面的检查 ```go存活检查,如果检查失败,将杀死容器,根据Pod的restartPolicy【重启策略】来操作
livenessProbe
就绪检查,如果检查失败,Kubernetes会把Pod从Service endpoints中剔除
readinessProbe
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655527884395-392e591e-99ae-4983-b790-bee81a648de0.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=453&id=ub477adb9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=610&originWidth=529&originalType=url&ratio=1&rotation=0&showTitle=false&size=87094&status=done&style=none&taskId=uf46fecba-0a48-4c2b-a8d0-d4a0ba31034&title=&width=393)<br />Probe支持以下三种检查方式
- http Get:发送HTTP请求,返回200 - 400 范围状态码为成功
- exec:执行Shell命令返回状态码是0为成功
- tcpSocket:发起TCP Socket建立成功
<a name="KszTf"></a>
### Pod调度策略
<a name="P2HVV"></a>
#### 创建Pod流程
- 首先创建一个pod,然后创建一个API Server 和 Etcd【把创建出来的信息存储在etcd中】
- 然后创建 Scheduler,监控API Server是否有新的Pod,如果有的话,会通过调度算法,把pod调度某个node上
- 在node节点,会通过 kubelet -- apiserver 读取etcd 拿到分配在当前node节点上的pod,然后通过docker创建容器
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655527946460-d77b06ab-6cea-458d-8461-76f251409b4b.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ue20caa5e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=651&originWidth=1146&originalType=url&ratio=1&rotation=0&showTitle=false&size=204348&status=done&style=none&taskId=u60bdcb7d-e44e-4705-8c53-f7df3fe61c3&title=)
<a name="X7vk3"></a>
### 影响Pod调度的属性
Pod资源限制对Pod的调度会有影响
<a name="BGqN7"></a>
#### 根据request找到足够node节点进行调度
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655527986801-ac808a32-030c-434b-81e8-ed09b8f14b62.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=449&id=ud4d83ac9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=530&originWidth=484&originalType=url&ratio=1&rotation=0&showTitle=false&size=63040&status=done&style=none&taskId=ue1039cb6-3941-41ec-a4c2-fa2aa92b5a6&title=&width=410)
<a name="HsXwQ"></a>
#### 节点选择器标签影响Pod调度
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528004415-f2097bd3-f452-4ff7-8c86-ee4a0fea3756.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u1e0bf727&margin=%5Bobject%20Object%5D&name=image.png&originHeight=333&originWidth=482&originalType=url&ratio=1&rotation=0&showTitle=false&size=143208&status=done&style=none&taskId=u30a8ffc7-0252-485b-8996-f1c9d520fb1&title=)<br />关于节点选择器,其实就是有两个环境,然后环境之间所用的资源配置不同<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528015330-44667ec7-a18f-4eec-91f7-01a8a1a89241.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ucb810ff3&margin=%5Bobject%20Object%5D&name=image.png&originHeight=481&originWidth=1276&originalType=url&ratio=1&rotation=0&showTitle=false&size=78976&status=done&style=none&taskId=u04665697-9798-40a6-9947-5fccaf84bcc&title=)<br />我们可以通过以下命令,给我们的节点新增标签,然后节点选择器就会进行调度了<br />`kubectl label node node1 env_role=prod`
<a name="pEJRP"></a>
#### 节点亲和性
节点亲和性 **nodeAffinity** 和 之前nodeSelector 基本一样的,根据节点上标签约束来决定Pod调度到哪些节点上
- 硬亲和性:约束条件必须满足
- 软亲和性:尝试满足,不保证
![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528063924-cb512197-a642-4796-b6be-c997d6b13be9.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u102a17b4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=632&originWidth=1341&originalType=url&ratio=1&rotation=0&showTitle=false&size=323190&status=done&style=none&taskId=ua0029d07-431d-462c-8c35-5d6227508d1&title=)<br />支持常用操作符:in、NotIn、Exists、Gt、Lt、DoesNotExists<br />反亲和性:就是和亲和性刚刚相反,如 NotIn、DoesNotExists等
<a name="mX2lX"></a>
### 污点和污点容忍
<a name="Eu578"></a>
#### 概述
nodeSelector 和 NodeAffinity,都是Prod调度到某些节点上,属于Pod的属性,是在调度的时候实现的。<br />Taint 污点:节点不做普通分配调度,是节点属性
<a name="mcPNW"></a>
#### 场景
- 专用节点【限制ip】
- 配置特定硬件的节点【固态硬盘】
- 基于Taint驱逐【在node1不放,在node2放】
<a name="tlmcW"></a>
#### 查看污点情况
`kubectl describe node k8smaster | grep Taint`<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528170718-ec6c145b-8c86-439f-9141-6ac47c27c07b.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u0734ecbe&margin=%5Bobject%20Object%5D&name=image.png&originHeight=52&originWidth=487&originalType=url&ratio=1&rotation=0&showTitle=false&size=5652&status=done&style=none&taskId=u72f54703-3f67-4950-b560-bf2237b084f&title=)<br />污点值有三个
- NoSchedule:一定不被调度
- PreferNoSchedule:尽量不被调度【也有被调度的几率】
- NoExecute:不会调度,并且还会驱逐Node已有Pod
<a name="U1END"></a>
#### 未节点添加污点
`kubectl taint node [node] key=value:污点的三个值`<br />举例:<br />`kubectl taint node k8snode1 env_role=yes:NoSchedule`
<a name="w4I6Q"></a>
#### 删除污点
`kubectl taint node k8snode1 env_role:NoSchedule-`<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528242425-60510d72-4d4c-464a-8fb5-8589cf67a321.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u4ab18098&margin=%5Bobject%20Object%5D&name=image.png&originHeight=104&originWidth=590&originalType=url&ratio=1&rotation=0&showTitle=false&size=12013&status=done&style=none&taskId=u9612c9fd-f325-4842-b4b5-1062ed2b79e&title=)
<a name="gYOM9"></a>
#### 演示
我们现在创建多个Pod,查看最后分配到Node上的情况<br />首先我们创建一个 nginx 的pod<br />`kubectl create deployment web --image=nginx`<br />然后使用命令查看<br />`kubectl get pods -o wide`<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528304447-6ad5cb4e-530c-4be5-b0a5-300d894a9af4.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u39d78f12&margin=%5Bobject%20Object%5D&name=image.png&originHeight=64&originWidth=875&originalType=url&ratio=1&rotation=0&showTitle=false&size=8692&status=done&style=none&taskId=ud549303b-a121-43ec-8538-17b5b260488&title=)<br />我们可以非常明显的看到,这个Pod已经被分配到 k8snode1 节点上了<br />下面我们把pod复制5份,在查看情况pod情况<br />`kubectl scale deployment web --replicas=5`<br />我们可以发现,因为master节点存在污点的情况,所以节点都被分配到了 node1 和 node2节点上<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528329318-976d8956-6004-4812-8eb7-c2e635448d5e.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u280e0c22&margin=%5Bobject%20Object%5D&name=image.png&originHeight=127&originWidth=970&originalType=url&ratio=1&rotation=0&showTitle=false&size=20160&status=done&style=none&taskId=u6df9e8ce-7b16-4ad5-93e3-0e44b55ad71&title=)<br />我们可以使用下面命令,把刚刚我们创建的pod都删除<br />`kubectl delete deployment web`<br />现在给了更好的演示污点的用法,我们现在给 node1节点打上污点<br />`kubectl taint node k8snode1 env_role=yes:NoSchedule`<br />然后我们查看污点是否成功添加<br />`kubectl describe node k8snode1 | grep Taint`<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25888738/1655528355938-4f103686-1b72-44dc-ab28-6da3f367b02a.png#clientId=u215553ff-0a6a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u1bc08b07&margin=%5Bobject%20Object%5D&name=image.png&originHeight=59&originWidth=521&originalType=url&ratio=1&rotation=0&showTitle=false&size=5570&status=done&style=none&taskId=uc0ede11d-44d1-4d9d-9d93-ebb8f40ff94&title=)<br />然后我们在创建一个 pod
```go
# 创建nginx pod
kubectl create deployment web --image=nginx
# 复制五次
kubectl scale deployment web --replicas=5
然后我们在进行查看kubectl get pods -o wide
我们能够看到现在所有的pod都被分配到了 k8snode2上,因为刚刚我们给node1节点设置了污点
最后我们可以删除刚刚添加的污点kubectl taint node k8snode1 env_role:NoSchedule-