1. 基本概念和架构
1.1 基本介绍
Kubernetes,简称K8S。一款开源、用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署、规划、更新、维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。
容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在 build 或 release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更 “透明”,这更便于监控和管理。
Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。
在 Kubernetes 中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。
※ 发展经历
经典案例:
Infrastructure as a Service(阿里云)
Platform as a service(新浪云)
Software as a Service(Office 365)
集群资源管理器:
Apache MESOS(最新版本可以管理Kubernetes, 但增加软件层可能会增加故障节点)
- Apache开源协议,分布式资源管理框架。
- 2019年5月,Twitter弃用 MESOS,开始使用Kubernetes。
Docker Swarm(功能较少, 缺乏滚动更新+回滚等功能)
- 2019年7月,阿里云宣布删除 Docker Swarm 选项。
Kubernetes(Google)
- Google拥有10年容器化基础架构经验,Google拥有强大的内部的容器管理系统——Borg。
- 采用GO语言,借鉴Borg的思想,开发了Kubernetes。
- 特点:
- 轻量级:消耗资源小
- 开源
- 弹性伸缩
- 负载均衡:IPVS框架
-
K8S是谷歌在2014年开源的容器化集群管理系统。
-
使用K8S进行容器化应用部署。
-
使用K8S利于应用扩展。
-
K8S目标:让部署容器化应用更加简介、高效。
1.2 功能和架构
1.2.1 概述
Kubernetes 是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环境运行工作负载15年的经验,并吸收了来自于社区的最佳想法与实践。
1.2.2 功能
-
自动装箱
基于容器对应用运行环境的资源配置要求自动部署应用容器。
-
自我修复(自愈能力)
当容器失败时,会对容器进行重启。
当所部署的 Node 节点有问题时,会对容器进行重新部署、重新调度。
当容器未通过监控检查时,会关闭此容器。直到容器正常运行时,才会对外提供服务。
-
水平扩展
通过简单的命令、用户UI界面或基于CPU等资源的使用情况,对应用容器进行规模扩大或规模剪裁。
-
服务发现
用户无需使用额外的服务发现机制,就能基于 Kubernetes 自身能力实现服务发现和负载均衡。
-
滚动更新
可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新。
-
版本回退
可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退。
-
密钥和配置管理
在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
-
存储编排
启动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要。
存储系统可以来自于本地目录、网络存储(NFS、Gluster、Ceph等)、公共云存储服务。
-
批处理
提供一次性任务,定时任务;满足批量数据处理和分析场景。
1.2.3 K8S集群架构组件
- Master(主控节点)
- API Server:集群的统一入口,以RESTful方式,交给etcd存储
- Scheduler:节点调度,选择node节点应用部署
- controller-manager:处理集群中常规后台任务,一个资源对应一个控制器
- etcd:存储系统,用于保存集群相关数据
- Node(工作节点)
- Kubelet:Master派到Node节点代表,管理本机容器
- Kube-Proxy:提供网络代理、负载均衡等操作
① Master Node
K8S集群控制节点,对集群进行调度管理,接受集群外用户去集群操作请求;Master Node 由 API Server、Scheduler、ClusterState Strore(ETCD数据库)和 Controller ManagerServer所组成。
② Worker Node
集群工作节点,运行用户业务应用容器;
Worker Node 包含 kubelet、kube proxy 和 ContainerRuntime;
1.2.4 核心概念
① Pod
- 最小部署单元
- 一组容器的集合
- 共享网络
- 生命周期短暂
② Controller
-
确保预期的Pod副本数量
-
应用部署状态
-
无状态应用部署
-
有状态应用部署 (依赖存储 / IP唯一)
-
-
确保所有的Node运行同一个Pod
-
一次性任务、定时任务
③ Service
- 定义一组Pod访问规则
2. 搭建集群
2.1 搭建K8S环境平台规划
2.1.1 单Master集群
2.1.2 多Master集群
2.2 服务器硬件配置要求
2.2.1 测试环境
Master:CPU 2核、内存4GB、磁盘20GB
Node:CPU 4核、内存8GB、磁盘40GB
2.2.2 生产环境
Master:CPU 8核+、内存16GB+、磁盘100GB+
Node:CPU 16核+、内存64GB+、磁盘500GB+
2.3 搭建K8S集群部署方式
目前生产部署 Kubernetes 集群主要有两种方式:
- Kubeadm
- Kubeadm是一个K8S部署工具,提供
kubeadm init
和kubeadm join
,用于快速部署 Kubernetes 集群。 - 官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/
- Kubeadm是一个K8S部署工具,提供
- 二进制包
- 从Github再在发行版的二进制包,手动部署每个组件,组成 Kubernetes 集群。
- Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易控制,推荐使用二进制包部署 Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。
2.4 Kubeadm部署方式
Kubeadm 是官方社区推出的一个用于快速部署 Kubernetes 集群的工具,这个工具能通过两条指令完成一个 Kubernetes 集群的部署:
- 创建一个Master节点:
kubeadm init
- 将Node节点加入到当前集群中
kubeadm join <Master 节点IP和端口>
2.4.1 安装要求
在开始之前,部署 Kubernetes 集群及其需要满足以下几个条件:
- 一台/多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:内存2GB+,CPU 2+、硬盘30GB+
- 集群中所有机器之间网络互通
- 可以访问外网,需要拉取镜像
- 禁止 swap 分区
2.4.2 最终目标
- 在所有节点上安装Docker和Kubeadm
- 部署 Kubernetes Master
- 部署容器网络插件
- 部署 Kubernetes Node,将节点加入Kubernetes 集群中
- 部署Dashboard Web 页面,可视化查看Kubernetes 资源
2.4.3 准备环境
① 虚拟机准备
角色 | IP |
---|---|
K8S-Master | 192.168.1.136 |
K8S-Node1 | 192.168.1.135 |
K8S-Node2 | 192.168.1.134 |
② 系统初始化
1、关闭防火墙
$ systemctl stop firewalld # 临时
$ systemctl disable firewalld # 永久
2、关闭 selinux
$ sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
$ setenforce 0 # 临时
3、关闭 swap
$ swapoff -a # 临时
$ vim /etc/fstab # 永久(删除swap相关行 /mnt/swap swap swap defaults 0 0 这一行或者注释掉这一行)
$ free -m # 确认swap已经关闭(若swap行都显示 0 则表示关闭成功)
4、根据规划设置主机名
$ hostnamectl set-hostname <hostname>
5、在master添加hosts
$ cat >> /etc/hosts << EOF
192.168.1.136 k8smaster
192.168.1.135 k8snode1
192.168.1.134 k8snode2
EOF
6、将桥接的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 # 生效
7、时间同步
$ yum install ntpdate -y
$ ntpdate time.windows.com
2.4.4 所有节点安装Docker/Kubeadm/Kubelet
Kubernetes 默认CRI(容器运行时)为Docker,因此先安装Docker。
① 安装Docker
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.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
② 添加阿里云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 kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
$ systemctl enable kubelet
2.4.5 部署 Kubernetes Master
在Master中执行命令:
$ kubeadm init \
--apiserver-advertise-address=192.168.1.136 \
--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国内无法访问,这里指定阿里云镜像仓库地址。
使用kubectl工具(省略权限修饰符):
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
此时,各个节点状态为Not Ready。
2.4.6 加入 Kubernetes Node
在Node执行命令,向集群添加新节点,执行在kubeadm init输出的kubeadm join命令:
kubeadm join 192.168.1.136:6443 --token 3o69uv.pugf6vy6lq44wjrs \
--discovery-token-ca-cert-hash sha256:3150067383e9af1021776982a4100823564e7ab0a604fe59137409159042b9ec
默认token有效期为24小时,当过期后,该token就不可用了。这时就需要重新创建token,操作如下:
kubeadm token create --print-join-command
2.4.7 部署CNI网络插件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
默认镜像地址无法访问,sed命令修改为docker hub 镜像仓库。(连接不上可查询IP并修改/etc/hosts
文件)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl get pods -n kube-system
查看当前已加入节点:
kubectl get nodes
此时,各个节点状态为Ready。
2.4.8 测试 Kubernetes 集群
在Kubernetes集群中创建一个pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
访问地址:http://Node_IP:Port
3. Kubernetes集群命令行工具kubectl
3.1 概述
kubectl是Kubernetes集群的命令行工具没通过kubectl能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署
3.2 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 nodes
-
flags:指定可选的参数。例如:可用
-s
或者-server
参数指定 Kubernetes API server 的地址、端口。
3.3 kubectl --help 获取更多信息
所有帮助信息:
kubectl --help
具体查看某个操作帮助信息:
kubectl [?] --help
3.4 kubectl 子命令使用分类
3.4.1 基础命令
命令 | 解释 |
---|---|
create | 通过文件或标准输入创建资源 |
expose | 将一个资源公开为一个新的Service |
run | 在集群中运行一个特定的镜像 |
set | 在对象上设置特定的功能 |
get | 显示一个/多个资源 |
explain | 文档参考资料 |
edit | 使用默认的编辑器编辑一个资源 |
delete | 通过文件名、标准输入、资源名称、标签选择器来删除资源 |
3.4.2 部署和集群管理命令
① 部署命令
命令 | 解释 |
---|---|
rollout | 管理资源的发布 |
rolling-update | 给指定的复制控制器滚动更新 |
scale | 扩容/缩容Pod数量,Deployment、ReplicaSet、RC、Job |
autoscale | 创建一个自动选择扩容/缩容并设置Pod数量 |
② 集群管理命令
命令 | 解释 |
---|---|
certificate | 修改证书资源 |
cluster-info | 显示集群信息 |
top | 显示资源(CPU/Memory/Storage)使用。需要Heapster运行。 |
cordon | 标记节点不可调度 |
uncordon | 标记节点可调度 |
drain | 驱逐节点上的应用,准备下线维护 |
taint | 修改节点taint标记 |
3.4.3 故障和调试命令
命令 | 解释 |
---|---|
describe | 显示特定资源或资源组的详细信息 |
logs | 在一个Pod中打印一个容器日志,如果Pod只有一个容器,容器名称是可选的 |
attach | 附加到一个运行的容器 |
exec | 执行命令到容器 |
port-forward | 转发一个/多个本地端口到一个Pod |
proxy | 运行一个proxy到Kubernetes API Server |
cp | 拷贝文件/目录到容器中 |
auth | 检查授权 |
3.4.5 其他命令
① 高级命令
命令 | 解释 |
---|---|
apply | 通过文件名/标准输入对资源应用配置 |
patch | 使用补丁修改、更新资源的字段 |
replace | 通过文件名/标准输入替换一个资源 |
convert | 不同的API版本之间转换配置文件 |
② 设置命令
命令 | 解释 |
---|---|
label | 更新资源上的标签 |
annotate | 更新资源上的注释 |
completion | 用于实现kubectl工具自动补全 |
③ 其他命令
命令 | 解释 |
---|---|
api-versions | 打印受支持的API版本 |
config | 修改kubeconfig文件(用于访问API,比如配置认证信息) |
help | 所有命令帮助 |
plugin | 运行一个命令行插件 |
version | 打印客户端和服务版本信息 |
※ 常用命令举例
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
kubectl get pods
kubectl get nodes
kubectl cs
kubectl apply -f [yaml文件本地/网络路径]
4. 资源编排:YAML
4.1 介绍
K8S集群中对资源管理和资源对象编排部署都可以通过声明样式(YAML)文件来解决,也就是可以把需要对资源对象操作编辑到YAML格式文件中,我们把这种文件叫做资源清单文件,通过kubectl
命令直接使用资源清单文件就可以实现对大量的资源对象进行编排部署了。
4.2 编写格式
4.2.1 YAML介绍
YAML:仍是一种标记语言。为了强调这种语言以数据作为中心,而不是以标记语言作为重点。
YAML是一个可读性高,用来表达数据序列的格式。
4.2.2 YAML基本语法
- 使用空格作为缩进,通过缩进表示层级关系
- 缩进空格数目不重要,只要相同层级的元素左侧对齐即可
- 一般缩进不允许使用Tab键,只允许使用空格
- 一般开头缩进两个空格,字符 (冒号/逗号) 后缩进一个空格
- 使用
---
表示新的yaml文件开始 - 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
4.2.3 YAML文件组成
- 控制器定义
- 被控制对象
# 控制器定义
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
# 被控制对象
template: # 开始定义规则
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
4.2.4 YAML常用字段含义
字段 | 含义 |
---|---|
apiVersion | API版本 |
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数量 |
selector | 标签选择器 |
template | Pod模板 |
metadata | Pod元数据 |
spec | Pod规格 |
containers | 容器配置 |
4.2.5 快速编写YAML文件
- 使用 kubectl create 命令生成 YAML文件
- 使用 kubectl get 导出 YAML文件
① 使用kubectl create命令生成文件
举例:
产生yaml格式:
kubectl create deployment web --image=nginx -o yaml --dry-run
输出至具体文件:
kubectl create deployment web --image=nginx -o yaml --dry-run > m1.yaml
② 使用 kubectl get 导出 YAML文件
举例:
从已部署资源中导出yaml,并输出至文件:
kubectl get deploy nginx -o=yaml --export > m2.yaml
5. 核心概念
5.1 Pod
5.1.1 Pod 概述
Pod是K8S系统中可以创建、管理的最小单元,是资源对象模型中由用户创建/部署的最小资源对象模型,也是在K8S上运行容器化应用的资源对象,其他资源对象都是用来支撑/扩展Pod对象功能的,比如Controller对象是用来管控Pod对象的,Service/Ingress资源对象是用来暴露Pod引用对象的,Persistent Volumn 资源对象是用来为Pod提供存储等等,K8S不会直接处理容器,而是Pod。Pod是由一个/多个container组成。
Pod是 Kubernetes 的最重要概念,每一个Pod都有一个特殊的被称为 “根容器” 的 Pause容器。Pause容器对应的镜像属于 Kubernetes 平台的一部分,除了Pause容器,每个Pod还包含一个/多个紧密相关的用户业务容器。
特点总结:
- 最小部署单元
- 包含多个容器(一组容器的集合)
- 一个Pod中的容器共享网络命名空间
- Pod是短暂的
存在意义:
- 创建容器使用Docker,一个Docker对应一个容器,一个容器有进程 (查看进程
ps -ef
),一个容器运行一个应用程序(单进程+守护进程) - Pod是多进程设计,运行多个应用程序(一个Pod有多个容器,一个容器里运行一个应用程序)
- Pod的存在为了 亲密性应用 而产生
- 两个应用之间进行交互
- 网络之间调用 (127.0.0.1 / Socket)
- 两个应用需要频繁调用
5.1.2 Pod 实现机制
Pod 两大实现机制:
- 共享网络
- 共享存储
① 共享网络
容器本身之间相互隔离
- namespace
- group
前提条件:容器在同一个namespace中
实现机制:
通过Pause容器,把其他业务容器加入Pause容器,让所有容器在同一个namespace中,实现网络共享。
- 首先,创建Pause容器(独立IP、MAC、Port、namespace)
- 其次,分别创建业务容器并加入Pause容器,使其处于同一namespace中
② 共享存储
Pod持久化操作:
- 日志数据
- 业务数据
引入数据卷概念Volumn,使用数据卷进行持久化存储。
示例YAML:
5.1.3 Pod 镜像拉取策略
Pod镜像拉取策略 imagePullPolicy:
-
IfNotPresent:镜像在宿主机上不存在时才拉取(默认)
-
Always:每次创建Pod都会重新拉取一次镜像
-
Never:Pod永远不会主动拉取这个镜像
示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: nginx
image: nginx:1.14
imagePullPolicy: Always
# Pod镜像拉取策略-imagePullPolicy
# IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
# Always:每次创建Pod都会重新拉取一次镜像
# Never:Pod永远不会主动拉取这个镜像
5.1.4 Pod 资源限制
示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests: # 资源请求(调度)
memory: "64Mi"
cpu: "250m"
limits: # 资源限制(最大)
memory: "128Mi"
cpu: "500m"
Pod和Container的资源请求和限制:
- spec.containers[].resources.limits.cpu
- spec.containers[].resources.limits.memory
- spec.containers[].resources.requests.cpu
- spec.containers[].resources.requests.memory
CPU资源举例解释:设 1c=1000m,则0.25c=250m、0.5=500m
5.1.5 Pod 重启机制
Pod重启机制 restartPolicy:
-
Always:当容器终止退出后,总是重启容器(默认)
-
OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
-
Never:当容器终止退出,从不重启容器
- 批量一次性任务正常结束
示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: busybox
image: busybox:1.28.4
args:
- /bin/sh
- -c
- sleep 36000
restartPolicy: Never
# Pod重启机制-restartPolicy
# Always:当容器终止退出后,总是重启容器,默认策略
# OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
# Never:当容器终止退出,从不重启容器
5.1.6 Pod 健康检查
应用层面健康检查:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy
livenessProbe:
exec:
command:
- cat
- /temp/healthy
initialDelaySeconds: 5
periodSeconds: 5
健康检查策略:
-
livenessProbe(存活检查)
如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
-
readinessPribe(就绪检查)
如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
Porbe支持的检查方法:
-
httpGet
发送HTTP请求,返回200~400范围状态码为成功。
-
exec
执行shell命令返回状态码是0为成功。
- touch创建文件后,通过
echo $?
查看状态码为0;删除文件后,通过echo $?
查看状态码为1。
- touch创建文件后,通过
-
tcpSocket
发起TCP Socket建立成功
5.1.7 Pod 调度策略
① 创建Pod流程
master节点:
-
createpod – apiserver – etcd
-
scheduler – apiserver – etcd – 调度算法, 将Pod调度到Node节点
node节点:
- kubelet – apiserver – 读取etcd拿到分配给当前节点pod – docker创建容器
② Pod调度
影响调度的属性:
-
Pod资源限制
根据request找到足够node节点进行调度。
-
节点选择器nodeSelector标签
(对节点创建标签:
kubectl label [node_name] env_role=dev
)apiVersion: v1 kind: Pod metadata: name: pod-example spec: nodeSelector: env_role: dev containers: - name: nginx image: nginx:1.15
-
节点亲和性nodeAffinity标签
与nodeSelector基本一样,根据节点上标签的约束来决定Pod调度到哪些节点上,但功能更加强大。
- 硬亲和性(requiredDuringSchedulingIgnoreDuringExecution):约束条件必须满足
- 软亲和性(preferredDuringSchedulingIgnoreDuringExecution):尝试满足,不保证绝对满足
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoreDuringExecution: nodeSelectorTerms: - matchExpressions: - key: evn_role operator: In values: - dev - test preferredDuringSchedulingIgnoreDuringExecution: - weight: 1 preference: matchExpressions: - key: group operator: In values: - otherprod containers: - name: webdemo image: nginx
支持常用操作符operator:In、NotIn(反亲和性)、Exists、Gt、Lt、DoesNotExists(反亲和性)
-
污点&污点容忍
-
基本介绍:
- nodeSelector、nodeAffinity:Pod调度到节点上,Pod属性,调度时实现。
- Taint污点:节点不做普通分配调度,是节点属性
-
场景:
- 专用节点(IP范围)
- 配置特定硬件节点
- 基于Taint驱逐
-
具体演示:
-
查看节点污点情况:
kubectl describe node [node_name] | grep Taint
污点值(taint_value)有三个:
- NoSchedule:一定不被调度
- PreferNoSchedule:尽量不被调度
- NoExecute:不会调度,并且驱逐已有Pod进其它Node
-
为节点添加污点 (key, value自定义):
kubectl taint node [node_name] key=value:[taint_value]
-
为节点删除污点 (key, value自定义):
kubectl taint node [node_name] key=value-
-
-
污点容忍tolerations : 可能被调度 (部分YAML) :
spec: tolerations: - key: "key" operator: "Equal" value: "value" effect: "NoSchedule" containers: - name: webdemo image: nginx
-
5.2 Controller
5.2.1 Controller概述
- 在集群上,管理和运行容器的对象
5.2.2 Pod和Controller关系
-
Pod通过Controller实现应用的运维
(如:伸缩、滚动升级 等)
-
Pod与Controller之间通过 label标签 建立关系
5.2.3 Deployment控制器应用场景
- 部署无状态应用
- 管理Pod和ReplicaSet
- 部署、滚动升级 等功能
应用场景:Web服务、微服务
5.2.4 Deployment:控制器部署无状态应用
- 导出yaml文件:
kubectl create deployment web --image=nginx --dry-run -o yaml > web.yaml
- 使用yaml部署应用:
kubectl apply -f web.yaml
;并查看状态:kubectl get pods
- 对外发布(暴露对外端口号):
kubectl expose deployment [app_name] --port=80 --type=NodePort --target-port=80 --name=[app_name]
5.2.5 应用升级回滚
① 应用升级
升级应用至某指定版本:
kubectl set image deployment web [the_name]=[image_name]:[version_number]
# 举例
kubectl set image deployment web nginx=nginx:1.15
查看升级状态:
② 应用回滚
查看应用升级历史版本:
回滚至上一个版本:
kubectl rollout undo deployment web
查看回滚状态:
kubectl rollout status deployment web
回滚到指定版本(eg. 1):
kubectl rollout undo deployment web --to-revision=1
5.2.6 应用弹性伸缩
提供更多服务:
kubectl scale deployment web --replicas=10
查看新增9个副本:
5.2.7 StatefulSet:部署有状态应用
※ 无状态 & 有状态:
- 无状态
- 认为Pod都是一样的
- 没有顺序要求
- 不用考虑在哪个Node运行
- 随意进行伸缩、扩展
- 有状态
- 考虑以上所有因素
- 让每个Pod独立,保持Pod的启动顺序、唯一性
- 唯一的网络标识符、持久存储
- 有序(如:MySQL主从)
- 无头Service
- ClusterIP:none
※ 部署有状态应用
YAML示例:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-statefulset
namespace: default
spec:
serviceName: nginx
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
查看Pod,有3个Pod,每个都是唯一名称:
查看创建的无头Service:
Deployment 和 StatefulSet区别:有身份(唯一标识):
- 根据主机名(每个Pod有唯一主机名) + 按照一定规则生成域名
- 每个Pod有唯一主机名
- 生成唯一域名:
- 主机格式.service名称.名称空间.svc.cluster.local
- 举例:
nginx-statfulset-0.nginx.default.svc.cluster.local
5.2.8 DeamonSet:部署守护进程
部署守护进程DeamonSet
- 在每个node节点上运行同一个Pod,新加入的node也同样运行这个Pod
- 举例:每个node节点安装数据采集工具
YAML示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds-test
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
containers:
- name: logs
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: varlog
mountPath: /tmp/log
volumes:
- name: varlog
hostPath:
path: /var/log
创建成功:
进入其中一个Pod (kubectl exec -it [pod_name] bash
),查看日志文件:
5.2.9 Job:部署一次任务
YAML示例:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4 # 失败后尝试重试次数
创建成功 (kubectl create -f pi.yaml
):
计算完成:
通过日志(kubectl logs pi-gxztq
),查看计算结果:
通过删除K8S中缓存的yaml文件,移除一次性任务:
5.2.10 CronJob:部署定时任务
YAML示例:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
创建成功:
已成功运行一次:
通过日志,查看运行结果:
每隔一段时间执行一次,出现一个Pod (Complated):
删除K8S缓存yaml配置,移除定时任务:
5.3 Service
5.3.1 存在意义
-
Pod的IP不固定,Service可防止Pod失联(服务发现)
-
定义一组Pod访问策略(负载均衡)
5.3.2 Pod和Service关系
根据 label 和 selector 标签建立关联
通过Service实现Pod的负载均衡,每个Service拥有一个 虚拟IP(Virtual IP),借助Service访问一组Pod通过虚拟IP访问。
5.3.3 常用Service类型
-
ClusterIP:集群内部访问
-
NodePort:对外访问应用使用
-
LoadBalancer:对外访问应用使用 / 用于公有云
-
ExternalName:将服务映射到 DNS 名称,而非典型的选择器(需追加属性externalName)
type: ExternalName externalName: [external_name]
① ClusterIP
使用kubectl expose deployment web --port=80 --target-port=80 --dry-run -o yaml > service.yaml
导出web的svc(Service)配置,并进行修改:
使用命令kubectl apply -f service.yaml
执行(若已自动生成svc, 可手动删除替换),创建Service:
从其他节点内部访问curl [ip_address]
:
② NodePort
更改名称并更改类型为NodePort:
创建成功,检查类型:
内部访问成功:
外部访问成功:
③ LoadBalancer
Node在内网进行部署,外网一般不能访问到:
- 找到一台可以进行外网访问机器,安装nginx,反向代理
- 手动把可以访问到的节点添加到nginx里
- LoadBalancer:公有云 → 负载均衡、控制器
5.4 配置管理
5.4.1 Secret
作用:加密数据存在etcd中,让Pod容器以挂载 变量/Volume(数据卷) 方式进行访问
场景:凭证
- base64编码 (
echo -n [target_str] | base64
)
-
创建Secrete加密数据(用户名密码已用base64加密, 命令
kubectl create -f secret.yaml
)apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm
-
以变量形式挂载到Pod容器中
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: nginx image: nginx env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password
-
以Volume(数据卷)形式挂载到Pod容器中
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: nginx image: nginx volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret
5.4.2 ConfigMap
作用:存储不加密数据到etcd中,让Pod以变量或Volume数据卷形式挂载到容器中
场景:配置文件 (IP / 端口号 / 用户名)
-
创建配置文件(如:Redis配置文件)
redis.host=127.0.0.1 redis.port=6379 redis.password=123456
-
创建configMap (命令:
kubectl create configmap redis-config --from-file=redis.properties
)查看所有
kubectl get configmap
或kubectl get cm
,查看详细信息kubectl describe cm redis-config
-
以Volume挂载到Pod容器(cm.yaml)
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: busybox image: busybox command: [ "/bin/sh","-c","cat /etc/config/redis.properties" ] volumeMounts: - name: config-volume mountPath: "/etc/config" volumes: - name: config-volume configMap: name: redis-config restartPolicy: Never
-
以变量形式挂载到Pod容器(myconfig.yaml)
① 创建yaml,声明变量信息 configmap 创建
kubectl apply -f myconfig.yaml
apiVersion: v1 kind: ConfigMap metadata: name: myconfig namespace: default data: special.level: info special.type: hello
② 以变量挂载(config-var.yaml)
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: busybox image: busybox command: [ "/bin/sh","-c","echo $(LEVEL) $(TYPE)" ] env: - name: LEVEL valueFrom: configMapKeyRef: name: myconfig key: special.level - name: TYPE valueFrom: configMapKeyRef: name: myconfig key: special.type restartPolicy: Never
通过日志查看输出:
5.5. 集群安全机制
5.5.1 概述
- 访问K8S集群资源(Pod/Service/Controller)时,需要经过三个步骤完成具体操作
- 第一步:认证
- 第二步:鉴权(授权)
- 第三步:准入控制
- 进行访问时,过程中需要经过 API Server 做统一协调。
- 访问过程中,需要证书 / token / 用户名+密码。
- 访问Pod需要serviceAccount。
① 认证:传输安全
- 传输安全:对外不暴露8080端口,只能内部访问,对外使用端口6443
- 认证:客户端身份认证常用方式:
- https证书认证:基于CA证书
- http token:通过token识别用户
- http基本认证:用户名+密码认证
② 鉴权 (授权)
- 基于RBAC鉴权操作
- 基于角色访问控制
③ 准入控制
- 进入准入控制器的列表,如果列表中有请求内容就通过,如果没有就拒绝
5.5.2 RBAC介绍
基于角色的访问控制
- 角色
- role:特定命名空间访问权限(查看命名空间:
kubectl get ns
) - clusterRole:所有命名空间控制
- role:特定命名空间访问权限(查看命名空间:
- 角色绑定
- roleBingding:角色绑定到主体
- clusterRoleBingding:集群的角色绑定到主体
- 主体:
- user:用户
- group:用户组
- serviceAccount:服务账号(Pod访问)
5.5.3 RBAC鉴权
-
创建命名空间
-
在新创建的命名空间创建一个Pod
-
创建角色(rbac-role.yaml)
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: roledemo name: pod-reader rules: - apiGroups: [""] # "" indicates the core API group resources: ["pods"] verbs: ["get", "watch", "list"]
查看角色:
-
创建角色绑定(rbac-rolebinding.yaml)
kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: roledemo name: read-pods subjects: - kind: User name: lucy # Name is case sensive apiGroup: rbac.authorization.k8s.io roleRef: kind: Role # This must be Role or ClusterRole name: pod-reader # This must match the name of the Role or ClusterRole you wish to bind to apiGroup: rbac.authorization.k8s.io
-
使用证书识别身份(二进制搭建集群)
cat > lucy-csr.json << EOF { "CN": "lucy", "host": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "BeiJing", "ST": "BeiJing" } ] } EOF cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes lucy-csr.json | cfssljson -bare lucy kubectl config set-cluster kubernetes \ --certificate-authority=ca.pem \ --embed-certs=true \ --server=https://192.168.1.1.36:6443 \ --kubeconfig=lucy-kubeconfig kubectl config set-certificate lucy \ --client-key=lucy-key.pem \ --client.certificate=lucy.pem \ --embed-certs=true \ --kubeconfig=lucy-kubeconfig kubectl config set-context lucy \ --cluster=kubernetes \ --user=lucy \ --kubeconfig=lucy-kubeconfig kubectl config use-context default --kubeconfig=lucy-kubeconfig
5.6 Ingress
5.6.1 概述
-
把端口号对外暴露,通过IP+端口号进行访问
- 使用Service中NodePort实现
-
NodePort缺陷
- 在每个节点上都会启动端口,在访问时通过任何节点IP+暴露端口号进行访问
- 意味着每个端口只能使用一次,一个端口对应一个项目
- 实际访问中都是使用域名,根据不同域名跳转到不同端口服务中
-
Ingress和Pod关系
- pod和ingress通过service关联
- ingress作为统一入口,由service关联一组pod
-
Ingress工作流程
-
使用Ingress
- 部署Ingress Controller (官方维护nginx控制器→实现部署)
- 创建Ingress规则
5.6.2 对外暴露应用
-
创建nginx-pod应用,对外暴露端口使用NodePort
-
部署 Ingress Controller
apiVersion: v1 kind: Namespace metadata: name: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses verbs: - get - list - watch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter # when launching the nginx-ingress-controller. - "ingress-controller-leader-nginx" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: nginx-ingress-role-nisa-binding namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: nginx-ingress-role subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: nginx-ingress-clusterrole-nisa-binding labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: hostNetwork: true # wait up to five minutes for the drain of connections terminationGracePeriodSeconds: 300 serviceAccountName: nginx-ingress-serviceaccount nodeSelector: kubernetes.io/os: linux containers: - name: nginx-ingress-controller image: lizhenliang/nginx-ingress-controller:0.30.0 args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 101 runAsUser: 101 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 lifecycle: preStop: exec: command: - /wait-shutdown --- apiVersion: v1 kind: LimitRange metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: limits: - min: memory: 90Mi cpu: 100m type: Container
-
创建ingress规则
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: example-ingress spec: rules: - host: example.ingredemo.com http: paths: - path: / backend: serviceName: web servicePort: 80
-
在windows系统host文件(
C:\Windows\System32\drivers\etc\hosts
)中添加域名访问规则后,并访问
5.7 Helm
5.7.1 引入
此前部署应用的过程:
- 编写yaml文件
- Deployment
- Service
- Ingress
如果使用此前的方式 部署 单一应用/少数服务的应用 比较合适。
部署微服务项目,可能会有几十个服务,每个服务都有一套yaml文件,需要维护大量yaml文件,版本管理不方便。
使用helm可以解决哪些问题?
- 使用helm可将这些yaml文件作为一个整体管理
- 实现yaml文件高效复用
- 实现应用级别的版本管理
5.7.2 概述
Helm介绍:
Helm是个Kubernetes的包管理工具,就想Linux下的包管理器,如yum/apt等,可以很方便的将之前打包好的yaml文件部署到kubernetes上。
Helm3个重要概念:
- Helm:一个命令行客户端工具,主要用于Kubernetes应用chart的创建、打包、发布、管理。
- Chart:应用描述,一系列用于描述ks资源相关文件的集合。可以理解为yaml的集合。
- Release:基于Chart的部署实体,一个chart被Helm运行后将会生成对应的一个release;将在k8s中创建出真实运行的资源对象。可实现应用级别的版本管理。
Helm v3 (2019) 版本变化:架构变化
- 删除Tiller (此前版本通过Tiller操作集群)
- release可以在不同的命名空间重用
- 将chart推送到docker仓库中
5.7.3 安装和配置仓库
① helm安装
- 下载 Helm 压缩文件,上传到Linux系统中。
- 解压helmy压缩文件,将解压后的helm目录复制到
/usr/bin
目录下。
② 配置helm仓库
-
添加仓库
helm repo add [repo_name] [repo_address]
helm repo add stable http://mirror.azune.cn/kubernetes/charts/ helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts helm repo update
-
查看仓库
helm repo list
-
更新仓库地址
helm repo update
-
删除仓库
helm repo remove [repo_name]
5.7.4 快速部署应用
-
使用命令搜索应用:
helm search repo [key_word]
-
根据搜索内容选择安装:
helm install [name] [app_name]
查看安装后状态:
helm list
或helm status [name]
使其可从外部访问:修改Service的yaml文件,type改为NodePort(kubectl edit svc ui-weave-scope
)
5.7.5 自定义chart部署
自定义Chart完成部署:
-
使用命令创建chart:
helm create chart [chart_name]
- Chart.yaml:当前chart属性配置信息
- templates:编写yaml文件放到这个目录
- values.yaml:yaml文件可以使用全局变量
-
在templates文件夹创建两个yaml文件
- deployment.yaml(
kubectl create deployment web1 --image=nginx --dry-run -o yaml > deployment.yaml
) - service.yaml(先创建再删除/根据模板修改:
kubectl expose deployment web1 --port=80 --target-port=80 --type=NodePort --dry-run -o yaml > service.yaml
)
- deployment.yaml(
-
安装mychart
-
应用升级:
helm upgrade [chart_name] [chart_dir]
5.7.6 chart模板使用
实现yaml高效复用:
- 通过传递参数,动态渲染模板,yaml内容动态传入参数生成
- 在 chart 有 values.yaml 文件,定义 yaml 文件全局变量
- yaml文件大体上有这些地方不同
- image
- tag
- label
- port
- replicas
- 在values.yaml定义变量和值
-
在具体yaml文件,获取使用定义变量值(格式:
{{ .Values.[var_name]}}
;动态生成名称:{{ .Release.Name}}
)-
deployment.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name}}-dep spec: replicas: 1 selector: matchLabels: app: {{ .Values.label}} strategy: {} template: metadata: creationTimestamp: null labels: app: {{ .Values.label}} spec: containers: - image: {{ .Values.image}} name: nginx resources: {} status: {}
-
service.yaml:
apiVersion: v1 kind: Service metadata: name: {{ .Release.Name}}-svc spec: ports: - port: {{ .Values.port}} protocol: TCP targetPort: 80 selector: app: {{ .Values.label}} type: NodePort status: loadBalancer: {}
-
使用helm install --dry-run web2 mychart/
命令查看生成yaml,验证结果,直接安装也可验证:
5.8 持久化存储
5.8.1 nfs网络存储
数据卷 empty dir,为本地存储。pod重启后,数据不存在,需对数据持久化存储。
nfs 网络存储
pod重启数据,仍存在。
-
找一台服务器作为nfs服务端,安装nfs(
yum install -y nfs-utils
) -
nfs服务端设置挂载路径:
vim /etc/exports # 写入信息: *(rw,no_root_squash)
-
nfs服务端创建挂载路径:
mkdir /data/nfs
-
在k8s集群node节点安装nfs(
yum install -y nfs-utils
) -
在nfs服务端启动nfs服务
-
在ks集群部署应用使用nfs网络持久存储
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-dep1 spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx name: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot nfs: server: 192.168.1.139 # nfs server ip path: /data/nfs
-
在nfs服务器目录创建文件后,进入容器 寻找
/usr/share/nginx/html
目录内主页信息,查看文件是否读取。 -
创建Service-NodePort,在浏览器查看主页信息是否发生变化。
5.8.2 PV和PVC
PV
持久化存储,对存储资源进行抽象,对外提供一个可以调用的地方。
PVC
用于调用,不需要关心内部实现细节。
实现流程
-
应用部署
-
定义PVC(绑定PV)
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-dep1 spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot persistentVolumeClaim: claimName: my-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi
-
定义PV(数据存储服务器IP、路径;定义存储容量storage、匹配模式accessModes-RW)
apiVersion: v1 kind: PersistentVolume metadata: name: my-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: path: /k8s/nfs server: 192.168.1.139
6. 集群监控平台系统
6.1 监控指标和方案
6.1.1 监控指标
- 集群监控
- 节点资源利用率
- 节点数
- 运行pods
- Pod监控
- 容器指标
- 应用程序
6.1.2 监控平台搭建方案
组件: prometheus + Grafana
-
prometheus
- 开源
- 监控、报警
- 内置数据库
- 以HTTP协议周期性抓取被监控组件状态
- 无需复杂的集成过程,使用http接口接入即可
-
Grafana:
-
开源
-
数据分析、可视化工具
-
支持多种数据源
-
6.2 搭建监控平台
-
部署守护进程 node.exporter.yaml(
kubectl create -f node-exporter.yaml
):--- apiVersion: apps/v1 kind: DaemonSet metadata: name: node-exporter namespace: kube-system labels: k8s-app: node-exporter spec: selector: matchLabels: k8s-app: node-exporter template: metadata: labels: k8s-app: node-exporter spec: containers: - image: prom/node-exporter name: node-exporter ports: - containerPort: 9100 protocol: TCP name: http --- apiVersion: v1 kind: Service metadata: labels: k8s-app: node-exporter name: node-exporter namespace: kube-system spec: ports: - name: http port: 9100 nodePort: 31672 protocol: TCP type: NodePort selector: k8s-app: node-exporter
-
部署 prometheus:
-
rbac-setup.yaml(
kubectl create -f rbac-setup.yaml
):apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus rules: - apiGroups: [""] resources: - nodes - nodes/proxy - services - endpoints - pods verbs: ["get", "list", "watch"] - apiGroups: - extensions resources: - ingresses verbs: ["get", "list", "watch"] - nonResourceURLs: ["/metrics"] verbs: ["get"] --- apiVersion: v1 kind: ServiceAccount metadata: name: prometheus namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: prometheus roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus subjects: - kind: ServiceAccount name: prometheus namespace: kube-system
-
configMap.yaml(
kubectl create -f configMap.yaml
):apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: kube-system data: prometheus.yml: | global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'kubernetes-apiservers' kubernetes_sd_configs: - role: endpoints scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] action: keep regex: default;kubernetes;https - job_name: 'kubernetes-nodes' kubernetes_sd_configs: - role: node scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - action: labelmap regex: __meta_kubernetes_node_label_(.+) - target_label: __address__ replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name] regex: (.+) target_label: __metrics_path__ replacement: /api/v1/nodes/${1}/proxy/metrics - job_name: 'kubernetes-cadvisor' kubernetes_sd_configs: - role: node scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - action: labelmap regex: __meta_kubernetes_node_label_(.+) - target_label: __address__ replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name] regex: (.+) target_label: __metrics_path__ replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor - job_name: 'kubernetes-service-endpoints' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] action: replace target_label: __scheme__ regex: (https?) - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] action: replace target_label: __address__ regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace target_label: kubernetes_name - job_name: 'kubernetes-services' kubernetes_sd_configs: - role: service metrics_path: /probe params: module: [http_2xx] relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe] action: keep regex: true - source_labels: [__address__] target_label: __param_target - target_label: __address__ replacement: blackbox-exporter.example.com:9115 - source_labels: [__param_target] target_label: instance - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] target_label: kubernetes_name - job_name: 'kubernetes-ingresses' kubernetes_sd_configs: - role: ingress relabel_configs: - source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_probe] action: keep regex: true - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path] regex: (.+);(.+);(.+) replacement: ${1}://${2}${3} target_label: __param_target - target_label: __address__ replacement: blackbox-exporter.example.com:9115 - source_labels: [__param_target] target_label: instance - action: labelmap regex: __meta_kubernetes_ingress_label_(.+) - source_labels: [__meta_kubernetes_namespace] target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_ingress_name] target_label: kubernetes_name - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 target_label: __address__ - action: labelmap regex: __meta_kubernetes_pod_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_pod_name] action: replace target_label: kubernetes_pod_name
-
prometheus.deploy.yaml(
kubectl create -f prometheus.deploy.yaml
):--- apiVersion: apps/v1 kind: Deployment metadata: labels: name: prometheus-deployment name: prometheus namespace: kube-system spec: replicas: 1 selector: matchLabels: app: prometheus template: metadata: labels: app: prometheus spec: containers: - image: prom/prometheus:v2.0.0 name: prometheus command: - "/bin/prometheus" args: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention=24h" ports: - containerPort: 9090 protocol: TCP volumeMounts: - mountPath: "/prometheus" name: data - mountPath: "/etc/prometheus" name: config-volume resources: requests: cpu: 100m memory: 100Mi limits: cpu: 500m memory: 2500Mi serviceAccountName: prometheus volumes: - name: data emptyDir: {} - name: config-volume configMap: name: prometheus-config
-
prometheus.svc.yaml(
kubectl create -f prometheus.svc.yaml
):--- kind: Service apiVersion: v1 metadata: labels: app: prometheus name: prometheus namespace: kube-system spec: type: NodePort ports: - port: 9090 targetPort: 9090 nodePort: 30003 selector: app: prometheus
-
-
部署 Grafana
-
grafana-deploy.yaml(
kubectl create -f grafana-deploy.yaml
)apiVersion: apps/v1 kind: Deployment metadata: name: grafana-core namespace: kube-system labels: app: grafana component: core spec: replicas: 1 selector: matchLabels: app: grafana component: core template: metadata: labels: app: grafana component: core spec: containers: - image: grafana/grafana:4.2.0 name: grafana-core imagePullPolicy: IfNotPresent # env: resources: # keep request = limit to keep this container in guaranteed class limits: cpu: 100m memory: 100Mi requests: cpu: 100m memory: 100Mi env: # The following env variables set up basic auth twith the default admin user and admin password. - name: GF_AUTH_BASIC_ENABLED value: "true" - name: GF_AUTH_ANONYMOUS_ENABLED value: "false" # - name: GF_AUTH_ANONYMOUS_ORG_ROLE # value: Admin # does not really work, because of template variables in exported dashboards: # - name: GF_DASHBOARDS_JSON_ENABLED # value: "true" readinessProbe: httpGet: path: /login port: 3000 # initialDelaySeconds: 30 # timeoutSeconds: 1 volumeMounts: - name: grafana-persistent-storage mountPath: /var volumes: - name: grafana-persistent-storage emptyDir: {}
-
grafana-ing.yaml(
kubectl create -f grafana-ing.yaml
)apiVersion: extensions/v1beta1 kind: Ingress metadata: name: grafana namespace: kube-system spec: rules: - host: k8s.grafana http: paths: - path: / backend: serviceName: grafana servicePort: 3000
-
grafana-svc.yaml(
kubectl create -f grafana-svc.yaml
)apiVersion: v1 kind: Service metadata: name: grafana namespace: kube-system labels: app: grafana component: core spec: type: NodePort ports: - port: 3000 selector: app: grafana component: core
-
-
打开Grafana,配置数据源,导入显示模板。
-
通过查看端口号访问:
-
默认用户名和密码为admin:
-
配置数据源,使用 Prometheus:
配置时
http://CLUSTER-IP:Port
需填入:prometheus的CLUSTER-IP与Port:
-
设置显示模板:
设置
-