Kubernetes介绍
1、应用部署方式演变
在部署应用程序的方式上,主要经历了三个时代
- 传统部署:直接将应用程序部署在物理机上
优点:
简单、不需要其他技术支持
缺点:
不能为应用程序定义资源使用边界,会很难合理的分配计算机资源,并且程序之间会产生影响
- 虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
优点:
程序环境不会相互影响,提供了一定程度的安全性
缺点:
增加了操作系统,浪费了部分资源
- 容器化部署:与虚拟化类似,但是共享了操作系统
优点:
可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间
运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
容器化的应用程序可以跨云服务商,跨Linux操作系统发行版进行部署
容器化部署也有一些问题:
- 一个容器故障停机了,怎么样让另一个容器立刻启动去替补停机的容器
- 当并发访问量大的时候,怎么样做到横向拓展容器数量
这些容器管理问题统称为容器编排问题,为了解决这些容器编排问题,产生了一些容器编排软件:
- Swarm:Docker自己的容器编排工具
- Mesos:Apache的一个资源同意管控的工具,需要和Marathon结合使用
- Kubernetes:Google开源的容器编排工具
2、kubernetes简介
kubernetes,是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的密码武器----Borg系的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本
kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器话的应用,Kubernetes的目标是让部署容器化的应用简单并高效,Kubernetes提供了应用的部署,规划,更新,维护的一种机制
kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理,目的是实现资源的自动化,主要提供了如下的主要特性:
- 自我修复:一旦一个容器崩溃,能够在一秒中左右迅速启动新的容器
- 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
- 负载均衡:如果一个服务启动了多个容器,能够自动实现请求的负载均衡
- 版本回退:如果新发布的程序版本有问题,可以立即回退到原来的版本
- 存储编排:可以根据容器自身的需求自动创建存储卷
3、kubernetes组件
一个kubernetes集群主要是由控制节点(master)、工作节点(node)组成,每个节点上都会安装不同的组件
master:集群的控制平面,负责集群的决策
1、API Server:
资源操作的唯一入口,接受用户输入的命令,提供认证、授权、API注册和发现等机制
2、Scheduler:
负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
3、ControllerManager:
负责维护集群的状态,比如程序部署安排、故障检测、自动拓展、滚动更新
4、ETCD:
负责存储句群中各种资源对象的信息
node:集群的数据平面,负责为容器提供运行环境
1、Kubelet:
负责维护容器的生命周期,即通过控制docker来创建、更新、销毁容器
2、KubeProxy:
负责提供集群内部的服务发现和负载均衡
3、Docker
负责节点上容器的各种操作
模拟部署一个nginx服务来说明kubernetes系统各个组件调用关系:
1、kubernetes启动,先将master和node的信息存储到etcd中
2、一个nginx服务的安装请求先发送到master节点的ApiServer组件
3、ApiServer组件会调用Scheduler组件来决定到底应该把这个服务安装到哪个node节点上
Scheduler会在etcd中读取各个node节点的信息,然后按照算法进行选择,将结果告诉ApiServer
4、ApiServer调用ControllerManager去调度node节点安装nginx服务
5、kubelet接收到指令后,通知docker,然后由docker启动一个nginx的pod
pod是kubernetes的最小操作单元,容器必须跑在pod中
6、一个nginx服务就运行了,如果要访问nginx,就需要通过kube-proxy来对pod产生访问的代理
这样外界就可以访问集群中中的nginx服务了
4、kubernetes概念
Master:集群的控制节点,每个集群要求至少有一个master节点
Node:工作负载节点,由master分配容器到这写node节点上,然后node节点的docker负责容器运行
Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod可以有一个或多个容器
Controller:控制器,通过它来实现对pod的管理,例如启动pod,停止、伸缩
Service:pod对外服务的统一入口,下面可以维护着同一类多个pod
Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签
NameSpace:命名空间,用来隔离pod的运行环境
集群环境搭建
1、环境规划
集群类型:
- 一主多从:一台master和多台node,搭建简单,但是由单机故障风险
- 多主多从:多个master和多台node,搭建麻烦,安全性高
安装方式:
主流的由kubeadm、minikube、二进制包
- minikube:快速搭建单节点的kubernetes工具
- kubeadm:跨速搭建kubernetes集群的工具
- 二进制包:从官网下载每个组件的二进制包,依次安装,可以深入理解kubernetes
2、环境搭建
省略。。。
3、服务部署
在kubernetes集群中部署一个nginx程序,测试一下
# 部署nginx
kubectl create deployment nginx --image=nginx:1.14-alpine
# 暴露端口
kubectl expose deployment nginx --prot=80 --type=NodeProt
# 查看服务状态 svc==service
kubectl get pods,svc
# 在电脑上访问部署的nginx服务
资源管理
资源管理介绍
在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes
kubernetes的本质就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务
就是在kubernetes集群中运行一个个容器,并将指定的程序跑在容器中
kubernetes的最小管理单元是pod,只能将容器放在pod中,而kubernetes一般也不会直接
管理Pod,而是通过Pod控制器来管理Pod的
Pod可以提供服务之后,就要考虑如何访问pod中的服务,kubernetes提供了Service资源实现这个功能
如果Pod中程序的数据需要持久化,kubernetes提供了各种存储系统
YAML语法
YAML是一个类似于XML、JSON的标记性语言,它强调以数据为中心,并不是以标识语言为重点。因而YAML本身的定义比较简单,号称“一种人性化的数据格式语言”
YAML的语法简单,主要有下面几个:
- 大小写敏感
- 使用缩进标识层级关系
- 缩进不允许使用tab,只允许空格(只限制低版本)
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'标识注释
YAML支持一下几种数据类型:
- 纯量:单个的、不可再分的值
- 对象:键值对的集合,又称为映射(mapping)/哈希(hash)/字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence)/列表(list)
# 纯量,就是指的一个简单的值,字符串、整数、浮点数、Null、时间、日期
# 1 布尔类型
c1: true
# 2 整型
c2: 234
# 3 浮点型
c3: 3.14
# 4 null类型
c4: ~
# 5 日期类型
c5: 2022-03-08
# 6 时间类型
c6: 2022-03-08T11:10:31+08:00
# 7 字符串类型
c7: hehe
c8: list1
list2
# 对象
# 形式一(推荐)
student:
name: lisi
age: 18
# 形式二
student: {name: lisi,age: 15}
# 数组
# 形式一
adddres:
- 北京
- 上海
# 形式二
addres: [北京,上海]
资源管理方式
- 命令式对象管理:直接使用命令去操作Kubernetes资源
kubectl run nginx -pod --image=nginx:1.17.1 --prot=80
- 命令式对象配置:通过命令配置和配置文件去操作kubernetes资源
kubectl create/patch -f nginx-pod.yaml
- 声明式对象配置:通过apply命令和配置文件去操作kubernetes资源
# 只用于创建和更新资源
kubectl apply -f nginx-pod.yaml
类型 | 操作对象 | 适用环境 | 优点 | 缺点 |
命令式对象管理 | 对象 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 |
命令式对象配置 | 文件 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
声明式对象配置 | 目录 | 开发 | 支持目录操作 | 意外情况下难以调试 |
命令式对象管理
kubectl命令
kubectl式kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。
kubectl命令语法如下:
kubectl [command] [type] [name] [flags]
# comand:指定要对资源执行的操作,例如create、get、delete
# type:指定资源类型,比如deployment、pod、service
# name:指定资源的名称,名称大小写敏感
# flags:指定额外的可选参数
# 例子:
# 查看所有的pod
kubectl get pod
# 查看某个pod
kubectl get pod pod_name
# 查看某个pod,以yaml格式展示结果
kubectl get pod pod_name -o yaml
资源类型
kubernetes允许对资源进行多种操作,可以通过--help查看详细的操作命令
kubectl --help
命令式对象配置
命令式对象配置就是使用命令配合配置文件一起来操作kubernetes资源
1、创建一个nginxpod.yaml文件
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Pod
metadata:
name: nginxpod
namespace: dev
spec:
containers:
- name: nginx-continers
image: nginx:1.17.1
2、执行create命令,创建资源
kubectl create -f nginxpod.yaml
此时创建了两个资源对象,分别是namespace和pod
3、执行get命令,查看资源
kubectl get -f nginxpod.yml
4、执行delete命令,删除资源
kubectl delete -f nginxpod.yaml
资源被删除
声明式对象配置
声明式对象配置跟命令式对象很相似,但是它只有一个命令apply
# 先查询yaml资源
kubectl apply -f yaml
# 创建
kubectl apply -f nginxpod.yaml
# 再执行一次,发现资源没有变动
kubectl apply -f nginxpod.yaml
总结:
- 声明式对象配置使用apply描述一个资源最终的状态
- 使用apply操作资源:
- 如果资源不存在,就创建
- 如果资源存在,就更新
实战入门
Namespace
Namespace是kubernetes系统中的一种非常重要的资源,他的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离
默认情况下,kubernetes集群中的所有Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内容的资源分配到不同的Namespace中,可以形成逻辑上的组,以方便不同的组资源进行隔离使用和管理
可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量,内存使用量等等,来实现租户可用资源的管理
kubernetes集群启动之后,会默认创建几个namespace
default # 所有未指定Namespace的对象都会被分配在defaule中
kube-node-lease # 集群节点之间的心跳维护 v1.13开始引入
kube-public # 此命令空间下的资源可以被所有人访问 ,包括未认证用户
kube-system # 所有由kubernetes系统创建的资源都会处于这个命名空间中
常用命令:
# 1、查看所有的ns
kubectl get ns
# 2、查看指定的ns
kubectl get ns ns名称
# 3、指定输出格式
kubectl get ns ns名称 -o 格式参数
# 创建namespace
kubectl create ns dev
# 删除namespace
kubectl delete ns dev
使用配置文件来创建删除
准备一个yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev
- 创建命令:kubectl create -f ns-dev.yaml
- 删除命令:kubevtl delete -f ns-dev.yaml
Pod
Pod是kubernetes进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中
Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器
kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的,可以通过下面命令查看:
kubectl get pod -n kube-system
kubernetes没有提供单独运行Pod的命令,都是通过Pod控制器来实现的
运行
# 命令格式: kubectl run pod控制器名称 [参数]
# --image 指定Pod镜像
# --port 指定端口
# --namespace 指定namespace
kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
查看pod信息
# 查看pod基本信息
kubectl get pods -n dev
# 查看pod的详细信息
kubectl describe pod nginx-5ff7956ff6-fg2db -n dev
访问Pod
# 获取pod ip
kubectl get pods -n dev wide
删除指定pod
# 删除指定pod,删除成功之后控制器还会产生新的一个,想要彻底删除,删除pod控制器
kubectl delete pod podName -n dev
# 查询pod控制器
kubectl get deployment -n dev
# 删除pod控制器
kukbectl delete deployment nginx -n dev
配置文件方式
创建一个yaml文件
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: dev
spec:
containers:
- image: nginx:1.17.1
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
创建命令:kubectl create -f pod-nginx.yaml
删除命令:kubectl delete -f pod-nginx.yaml
Label
Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对他们进行区分和选择
Label特点:
- 一个Label会以key/value键值对的形式附加到各种对象上,如node、pod、service
- 一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去
- Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除
可以通过Label实现资源的多维度分组,以便灵活,方便的进行资源分配,调度,配置,部署
一些常用的Label:
- 版本标签:"version":"release","version":"stable"
- 环境标签:"environment":"dev","environment":"test"
- 架构标签:"tier":"frontend","tier","backend"
标签定义完之后,还要考虑到标签的选择,这就要使用到Label Selector,即:
Label用于给某个资源对象定义标识
Label Selector 用户查询和筛选拥有某些标签的资源对象
当前有两种Label Selector:
- 基于等式的Labael Selector
name = slave:选择所有包含Label中key="name"且value="slave"的对象
env != production:选择所有包含Label中的key="env"且value不等于"production"的对象 - 基于集合的Label Selector
name in (master,slave):选择所有包含Label中的key="name"且value="master"或"slave"的对象
name not in (frontend):选择所有包含Label中key="name"且value不等于"frontend"的对象
标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号进行分隔
例如:
name=slave,env != production
命令方式
# 为pod资源打标签
kubectl label pod nginx-pod version=1.0 -n dev
# 为pod资源更新标签
kubectl label pod nginx-pod version=2.0 -n dev --overwrite
# 查看标签
kubectl get pod nginx-pod -n dev --show-labels
# 筛选标签
kubectl get pod -n dev -l version=2.0 --show-labels
kubectl get pod -n dev -l version != 2.0 --show-labels
# 删除标签
kubectl label pod nginx-pod version- -n dev
配置方式
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
version: "3.0"
env: "test"
spec:
containers:
- image: nginx:1.17.1
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
执行对应的更新命令:
kubectl apply -f pod-nginx.yaml
Deployment
在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制pod,一般都是通过Pod控制器来完成的,Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建pod
在kubernet中Pod控制器的种类有很多,Deployment只是其中之一
# 命令模式:kubectl run depliyment名称 [参数]
# --image 指定pod的镜像
# --port 指定端口
# --replicas 指定创建pod数量
# --namespace 指定namespace
kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
# 查看创建的pod
kubectl get pods -n dev
# 查看deployment的信息
kubectl get deploy -n dev
# UP-TO-DATE:成功升级的副本数量
# ACAILABLE:可用副本的数量
kubectl get deploy -n dev -o wide
# 查看deployment的详细信息
kubectl describe deploy nginx -n dev
# 删除
kubectl delete deploy nginx -n dev
配置文件操作
文件名:deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment # Deployment 模板
metadata:
name: nginx
namespace: dev
spec:
replicas: 3 # 生成的pod的数量 副本数
selector:
matchLabels:
run: nginx # 选择器 选择对应标签的pod
template:
metadata: # Pod模板
labels:
run: nginx # 给pod定义的标签
spec:
containers:
- image: nginx:1.17.1
name: nginx
ports:
- containeProt: 80
protocol: TCP
然后就可以执行对应的创建和删除命令
创建:kubectl create -f deploy-nginx.yaml
删除:kubectl delete -f deploy-nginx.yaml
Service
虽然每个Pod都会分配一个单独的ip,然后却存在以下问题:
- Pod IP 会随着Pod的重建产生变化
- Pod IP仅仅是集群内可见的虚拟IP,外部无法访问
这样对于访问和这个服务器带来了难度,因此,kubernetes设计了Service来解决这个问题
Service可以看做是一组同类Pod对外的访问接口,借助Service,应用可以方便的实现服务发现和负载均衡
创建集群内部可访问的Service:
# 暴露Service
kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
# 查看Service
kubectl get service svc-nginx -n dev -o wide
创建集群外部可访问的Service:
# ClusterIP只用于集群内部访问
# NodePort才可以用于外部访问
kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
# 创建之后就可以通过当前集群节点的ip+查看Service暴露的随机端口来访问pod了
# 删除Service
kubectl delete service svc-nginx-1 -n dev
配置文件方式
创建一个集群内部可访问的Service
scv-nginx.yaml
apiVersion: apps/v1
kind: Service
metadata:
name: service-nginx
namespace: dev
spec:
clusterIP: 10.109.179.231
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx
type: ClusterIP
创建:kubectl create -f scv-nginx.yaml
删除:kubectl delete -f scv-nginx.yaml
Pod详解
Pod介绍
结构
每个Pod都可以包含一个或多个容器,这些容器可以分为两类:
- 自定义运行的容器实例
- Pause容器,这是每个Pod都会有的一个根容器
根容器保证了容器中的其他容器之间的网络通信
也是判别Pod的健康与否
Pod定义
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如 Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #Pod所属的命名空间,默认为"default"
labels: #自定义标签列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string