Kubernetes1.18学习笔记
一、Kubernetes 概述和架构
1、kubernetes 基本介绍
kubernetes,简称K8s,是用8 代替8 个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署,规划,更新,维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的
- K8s是谷歌在2014年发布的容器化集群管理系统
- 使用k8s进行容器化应用部署
- 使用k8s利于应用扩展
- k8s目标实施让部署容器化应用更加简洁和高效
2、Kubernetes 功能
- 自动装箱
- 基于容器对应用运行环境的资源配置要求自动部署应用容器
- 自我修复
- 当容器失败时,会对容器进行重启
- 当所部署的 Node 节点有问题时,会对容器进行重新部署和重新调度
- 当容器未通过监控检查时,会关闭此容器直到容器正常运行时,才会对外提供服务
- 水平扩展
- 通过简单的命令、用户 UI 界面或基于 CPU 等资源使用情况,对应用容器进行规模扩大或规模剪裁
- 当我们有大量的请求来临时,我们可以增加副本数量,从而达到水平扩展的效果
- 服务发现
- 用户不需使用额外的服务发现机制,就能够基于 Kubernetes 自身能力实现服务发现和负载均衡
- 滚动更新
- 可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新
- 版本回退
- 可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退
- 密钥和配置管理
- 在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
- 存储编排
- 自动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要
- 存储系统可以来自于本地目录、网络存储 (NFS、Gluster、Ceph 等)、公共云存储服务
- 批处理
- 提供一次性任务,定时任务;满足批量数据处理和分析的场景
3、Kubernetes 架构组件
Master:主控节点
- API Server:集群统一入口,以 restful 风格进行操作,同时交给 etcd 存储
- 提供认证、授权、访问控制、API 注册和发现等机制
- scheduler:节点的调度,选择 node 节点应用部署
- controller-manager:处理集群中常规后台任务,一个资源对应一个控制器
- etcd:存储系统,用于保存集群中的相关数据
Worker node:工作节点
- Kubelet:master 派到 node 节点代表,管理本机容器
- 一个集群中每个节点上运行的代理,它保证容器都运行在 Pod 中
- 负责维护容器的生命周期,同时也负责 Volume(CSI) 和 网络 (CNI) 的管理
- kube-proxy:提供网络代理,负载均衡等操作
容器运行环境【Container Runtime】
- 容器运行环境是负责运行容器的软件
- Kubernetes 支持多个容器运行环境:Docker、containerd、cri-o、rktlet 以及任何实现 Kubernetes CRI (容器运行环境接口) 的软件。
fluentd:是一个守护进程,它有助于提升集群层面日志
4、Kubernetes 核心概念
Pod
- Pod 是 K8s 中最小的单元
- 一组容器的集合
- 共享网络【一个 Pod 中的所有容器共享同一网络】
- 生命周期是短暂的(服务器重启后,就找不到了)
Volume
- 声明在 Pod 容器中可访问的文件目录
- 可以被挂载到 Pod 中一个或多个容器指定路径下
- 支持多种后端存储抽象【本地存储、分布式存储、云存储】
Controller
- 确保预期的 pod 副本数量【ReplicaSet】
- 无状态应用部署【Deployment】
- 无状态就是指,不需要依赖于网络或者 ip
- 有状态应用部署【StatefulSet】
- 有状态需要特定的条件
- 确保所有的 node 运行同一个 pod 【DaemonSet】
- 一次性任务和定时任务【Job 和 CronJob】
Deployment
- 定义一组 Pod 副本数目,版本等
- 通过控制器【Controller】维持 Pod 数目【自动回复失败的 Pod】
- 通过控制器以指定的策略控制版本【滚动升级、回滚等】
Service
- 定义一组 pod 的访问规则
- Pod 的负载均衡,提供一个或多个 Pod 的稳定访问地址
- 支持多种方式【ClusterIP、NodePort、LoadBalancer】
Label
- label:标签,用于对象资源查询,筛选
Namespace
- 命名空间,逻辑隔离
- 一个集群内部的逻辑隔离机制【鉴权、资源】
- 每个资源都属于一个 namespace
- 同一个 namespace 所有资源不能重复
- 不同 namespace 可以资源名重复
API
- 我们通过 Kubernetes 的 API 来操作整个集群
- 同时我们可以通过 kubectl 、ui、curl 最终发送 http + json/yaml 方式的请求给 API Server,然后控制整个 K8S 集群,K8S 中所有的资源对象都可以采用 yaml 或 json 格式的文件定义或描述
5、Kubernetes 工作原理
二、Kubernetes 集群搭建
1、系统环境准备
1.1 安装要求
在开始之前,部署 Kubernetes 集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 30GB 或更多【注意】【master 需要两核】
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止 swap 分区
1.2 系统初始化
1 | # 关闭防火墙 |
还可以设置一下静态ip(cat /etc/sysconfig/network-scripts/ifcfg-ens33
),以及开机自启网卡(可以使用DHCP,不影响),网段可以在虚拟网络编辑器进行编辑
1 | TYPE="Ethernet" |
网络设置完毕后需要重启systemctl restart network
,重启完网络服务后ip地址已经发生了改变,此时FinalShell已经连接不上Linux系统,需要创建一个新连接才能连接到Linux
2、客户端工具kubeadm搭建
2.1 安装步骤
kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具。这个工具能通过两条指令完成一个 kubernetes 集群的部署
官方参考:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
- 【环境准备】准备三台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对三个刚安装好的操作系统进行初始化操作
- 【安装工具】在三个节点安装
docker
kubelet
kubeadm
kubectl
- 【集群部署-master】在 master 节点执行
kubeadm init
命令初始化 - 【集群部署-node】在 node 节点上执行
kubeadm join
命令,把 node 节点添加到当前集群 - 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
1 | # 创建一个 Master 节点 |
2.2 安装组件
【所有节点】需要安装以下组件 ,Kubernetes 默认 CRI(容器运行时)为 Docker,因此先安装 Docker,其他操作见上面的系统初始化
- Docker
- kubeadm
- kubelet
- kubectl
1 | # ===========================安装docker============================= |
2.3 集群部署
1 | # master节点执行 |
2.4 部署 CNI 网络插件
上面的状态还是 NotReady,下面我们需要网络插件,来进行联网访问;网络插件有两种:flannel和calico
1 | # 下载网络插件配置 |
手动导入yaml文件后通过查看日志发现镜像无法拉取,于是手动拉取导入,然后用tag打上与yml文件中的镜像一模一样的名字,这里我每个结点都是这样操作(按理说会自动同步过去其他结点,但是每个结点都报错了,所以我手动下载了;当然换个国内源也可以)
1 | # 下载地址 |
2.5 测试集群
在 Kubernetes 集群中创建一个 pod,验证是否正常运行
1 | # 下载 nginx 【会联网拉取 nginx 镜像】 |
3、二进制方式搭建
参考:https://blog.csdn.net/qq_40942490/article/details/114022294
3.1 安装步骤
- 【环境准备】准备三台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对三个刚安装好的操作系统进行初始化操作
- 【部署 etcd 集群】对三个节点安装 etcd
- 【安装 Docker】对三个节点安装 docker
- 【部署 mastber 组件】在 master 节点上安装
kube-apiserver
、kube-controller-manager
、kube-scheduler
- 【部署 node 组件】在 node 节点上安装
kubelet
、kube-proxy
- 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
3.2 部署 etcd(主节点)
服务器初始化见上面,这里首先签发证书,让服务器能够正常访问,需要为 etcd 和 apiserver 自签证书
1 | # 为 etcd 和 apiserver 自签证书【k8smaster 节点操作】 |
1 | # 下载二进制文件 |
创建配置文件,注意ip地址改成自己的
1 | cat > /opt/etcd/cfg/etcd.conf << EOF |
创建 etcd.service:
1 | cat > /usr/lib/systemd/system/etcd.service << EOF |
转发 etcd 到 node 节点【k8smaster 节点上操作】【需要输入密码,建议密码设置简单一点】
1 | ###### 转发到 k8snode1 ###### |
启动并设置开机启动:【k8snode1 和 k8snode2 均需一起启动】
1 | systemctl daemon-reload |
3.3 安装 docker
在所有节点操作。这里采用二进制安装,用 yum 安装也一样 (多台节点安装可以采用键盘工具)
1 | cd ~/TLS |
3.4 部署 master 组件
- kube-apiserver
- kuber-controller-manager
- kube-scheduler
首先进行apiserver自签证书(添加可信任ip列表方式)
1 | # 【生成 kube-apiserver 证书】 |
安装 kube-apiserver
1 | # 下载二进制包 |
部署 kube-controller-manager
1 | cat > /opt/kubernetes/cfg/kube-controller-manager.conf << EOF |
部署 kube-scheduler
1 | cat > /opt/kubernetes/cfg/kube-scheduler.conf << EOF |
3.5 部署node组件
- kubelet
- kube-proxy
安装 kubelet
1 | ##### k8snode1 节点上操作,注意修改集群的名字,不要重复(这里的m1) ##### |
部署 kube-proxy
1 | # 以下在node1和node2创建 |
3.6 部署 CNI 网络插件
1 | # node结点操作,下载 CNI 网络插件 |
3.7 测试 kubernetes 集群
1 | # 下载 nginx 【会联网拉取 nginx 镜像】 |
4、两种方式搭建集群的对比
4.1 Kubeadm 方式搭建 K8S 集群
- 安装虚拟机,在虚拟机安装 Linux 操作系统【3 台虚拟机】
- 对操作系统初始化操作
- 所有节点安装 Docker、kubeadm、kubelet、kubectl【包含 master 和 node 节点】
- 安装 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 节点上
- 测试 kubernetes 集群
4.2 二进制方式搭建 K8S 集群
- 安装虚拟机和操作系统,对操作系统进行初始化操作
- 生成 cfssl 自签证书
ca-key.pem
、ca.pem
server-key.pem
、server.pem
- 部署 Etcd 集群
- 部署的本质,就是把 etcd 集群交给 systemd 管理
- 把生成的证书复制过来,启动,设置开机启动
- 安装 Docker
- 部署 master 组件,主要包含以下组件
- apiserver
- controller-manager
- scheduler
- 交给 systemd 管理,并设置开机启动
- 如果要安装最新的 1.19 版本,下载二进制文件进行安装
- 部署 node 组件
- kubelet
- kube-proxy【需要批准 kubelet 证书申请加入集群】
- 交给 systemd 管理组件- 组件启动,设置开机启动
- 批准 kubelet 证书申请 并加入集群
- 部署 CNI 网络插件
- 测试 Kubernets 集群【安装 nginx 测试】
5、可视化安装
5.1 Kuboard v3 - kubernetes(推荐)
1 | # 安装 Kuboard |
docker的安装方式
1 | # https://hub.docker.com/r/eipwork/kuboard/tags 可以查看最新版本号 |
在浏览器输入 192.168.249.139
即可访问 Kuboard 的界面,登录方式:用户名:admin/密 码:Kuboard123
5.2 Kubernetes Dashboard
Kubernetes Dashboard 是 Kubernetes 的官方 Web UI。使用 Kubernetes Dashboard可以
- 向 Kubernetes 集群部署容器化应用
- 诊断容器化应用的问题
- 管理集群的资源
- 查看集群上所运行的应用程序
- 创建、修改Kubernetes 上的资源(例如 Deployment、Job、DaemonSet等)
- 展示集群上发生的错误
1 | # 安装 Kubernetes Dashboard |
另一种方法,kubernetes官方提供的可视化界面https://github.com/kubernetes/dashboard
1 | # 先自己下载下来 |
1 | #创建访问账号,准备一个yaml文件; vi dash.yaml |
5.3 k8slens IDE(推荐)
三、Kubernetes 核心概念(基础)
1、集群命令行工具 kubectl
1.1 kubectl 概述
kubectl 是 Kubernetes 集群的命令行工具,通过 kubectl 能够对集群本身进行管理,并能够在集群上进行容器化应用的安装和部署
1.2 kubectl 命令格式
1 | kubectl [command] [type] [name] [flags] |
举例常用命令
1 | # 部署应用 |
1.3 kubectl 基础命令
命令 | 介绍 |
---|---|
create | 通过文件名或标准输入创建资源 |
expose | 将一个资源公开为一个新的 Service |
run | 在集群中运行一个特定的镜像 |
set | 在对象上设置特定的功能 |
get | 显示一个或多个资源 |
explain | 文档参考资料 |
edit | 使用默认的编辑器编辑一个资源 |
delete | 通过文件名,标准输入,资源名称或标签来删除资源 |
1.4 kubectl 部署命令
命令 | 介绍 |
---|---|
rollout | 管理资源的发布 |
rolling-update | 对给定的复制控制器滚动更新 |
scale | 扩容或缩容 Pod 数量,Deployment、ReplicaSet、RC 或 Job |
autoscale | 创建一个自动选择扩容或缩容并设置 Pod 数量 |
1.5 kubectl 集群管理命令
命令 | 介绍 |
---|---|
certificate | 修改证书资源 |
cluster-info | 显示集群信息 |
top | 显示资源 (CPU/M) |
cordon | 标记节点不可调度 |
uncordon | 标记节点可被调度 |
drain | 驱逐节点上的应用,准备下线维护 |
taint | 修改节点 taint 标记 |
1.6 kubectl 故障和调试命令
命令 | 介绍 |
---|---|
describe | 显示特定资源或资源组的详细信息 |
logs | 在一个 Pod 中打印一个容器日志,如果 Pod 只有一个容器,容器名称是可选的 |
attach | 附加到一个运行的容器 |
exec | 执行命令到容器 |
port-forward | 转发一个或多个 |
proxy | 运行一个 proxy 到 Kubernetes API Server |
cp | 拷贝文件或目录到容器中 |
auth | 检查授权 |
1.7 kubectl 其它命令
命令 | 介绍 |
---|---|
apply | 通过文件名或标准输入对资源应用配置 |
patch | 使用补丁修改、更新资源的字段 |
replace | 通过文件名或标准输入替换一个资源 |
convert | 不同的 API 版本之间转换配置文件 |
label | 更新资源上的标签 |
annotate | 更新资源上的注释 |
completion | 用于实现 kubectl 工具自动补全 |
api-versions | 打印受支持的 API 版本 |
config | 修改 kubeconfig 文件(用于访问 API,比如配置认证信息) |
help | 所有命令帮助 |
plugin | 运行一个命令行插件 |
version | 打印客户端和服务版本信息 |
2、YAML 文件详解
参考:YAML 入门教程
2.1 YAML 概述
- YAML 文件 : 就是资源清单文件,用于资源编排
- YAML : 仍是一种标记语言。为了强调这种语言以数据做为中心,而不是以标记语言为重点
- YAML : 是一个可读性高,用来表达数据序列的格式
2.2 基础语法
- 使用空格做为缩进
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 低版本缩进时不允许使用 Tab 键,只允许使用空格
- 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
- 使用 — 表示新的 yaml 文件开始
2.3 YAML 数据结构
1 | # 对象类型:对象的一组键值对,使用冒号结构表示 |
2.4 组成部分
主要分为了两部分,一个是控制器的定义和被控制的对象。在一个 YAML 文件的控制器定义中,有很多属性名称
属性名称 | 介绍 |
---|---|
apiVersion | API 版本 |
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数量 |
selector | 标签选择器 |
template | Pod 模板 |
metadata | Pod 元数据 |
spec | Pod 规格 |
containers | 容器配置 |
2.5 快速编写
一般来说,我们很少自己手写 YAML 文件,因为这里面涉及到了很多内容,我们一般都会借助工具来创建
1 | # 尝试运行,并不会真正的创建镜像 |
3、Pod
参考:https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/pod-v1/
3.1 Pod概述
基本概念
- 最小部署的单元
- Pod 里面是由一个或多个容器组成【一组容器的集合】
- 一个 pod 中的容器是共享网络命名空间
- Pod 是短暂的
- 每个 Pod 包含一个或多个紧密相关的用户业务容器
Pod 存在的意义
- 创建容器使用 docker,一个 docker 对应一个容器,一个容器运行一个应用进程
- Pod 是多进程设计,运用多个应用程序,也就是一个 Pod 里面有多个容器,而一个容器里面运行一个应用程序
- Pod 的存在是为了亲密性应用
- 两个应用之间进行交互
- 网络之间的调用【通过 127.0.0.1 或 socket】
- 两个应用之间需要频繁调用
3.2 Pod 实现机制
Pod 主要有以下两大机制:共享网络 和 共享存储
- 共享网络【容器通过 namespace 和 group 进行隔离】,Pod 中容器通信 过程:
- 同一个 namespace 下
- 在 Pod 中创建一个根容器:
pause 容器
- 在 Pod 中创建业务容器 【nginx,redis 等】【创建时会添加到
info 容器
中】 - 在
info 容器
中会独立出 ip 地址,mac 地址,port 等信息,然后实现网络的共享
- 共享存储【Pod 持久化数据,专门存储到某个地方中,使用 Volumn 数据卷进行共享存储】
3.3 Pod 镜像拉取策略
拉取策略就是 imagePullPolicy
,有以下几个值
IfNotPresent
:默认值,镜像在宿主机上不存在才拉取Always
:每次创建 Pod 都会重新拉取一次镜像Never
:Pod 永远不会主动拉取这个镜像
3.4 Pod 资源限制
Pod 在进行调度的时候,可以对调度的资源进行限制,例如我们限制 Pod 调度是使用的资源是 2C4G,那么在调度对应的 node 节点时,只会占用对应的资源,对于不满足资源的节点,将不会进行调度。
这里分了两个部分:
request
:表示调度所需的资源limits
:表示最大所占用的资源
1 | sepc: |
3.5 Pod 重启机制
因为 Pod 中包含了很多个容器,假设某个容器出现问题了,那么就会触发 Pod 重启机制
restartPolicy重启策略主要分为以下三种:
Always
:当容器终止退出后,总是重启容器,默认策略 【nginx 等,需要不断提供服务】OnFailure
:当容器异常退出(退出状态码非 0)时,才重启容器。Never
:当容器终止退出,从不重启容器 【批量任务】
3.6 Pod 健康检查
1 | # 通过容器检查 |
Probe 支持以下三种检查方式
http Get
:发送 HTTP 请求,返回 200 - 400 范围状态码为成功exec
:执行 Shell 命令返回状态码是 0 为成功tcpSocket
:发起 TCP Socket 建立成功
3.7 Pod 调度策略
- 首先创建一个 pod,然后创建一个 API Server 和 Etcd【把创建出来的信息存储在 etcd 中】
- 然后创建 Scheduler,监控 API Server 是否有新的 Pod,如果有的话,会通过调度算法,把 pod 调度某个 node 上
- 在 node 节点,会通过
kubelet -- apiserver
读取 etcd 拿到分配在当前 node 节点上的 pod,然后通过 docker 创建容器
Pod资源限制对Pod的调度会有影响,节点选择器标签影响Pod调度,如果不满足就不会在该结点运行
1 | # 给我们的节点新增标签 |
节点亲和性 nodeAffinity (比选择器更强)和 之前nodeSelector 基本一样的,根据节点上标签约束来决定Pod调度到哪些节点上
- 硬亲和性:约束条件必须满足
- 软亲和性:尝试满足,不保证
支持常用操作符:in、NotIn、Exists、Gt、Lt、DoesNotExists
反亲和性:就是和亲和性刚刚相反,如 NotIn、DoesNotExists等
1 | apiVersion: v1 # api版本 |
3.8 污点和污点容忍
nodeSelector 和 NodeAffinity,都是Prod调度到某些节点上,属于Pod的属性,是在调度的时候实现的。Taint 污点:节点不做普通分配调度,是节点属性;污点容忍就是某个节点可能被调度,也可能不被调度
使用场景
- 专用节点【限制ip】
- 配置特定硬件的节点【固态硬盘】
- 基于Taint驱逐【在node1不放,在node2放】
污点值:
- NoSchedule:一定不被调度
- PreferNoSchedule:尽量不被调度【也有被调度的几率】
- NoExecute:不会调度,并且还会驱逐Node已有Pod
1 | # 查看节点污点 |
4、Controller之Deployment
4.1 Controller 简介
Controller 是集群上管理和运行容器的对象
- Controller 是实际存在的
- Pod 是虚拟机的
Pod 是通过 Controller 实现应用的运维,比如弹性收缩,滚动升级。Pod 和 Controller 之间是通过 label 标签建立关系,同时 Controller 又被称为控制器工作负载。
- Controller【控制器】【工作负载】
selector: app:nginx
- Pod【容器】
labels: app:nginx
4.2 Deployment控制器应用
- Deployment控制器可以部署无状态应用
- 管理Pod和ReplicaSet
- 部署,滚动升级等功能
- 应用场景:web服务,微服务
Deployment表示用户对K8S集群的一次更新操作。Deployment是一个比RS( Replica Set, RS) 应用模型更广的 API 对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧RS中的副本数减少到0的复合操作。这样一个复合操作用一个RS是不好描述的,所以用一个更通用的Deployment来描述。以K8S的发展方向,未来对所有长期伺服型的业务的管理,都会通过Deployment来管理
4.3 Deployment 部署应用
1 | # 使用 Deploment 部署应用,代码如下:【缺点:代码不好复用】 |
举例
1 | apiVersion: apps/v1 #指定api版本标签】 |
4.4 升级回滚和弹性收缩
- 升级: 假设从版本为 1.14 升级到 1.15 ,这就叫应用的升级【升级可以保证服务不中断】
- 回滚:从版本 1.15 变成 1.14,这就叫应用的回滚
- 弹性伸缩:我们根据不同的业务场景,来改变 Pod 的数量对外提供服务,这就是弹性伸缩
1 | # 应用升级 |
5、Service
文档参考:https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#headless-services
5.1 service概述
前面我们了解到 Deployment 只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。一个Pod只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务。
要稳定地提供服务需要服务发现和负载均衡能力。服务发现完成的工作,是针对客户端访问的服务,找到对应的后端服务实例。在K8S集群中,客户端需要访问的服务就是Service对象。每个Service会对应一个集群内部有效的虚拟IP,集群内部通过虚拟IP访问一个服务。在K8S集群中,微服务的负载均衡是由kube-proxy实现的。kube-proxy是k8s集群内部的负载均衡器。它是一个分布式代理服务器,在K8S的每个节点上都有一个;这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的kube-proxy就越多,高可用节点也随之增多。与之相比,我们平时在服务器端使用反向代理作负载均衡,还要进一步解决反向代理的高可用问题。
5.2 Service存在的意义
-
防止Pod失联【服务发现】
因为Pod每次创建都对应一个IP地址,而这个IP地址是短暂的,每次随着Pod的更新都会变化,假设当我们的前端页面有多个Pod时候,同时后端也多个Pod,这个时候,他们之间的相互访问,就需要通过注册中心,拿到Pod的IP地址,然后去访问对应的Pod
-
定义Pod访问策略【负载均衡】
页面前端的Pod访问到后端的Pod,中间会通过Service一层,而Service在这里还能做负载均衡,负载均衡的策略有很多种实现策略,例如:
- 随机
- 轮询
- 响应比
5.3 Pod和Service的关系
这里Pod 和 Service 之间还是根据 label 和 selector 建立关联的 【和Controller一样】,我们在访问service的时候,其实也是需要有一个ip地址,这个ip肯定不是pod的ip地址,而是 虚拟IP vip
5.4 Service常用类型
- ClusterIp:集群内部访问
- NodePort:对外访问应用使用
- LoadBalancer:对外访问应用使用,公有云
1 | kubectl expose deployment nginx --port=80 --target-port=80 --dry-run -o yaml > service.yaml |
如果我们没有做设置的话,默认使用的是第一种方式 ClusterIp,也就是只能在集群内部使用,我们可以添加一个type字段,用来设置我们的service类型
1 | apiVersion: v1 |
运行后能够看到,已经成功修改为 NodePort类型了,最后剩下的一种方式就是LoadBalanced:对外访问应用使用公有云,node一般是在内网进行部署,而外网一般是不能访问到的,那么如何访问的呢?
- 找到一台可以通过外网访问机器,安装nginx,反向代理
- 手动把可以访问的节点添加到nginx中
如果我们使用LoadBalancer,就会有负载均衡的控制器,类似于nginx的功能,就不需要自己添加到nginx上
6、Controller之Statefulset
6.1 Statefulset概述
Statefulset主要是用来部署有状态应用。对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。
前面我们部署的应用,都是不需要存储数据,不需要记住状态的,可以随意扩充副本,每个副本都是一样的,可替代的。 而像数据库、Redis 这类有状态的,则不能随意扩充副本。StatefulSet 会固定每个 Pod 的名字,具有以下特性
- Service 的
CLUSTER-IP
是空的,Pod 名字也是固定的。 - Pod 创建和销毁是有序的,创建是顺序的,销毁是逆序的。
- Pod 重建不会改变名字,除了IP,所以不要用IP直连
6.2 无状态和有状态容器
无状态应用,我们原来使用 deployment,部署的都是无状态的应用
- 认为Pod都是一样的
- 没有顺序要求
- 不考虑应用在哪个node上运行
- 能够进行随意伸缩和扩展
有状态应用,上述的因素都需要考虑到
- 每个Pod独立的,保持Pod启动顺序和唯一性
- 唯一的网络标识符,持久存储
- 有序,比如mysql中的主从
适合StatefulSet的业务包括数据库服务MySQL 和 PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务。StatefulSet的另一种典型应用场景是作为一种比普通容器更稳定可靠的模拟虚拟机的机制。传统的虚拟机正是一种有状态的宠物,运维人员需要不断地维护它,容器刚开始流行时,我们用容器来模拟虚拟机使用,所有状态都保存在容器里,而这已被证明是非常不安全、不可靠的。
使用StatefulSet,Pod仍然可以通过漂移到不同节点提供高可用,而存储也可以通过外挂的存储来提供 高可靠性,StatefulSet做的只是将确定的Pod与确定的存储关联起来保证状态的连续性
6.3 部署有状态应用
无头service, ClusterIp:none。这里就需要使用 StatefulSet部署有状态应用
1 | apiVersion: v1 |
然后通过查看pod,能否发现每个pod都有唯一的名称;然后我们在查看service,发现是无头的service
这里有状态的约定,肯定不是简简单单通过名称来进行约定,而是更加复杂的操作
- deployment:是有身份的,有唯一标识
- statefulset:根据主机名 + 按照一定规则生成域名
每个pod有唯一的主机名,并且有唯一的域名
- 格式:主机名称.service名称.名称空间.svc.cluster.local
- 举例:nginx-statefulset-0.default.svc.cluster.local
7、Controller之其他应用
7.1 DaemonSet
DaemonSet 即后台支撑型服务,主要是用来部署守护进程
长期伺服型和批处理型的核心在业务应用,可能有些节点运行多个同类业务的Pod,有些节点上又没有这类的Pod运行;而后台支撑型服务的核心关注点在K8S集群中的节点(物理机或虚拟机),要保证每个节点上都有一个此类Pod运行。节点可能是所有集群节点,也可能是通过 nodeSelector选定的一些特定节点。典型的后台支撑型服务包括:存储、日志和监控等。在每个节点上支撑K8S集群运行的服务。
守护进程在我们每个节点上,运行的是同一个pod,新加入的节点也同样运行在同一个pod里面
1 | apiVersion: apps/v1 |
1 | kubectl apply -f daemon.yaml |
7.2 Job和CronJob
- 一次性任务:一次性执行完就结束
- 定时任务:周期性执行
Job是K8S中用来控制批处理型任务的API对象。批处理业务与长期伺服业务的主要区别就是批处理业务的运行有头有尾,而长期伺服业务在用户不停止的情况下永远运行。Job管理的Pod根据用户的设置把任务成功完成就自动退出了。成功完成的标志根据不同的 spec.completions 策略而不同:单Pod型任务有一个Pod成功就标志完成;定数成功行任务保证有N个任务全部成功;工作队列性任务根据应用确定的全局成功而标志成功。
1 | # job的yaml文件 |
命令操作
1 | # 能够看到目前已经存在的Job |
7.3 Replication Controller
Replication Controller 简称 RC,是K8S中的复制控制器。RC是K8S集群中最早的保证Pod高可用的API对象。通过监控运行中的Pod来保证集群中运行指定数目的Pod副本。指定的数目可以是多个也可以是1个;少于指定数目,RC就会启动新的Pod副本;多于指定数目,RC就会杀死多余的Pod副本。即使在指定数目为1的情况下,通过RC运行Pod也比直接运行Pod更明智,因为RC也可以发挥它高可用的能力,保证永远有一个Pod在运行。RC是K8S中较早期的技术概念,只适用于长期伺服型的业务类型,比如控制Pod提供高可用的Web服务。
Replica Set 检查 RS,也就是副本集。RS是新一代的RC,提供同样高可用能力,区别主要在于RS后来居上,能够支持更多种类的匹配模式。副本集对象一般不单独使用,而是作为Deployment的理想状态参数来使用
四、Kubernetes 核心概念(进阶)
1、Kubernetes配置管理
1.1 Secret
参考文档:https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/
Secret的主要作用就是加密数据,然后存在etcd里面,让Pod容器以挂载Volume方式进行访问,一般场景的是对某个字符串进行base64编码 进行加密
- 场景:用户名 和 密码进行加密
密码文件举例
1 | apiVersion: v1 |
变量形式挂载到Pod
1 | echo -n 'admin' | base64 |
然后可以将密码文件挂载到pod,注意名字和key要和密码文件一一对应
1 | apiVersion: v1 |
数据卷形式挂载
1 | # 根据配置创建容器 |
修改secret-val.yaml文件
1 | apiVersion: v1 |
举例docker密钥的保存
1 | ##命令格式 |
1.2 ConfigMap
参考文档:https://kubernetes.io/zh/docs/concepts/configuration/configmap/
ConfigMap作用是存储不加密的数据到etcd中,让Pod以变量或数据卷Volume挂载到容器中;应用场景:配置文件
首先我们需要创建一个配置文件 redis.properties
1 | redis.port=127.0.0.1 |
我们使用命令创建configmap
1 | kubectl create configmap redis-config --from-file=redis.properties |
Volume数据卷形式挂载
1 | apiVersion: v1 |
以redis举例,可以抽取应用配置,并且可以自动更新;修改了CM,Pod里面的配置文件会跟着变,但要用需要重启redis
1 | apiVersion: v1 |
以变量的形式挂载Pod
1 | apiVersion: v1 |
命令
1 | # 创建pod |
然后创建可以挂载的Pod
1 | apiVersion: v1 |
2、Kubernetes集群安全机制
2.1 概述
当我们访问K8S集群时,需要经过三个步骤完成具体操作
- 认证
- 鉴权【授权】
- 准入控制
进行访问的时候,都需要经过 apiserver, apiserver做统一协调,比如门卫
- 访问过程中,需要证书、token、或者用户名和密码
- 如果访问pod需要serviceAccount
认证
对外不暴露8080端口,只能内部访问,对外使用的端口6443,客户端身份认证常用方式
- https证书认证,基于ca证书
- http token认证,通过token来识别用户
- http基本认证,用户名 + 密码认证
鉴权
基于RBAC进行鉴权操作;基于角色访问控制
准入控制
就是准入控制器的列表,如果列表有请求内容就通过,没有的话 就拒绝
2.2 RBAC介绍
基于角色的访问控制,为某个角色设置访问内容,然后用户分配该角色后,就拥有该角色的访问权限
k8s中有默认的几个角色
- role:特定命名空间访问权限
- ClusterRole:所有命名空间的访问权限
角色绑定
- roleBinding:角色绑定到主体
- ClusterRoleBinding:集群角色绑定到主体
主体
- user:用户
- group:用户组
- serviceAccount:服务账号
2.3 RBAC实现鉴权
首先创建角色, rbac-role.yaml进行创建,这个角色只对pod 有 get、list权限
1 | apiVersion: rbac.authorization.k8s.io/v1 |
相关命令
1 | # 查看已经存在的命名空间 |
然后进行创建角色绑定,通过 role-rolebinding.yaml 的方式,来创建我们的角色绑定
1 | apiVersion: rbac.authorization.k8s.io/v1 |
执行相关命令
1 | # 创建角色绑定 |
3、核心技术Ingress
3.1 前言概述
原来我们需要将端口号对外暴露,通过 ip + 端口号就可以进行访问,是使用Service中的NodePort来实现
- 在每个节点上都会启动端口
- 在访问的时候通过任何节点,通过ip + 端口号就能实现访问
但是NodePort还存在一些缺陷
- 因为端口不能重复,所以每个端口只能使用一次,一个端口对应一个应用
- 实际访问中都是用域名,根据不同域名跳转到不同端口服务中
3.2 Ingress和Pod关系
pod 和 ingress 是通过service进行关联的,而ingress作为统一入口,由service关联一组pod中
- 首先service就是关联我们的pod
- 然后ingress作为入口,首先需要到service,然后发现一组pod
- 发现pod后,就可以做负载均衡等操作
在实际的访问中,我们都是需要维护很多域名,a.com 和 b.com然后不同的域名对应的不同的Service,然后service管理不同的pod(ingress不是内置的组件,需要我们单独的安装),相当于Nginx
3.3 创建Ingress规则
参考:ingress-controller部署
github:https://github.com/kubernetes/ingress-nginx
- 部署ingress Controller【需要下载官方的】
- 创建ingress规则【对哪个Pod、名称空间配置规则】
1 | # 创建一个nginx应用,然后对外暴露端口,创建pod |
现在还只能在集群内部访问,需要暴露service,vimservice-nodeport.yaml
1 |
|
ingress.yaml规则文件,注意不同版本间的写法有差异
1 | apiVersion: networking.k8s.io/v1beta1 |
在windows 的 hosts文件,添加域名访问规则【因为我们没有域名解析,所以只能这样做】,最后通过域名:32080
就能访问
1 | xx.xx.xx.xx shawn.com |
3.4 其他高级配置
其他高级选项和nginx类似,可以通过高级注解选择,参考:nginx-ingress注解官网
路径重写
1 | apiVersion: networking.k8s.io/v1beta1 |
流量限制
1 | apiVersion: networking.k8s.io/v1beta1 |
4、Kubernetes核心技术Helm
Helm官网:https://helm.sh/zh/
包搜索:https://artifacthub.io/
4.1 Helm概述
Helm是一个Kubernetes的包管理工具,就像Linux下的包管理器,如yum/apt等,可以很方便的将之前打包好的yaml文件部署到kubernetes上。Helm就是一个包管理工具【类似于npm】。Helm有三个重要概念
- helm:一个命令行客户端工具,主要用于Kubernetes应用chart的创建、打包、发布和管理
- Chart:应用描述,一系列用于描述k8s资源相关文件的集合
- Release:基于Chart的部署实体,一个chart被Helm运行后将会生成对应的release,将在K8S中创建出真实的运行资源对象。也就是应用级别的版本管理
- Repository:用于发布和存储Chart的仓库
V3版本变化
- 架构变化
- 最明显的变化是Tiller的删除
- V3版本删除Tiller
- relesase可以在不同命名空间重用
4.2 helm下载与配置
1 | # 脚本安装,不过可能会失败 |
4.3 使用helm快速部署应用
1 | # 搜索 weave仓库 |
4.4 自定义Chart
目录格式
- templates:编写yaml文件存放到这个目录
- values.yaml:存放的是全局的yaml文件
- chart.yaml:当前chart属性配置信息
1 | # 使用命令,自己创建Chart |
4.5 chart模板使用
通过传递参数,动态渲染模板,yaml内容动态从传入参数生成
刚刚我们创建mychart的时候,看到有values.yaml文件,这个文件就是一些全局的变量,然后在templates中能取到变量的值,下面我们可以利用这个,来完成动态模板
- 在values.yaml定义变量和值
- 具体yaml文件,获取定义变量值
- yaml文件中大题有几个地方不同
- image
- tag
- label
- port
- replicas
1 | # 在values.yaml定义变量和值 |
修改模板文件
1 | # deployment.yaml文件 |
5、命名空间
如果一个集群中部署了多个应用,所有应用都在一起,就不太好管理,也可以导致名字冲突等。我们可以使用 namespace 把应用划分到不同的命名空间,跟代码里的 namespace 是一个概念,只是为了划分空间
1 | # 创建命名空间 |
可以用 kubens 快速切换 namespace,首先进行下载安装
1 | wget https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubens_v0.9.4_linux_x86_64.tar.gz |
6、Kubernetes持久化存储
6.1 概述
之前我们有提到数据卷:emptydir
,是本地存储,pod重启,数据就不存在了,需要对数据持久化存储,对于数据持久化存储【pod重启,数据还存在】,有两种方式
- nfs:网络存储【通过一台服务器来存储】
- PV和PVC
6.2 nfs网络存储
持久化服务器上操作,所有结点都需要安装nfs-utils
1 | # 找一台新的服务器nfs服务端,安装nfs,设置挂载路径,使用命令安装nfs |
从节点上操作
1 | # 然后需要在k8s集群node节点上安装nfs,这里需要在 node1 和 node2节点上安装 |
K8s集群部署应用
1 | # 最后我们在k8s集群上部署应用,使用nfs持久化存储 |
创建nfs-nginx.yaml文件,注意修改ip
1 | apiVersion: apps/v1 |
测试
1 | kubectl apply -f nfs-nginx.yaml |
6.3 PV和PVC
- PV:持久化存储,对存储的资源进行抽象,对外提供可以调用的地方【生产者】
- PVC:用于调用,不需要关心内部实现细节【消费者】
PV 和 PVC 使得 K8S 集群具备了存储的逻辑抽象能力。使得在配置Pod的逻辑里可以忽略对实际后台存储 技术的配置,而把这项配置的工作交给PV的配置者,即集群的管理者。存储的PV和PVC的这种关系,跟 计算的Node和Pod的关系是非常类似的;PV和Node是资源的提供者,根据集群的基础设施变化而变 化,由K8s集群管理员配置;而PVC和Pod是资源的使用者,根据业务服务的需求变化而变化,由K8s集 群的使用者即服务的管理员来配置。
实现流程
- PVC绑定PV
- 定义PVC
- 定义PV【数据卷定义,指定数据存储服务器的ip、路径、容量和匹配模式】
1 | # pvc.yaml |
测试
1 | # 然后就可以创建pod了 |
如果删除了pvc,会发现pv状态是处于Released的,需要进入特定的pv配置文件,删除claimRef下的内容即可
五、搭建集群监控平台系统
1、监控指标
一个好的监控系统主要监控以下内容:
- 集群监控
- 节点资源利用率
- 节点数
- 运行 Pods
- Pod 监控
- 容器指标
- 应用程序【程序占用多少 CPU、内存】
2、监控平台
台
- prometheus【监控】
- 定时搜索被监控服务的状态
- 开源
- 监控、报警、数据库
- 以 HTTP 协议周期性抓取被监控组件状态
- 不需要复杂的集成过程,使用 http 接口接入即可
- Grafana【展示】
- 开源的数据分析和可视化工具
- 支持多种数据源
3、部署 Pormetheus
3.1 创建守护进程Pod
首先需要部署一个守护进程,然后创建yaml文件vim node-exporter.yaml
1 |
|
然后通过yaml的方式部署prometheus:
- configmap:定义一个configmap:存储一些配置文件【不加密】
- prometheus.deploy.yaml:部署一个deployment【包括端口号,资源限制】
- prometheus.svc.yaml:对外暴露的端口
- rbac-setup.yaml:分配一些角色的权限
3.2 rbac创建
vim rbac-setup.yaml
1 | apiVersion: rbac.authorization.k8s.io/v1 |
3.3 ConfigMap
vim configmap.yaml
1 | apiVersion: v1 |
3.4 Deployment
vim prometheus.deploy.yaml
1 |
|
3.5 Service
vim prometheus.svc.yaml
1 |
|
3.6 创建与部署
1 | kubectl create -f node-exporter.yaml |
4、部署 Grafana
4.1 Deployment
vim grafana-deploy.yaml
1 | apiVersion: apps/v1 |
4.2 Service
vim grafana-svc.yaml
1 | apiVersion: v1 |
4.3 Runing
vim grafana-ing.yaml
1 | apiVersion: extensions/v1beta1 |
4.4 创建与部署
1 | kubectl create -f grafana-deploy.yaml |
六、搭建高可用 Kubernetes 集群
1、高可用集群架构
之前我们搭建的集群,只有一个 master 节点,当 master 节点宕机的时候,通过 node 节点将无法继续访问,而 master 主要是管理作用,所以整个集群将无法提供服务
- 在 node 节点和 master 节点之间,需要一个 LoadBalancer 组件
- 【作用 1】负载
- 【作用 2】检查 master 节点的状态
- 对外需要一个统一的 VIP
- 【作用 1】虚拟 ip 对外进行访问
2、高可用集群环境准备
我们采用 2 个 master 节点,一个 node 节点来搭建高可用集群
2.1 安装步骤
使用二进制包方式搭建 Kubernetes 集群主要分为以下几步:
- 【环境准备】准备四台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对四个刚安装好的操作系统进行初始化操作
- 【安装 docker、kubectl、kubeadm、kubectl】对四个节点进行安装
- 【配置高可用 VIP】对 master 节点安装
keepalived
和haproxy
- 【部署 master 组件】在 master 节点上安装
kube-apiserver
、kube-controller-manager
、kube-scheduler
- 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
2.2 安装要求
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 30GB 或更多【注意】【master 需要两核】
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止 swap 分区
2.3 准备环境
角色 | IP | 配置 | 步骤 |
---|---|---|---|
k8sLoadBalancer(这台可以不用) | 192.168.249.139 | 2CPU 1G | init docker kubectl kubeadm kubectl |
k8smaster1 | 192.168.249.146 | 2CPU 2G | init docker kubectl kubeadm kubectl keepalived haproxy |
k8smaster2 | 192.168.249.147 | 2CPU 2G | init docker kubectl kubeadm kubectl keepalived haproxy |
k8snode1 | 192.168.249.148 | 2CPU 2G | init docker kubectl kubeadm kubectl |
3、高可用集群搭建
3.1 系统初始化
1 | # 所有结点都需要 |
3.2 安装 docker、kubelet、kubeadm、kubectl
所有节点安装 docker/kubelet/kubeadm/kubectl,Kubernetes 默认 CRI(容器运行时)为 docker,因此先安装 docker
1 | # 所有结点都需要 |
3.3 配置高可用 VIP【haproxy+keepalived】
1 | # 【k8smaster1 + k8smaster2 上操作】 |
配置 keepalived,keepalived中使用track_script机制来配置脚本进行探测kubernetes的master节点是否宕机,并以此切换节点实现高可用,配置文件所在的位置/etc/keepalived/keepalived.cfg
需要注意几点(前两点记得修改):
mcast_src_ip
:配置多播源地址,此地址是当前主机的 ip 地址。priority
:keepalived
根据此项参数的大小仲裁master
节点。我们这里让 master 节点为kubernetes
提供服务,其他两个节点暂时为备用节点。因此k8smaster1
节点设置为100
,k8smaster2
节点设置为99
。state
:我们将k8smaster1
节点的state
字段设置为MASTER
,其他节点字段修改为BACKUP
。- 上面的集群检查功能是关闭的,等到集群建立完成后再开启。
1 | # k8smaster1节点的keepalived配置文件,虚拟ip是vip地址 |
启动和检查 【k8smaster1 和 k8smaster2 均要启动】
1 | # 启动 haproxy |
3.4 部署 Kubernetes Master 组件
1 | # 首先在master1结点操作 |
3.5 安装集群网络
1 | # 下载 yaml 文件 |
3.6 测试 kubernetes 集群
1 | # 创建 nginx deployment |
七、在集群环境中部署项目
1、容器交付流程
- 开发代码阶段
- 编写代码
- 编写 Dockerfile【打镜像做准备】
- 持续交付/集成
- 代码编译打包
- 制作镜像
- 上传镜像仓库
- 应用部署
- 环境准备
- Pod
- Service
- Ingress
- 运维
- 监控
- 故障排查
- 应用升级
2、k8s 部署 java 项目流程
- 制作镜像【Dockerfile】
- 上传到镜像仓库【Dockerhub、阿里云、网易】
- 控制器部署镜像【Deployment】
- 对外暴露应用【Service、Ingress】
- 运维【监控、升级】
3、k8s 部署 Java 项目
3.1 制作镜像
这里已经制作好了一个 jar 包,名字为demojenkins.jar,然后上传并编写vim Dockerfile
1 | FROM openjdk:8-jdk-alpine |
打包与测试
1 | docker build -t java-demo-01:latest . |
3.2 上传镜像仓库
镜像仓库可以选择云服务等,这里选择本地仓库地址进行测试,可以参考:docker学习笔记
1 | ## 搭建私人仓库 |
3.3 部署项目
1 | # 如果时私有仓库注意添加docker源 |
参考:
https://www.bilibili.com/video/BV1GT4y1A756