1.kubernetes介绍
Kubernetes容器集群管理系统,是Google开源的一个项目,目标是管理跨多个主机的容器,用于自动部署、扩展和管理容器化的应用程序,主要实现语言为Go 语言。
1.1特点:
可移植性、可扩展性、存储编排、自动化部署回滚、自我修复、服务发现负载均衡、机密管理配置管理
2.Kubernetes架构
2.1Kubernetes Master:
Master 节点是Kubernetes 集群的控制节点,负责整个集群的管理和控制。
Master 节点上包含以下组件:
1.kube-apiserver:提供了资源操作的唯一入口并提供认证、授权、访问控制、API 注册和发现等机制
2.kube-scheduler:负责资源的调度
3.kube-controller-manager:负责维护集群的状态比如故障检测、自动扩展、滚动更新等
4.etcd(键值数据库):保存了整个集群的状态,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)
2.2Kubernetes Node:
Node 节点是Kubernetes 集群中的工作节点,Node 上的工作负载由Master 节点分配,工作负载主要是运行容器应用。
Node 节点上包含以下组件:
1.kubelet:负责维持容器的生命周期,同时也负责Volume(CVI,Container Volume Interface)和网络(CNI,Container Network Interface)的管理
2.kube-proxy:负责为Service 提供cluster 内部的服务发现和负载均衡
3.Pod 网络(贯穿整个集群):Pod 要能够相互通信,Kubernetes Cluster 必须
部署Pod 网络Flannel 是其中一个可选方案,还有OpenvSwitch、Calico等
3.Kubernetes关键概念
1.namespace
1.Namespace用于实现多租户的资源隔离,通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
2.每个命名空间内的资源名称都是唯一的。
3.同一个命名空间内的服务可以通过DNS 使用服务名称互访,跨命名空间的服务,可以使用servicename.namespace 的方式进行访问。
查看命令空间:kubectl get namespaces
创建命令空间:kubectl create ns test
1.default --创建资源时如果不指定,将被放到这个Namespace 中
2.kube-system --Kubernetes 自己创建的系统资源将放到这个Namespace 中
3.kube-public --Kubernetes 公共的系统资源将放到这个Namespace 中
2.pod
1.Pod 是Kubernetes 应用程序的基本执行单元(最小资源单位),是一组容器的集合。
2.Pod 内部的容器共享网络栈
3.Pod 内部的容器可以共享存储卷
注释:
1.Pause Container:启动每个Pod都有一个特殊的被称为“根容器”的Pause容器,以它的状态代表整个容器组的状态。Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume,简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。
2.Init Container:在业务容器启动之前,会首先一次性的执行Init Container 的指令,这是一种专用的容器,在应用程序容器启动之前运行,用来包含一些应用镜像中不存在的实用工具或安装脚本。
3.业务容器:自定义容器,用于运行真正的业务代码
2.1在Kubernetes集群中Pod有如下两种使用方式:
1.一个Pod中运行一个容器。“每个Pod中一个容器”的模式是最常见的用法;在这种使用方式中,可以把Pod想象成是单个容器的封装,kuberentes管理的是Pod而不是直接管理容器。
- 在一个Pod中同时运行多个容器。一个Pod中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。
2.2Pod中可以共享两种资源:网络和存储
2.2.1.网络
每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。
2.2.2.存储
可以为一个Pod指定多个共享的Volume。Pod中的所有容器都可以访问共享的volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。
3.Controller
Kubernetes 通常不会直接创建Pod,而是通过Controller 来管理Pod 的。
1.Controller 中定义了Pod 的部署特性,可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力、在什么样的Node 上运行Pod等。
2.为了满足不同的业务场景,Kubernetes 提供了多种Controller,包括Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等。
3.1 Deployment
是最常用的Controller,定义Deployment创建Pod和ReplicaSet,可以管理Pod 的多个副本,并确保Pod 按照期望的状态运行。典型的应用场景包括:
➢滚动升级和回滚应用
➢扩容和缩容
➢暂停和继续Deployment
3.2 ReplicaSet
实现了Pod 的多副本管理。使用Deployment 时会自动创建ReplicaSet,也就是说Deployment是通过ReplicaSet 来管理Pod 的多个副本,我们通常不需要直接使用ReplicaSet。
3.3 StatefulSet
StatefulSet 作为Controller 为Pod 提供唯一的标识。解决有状态服务的Pod 的每个副本在整个生命周期中名称是不变,同时保证副本按照固定的顺序启动、更新或者删除(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
➢稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
➢稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
➢有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于initcontainers来实现
➢有序收缩,有序删除(即从N-1到0)
3.4 daemonset
DaemonSet 确保全部(或者一些)Node 上运行一个Pod 的副本。当有Node 加入集群时,也会为他们新增一个Pod 。当有Node 从集群移除时,这些Pod 也会被回收。删除DaemonSet 将会删除它创建的所有Pod。
使用DaemonSet 的一些典型用法:
➢运行集群存储daemon,例如在每个Node 上运行glusterd、ceph。
➢在每个Node 上运行日志收集daemon,例如fluentd、logstash。
➢在每个Node 上运行监控daemon,例如Prometheus Node Exporter、
collectd、Datadog 代理、New Relic 代理,或Ganglia gmond。
3.5 Job
用于运行一次性任务,运行结束就删除的应用。
保证批处理任务的一个或多个Pod成功结束,而其他类型的Controller 中Pod 通常是长期持续运行。
3.6 CronJob
1.CronJob其实就是在Job的基础上加上了时间调度
2.在给定的时间点运行一个任务,也可以周期性地在给定时间点运行。
这个实际上和Linux中的crontab就非常类似。一个CronJob对象其实就对应中crontab文件中的一行,它根据配置的时间格式周期性地运行一个Job,格式和crontab也是一样的。
4..Kubernetes 创建资源的方式:
4.1Kubernetes命令vs配置文件
- 用kubectl 命令直接创建,比如:
kubectl run httpd-app --image=reg.tstack.com/tstack/httpd:latest --replicas=2 在命令行中通过参数指定资源的属性。 - 通过yaml编排文件创建,要完成前面同样的工作,可执行命令:
kubectl apply -f httpd.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: httpd-deployment
spec:
replicas: 2 #副本数
template:
metadata:
labels:
name: httpd
spec:
containers:
- name: httpd-app
image: reg.tstack.com/tstack/httpd:latest #容器镜像
4.2YAML 基础:
kubernetes 集群通常使用YAML 文件来创建相关的资源。
它的基本语法规则如下:
格式规范:
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格。
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
井号表示注释,从这个字符一直到行尾,都会被解析器忽略。
4.2.1在kubernetes 中,需要两种结构类型:
Maps:是字典,就是一个key:value
Lists:列表,就是数组
list 的子项也可以是Maps,Maps 的子项也可以是list
#yaml格式:
---
apiVersion:v1
kind:Pod
metadata:
name:kube100-site
labels:
app:web
#json格式:
{
"apiVersion":"v1",
"kind":"Pod",
"metadata":{
"name":"kube100-site",
"labels":{
"app":"web"
}
}
}
#yaml格式:
---
apiVersion: v1
kind: Deployment
metadata:
name: kube100-site
labels:
app: web
spec:
containers:
- name: front-end
image: nginx
ports:
- containerPort: 80
- name: flaskapp-demo
image: jcdemo/flaskapp
ports:
- containerPort: 5000
5.Servcie:
1.Pod 可以部署多个副本,每个Pod 都有自己的IP,Pod 很可能会被频繁地销毁和重启,它们的IP 会发生变化,用IP 来访问不太现实。Kubernetes 运行容器(Pod)是由Controller执行,而访问容器(Pod)是Service 执行。
2.Service是将请求进行负载分发到后端的各个pod容器应用上的控制器。它定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过Label Selector(标签选择器)来实现无缝对接的。
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
tier: frontend
5.1 Pod IP:
每个Pod的IP地址,一个Pod里的容器访问另外一个Pod里的容器时,就是通过Pod IP所在的虚拟二层网络进行通信的,而真实的TCP/IP流量是通过Node IP所在的物理网卡流出。
5.2 Cluster IP :
就是Service 的IP ,是一个虚拟IP地址并由Kubernetes管理和分配。Service 为Pod 提供了负载均衡。
5.3 Node IP:
是Kubernetes集群中每个节点的物理网卡的IP地址,是一个真实存在的物理网络,所有属于这个网络的服务器都能通过这个网络直接通信,不管其中是否有部分节点不属于这个Kubernetes集群。
5.4 NodePort:
通过Cluster IP 只能是kubernetes集群内部的客户端访问到一组Pod,集群外部访问要在Pod所运行的Node上指定一个特定Port转发到Service Port 这个Port就是Node Port。
5.5 内部访问方式ClusterIP
ClusterIP服务是Kubernetes 的默认服务。是一个集群内的服务,集群内的其它应用都可以访问该服务。集群外部无法访问它。在某些场景下我们可以使用Kubernetes 的Proxy 模式来访问服务,比如调试服务时。
---
apiVersion: v1
kind: Namespace
metadata:
name: test
namespace: test
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: test
labels:
app: web
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-front-end
namespace: test
spec:
replicas: 2
template:
metadata:
labels:
name: nginx-front-end
app: web
spec:
containers:
- image: nginx
name: nginx-front-end
ports:
- containerPort: 80
5.6 外部访问方式NodePort
NodePort服务是引导外部流量到内部服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。
5.6.1 NodePort服务特征如下:
• 每个端口只能是一种服务
• 端口范围只能是30000-32767(可调)
• 不在YAML 配置文件中指定则会分配一个默认端口
5.6.2 建议:
不要在生产环境中使用这种方式暴露服务,大多数时候应该让Kubernetes 来选择端口
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: test
labels:
app: web
spec:
selector:
app: web
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodeProt: 31005
6.laber
Label标签,是附着到object上(例如Node、Pod、Service、RC等)的键值对。给object加入一些特定信息,通过LabelSelector (标签选择器)进行检索。
◆可以在创建object的时候指定,也可以在object创建后随时指定。
◆一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上。
◆一个Label是一个key=value的键值对,其中key与value由用户自己指定。
6.1 Label案例:控制Pod 启动的位置
默认配置下,Scheduler 会将Pod 调度到所有可用的Node。不过有些情况我们希望将Pod 部署到指定的Node,比如将有大量磁盘I/O 的Pod 部署到配置了SSD 的Node;或者Pod 需要GPU,需要运行在配置了GPU 的节点上。
Kubernetes 是通过label 来实现这个功能,灵活添加各种自定义属性。比如执行如下命令标注k8s-node3 是配置了SSD 的节点。
节点打标签
kubectl label node 172.16.254.23 disktype=ssd
查看节点标签
kubectl get node --show-labels
删除节点上的标签
kubectl label node 172.16.254.23 disktype-
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: httpd-deployment
spec:
replicas: 2
template:
metadata:
labels:
name: httpd
spec:
containers:
- name: httpd-app
image: reg.tstack.com/tstack/httpd:latest
nodeSelector:
disktype: ssd
7.ConfigMap:
分布式系统经常需要使用配置信息,Kubernetes 中使用Configmap 进行配置存储,所有配置参数存储在Etcd中,然后通过Volume映射的方式变成目标Pod内的配置文件,如果数据被修改,则映射到Pod中的“配置文件”也会随之自动更新。
7.1 ConfigMap 也支持四种创建方式:
7.1.1 通过--from-literal:
kubectl create configmap myconfigmap --from-literal=config1=xxx --from-literal=config2=yyy
每个--from-literal 对应一个信息条目。
7.1.2 通过--from-file:
echo -n xxx > ./config1
echo -n yyy > ./config2
kubectl create configmap myconfigmap --from-file=./config1 --from-file=./config2
每个文件内容对应一个信息条目。
7.1.3 通过--from-env-file:
cat << EOF > env.txt
config1=xxx
config2=yyy
EOF
kubectl create configmap myconfigmap --from-env-file=env.txt
文件env.txt 中每行Key=Value 对应一个信息条目。
7.1.4 通过YAML 配置文件:
Configmap 的结构很简单,除了Metadata,就只有一个Data 字段,其中保存了Keyvalue 的信息,例如:
apiVersion:v1
kind:ConfigMap
metadata:
name:myconfigmap
data:
key1:value1
key2:value2
7.1.5 平台内查看对应的configmap
kubectl get cm
如果需要修改服务对应的配置只需要修改对应configmap:kubectl edit cm xxx-config
8. Kubernetes网络——基础介绍
1.CNI(Container Network Interface):
容器网络接口,由一组用于配置Linux 容器的网络接口的规范和库组成,同时还包含了一些插件。CNI 仅关心容器创建时的网络分配,和当容器被删除时释放网络资源。
2.CNI 插件:
负责将网络接口插入容器网络命名空间(例如,vethpair的一端),并在主机上进行任何必要的改变(例如将veth pair的另一端连接到网桥)。然后将IP 分配给接口,并通过调用适当的IPAM 插件来设置与“IP 地址管理”部分一致的路由。
1、同一个Pod中容器间通信:同一个Pod的容器共享同一个网络命名空间,它们之间的访问可以用localhost地址+ 容器端口就可以访问。
2、同一Node中Pod间通信:同一Node中Pod的默认路由都是docker0的地址,由于它们关联在同一个docker0网桥上,地址网段相同,所有它们之间应当是能直接通信的。
3、不同Node中Pod间通信:不同Node中Pod间通信要满足2个条件:Pod的IP不能冲突;将Pod的IP和所在的Node的IP关联起来,通过这个关联让Pod可以互相访问。
8.1 Kubernetes网络——Flannel方案
Flannel是作为一个二进制文件的方式部署在每个node上:
8.1.1 主要实现两个功能:
• 为每个node分配subnet(子网),容器将自动从该子网中获取IP地址
• 当有node加入到网络中时,为每个node增加路由配置
9.Kubernetes网络——外部访问服务方式
9.2 ingress
通常情况下,Service 和Pod 的IP 仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到Service 在Node 上暴露的NodePort上,然后再由kube-proxy 通过边缘路由器(edge router) 将其转发给相关的Pod 或者丢弃。而Ingress 就是为进入集群的请求提供路由规则的集合
10. Kubernetes存储管理
10.1 Kubernetes Volume
容器和Pod 是短暂的,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除。使用Kubernetes Volume 可以持久化保存容器的数据,Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但Volume 会被保留。
10.1.1 Kubernetes Volume 类型:
◆ emptyDir:最基础的Volume 类型。正如其名字所示,一个emptyDir Volume 是Host 上的一个空目录。
◆ hostPath Volume:将Docker Host 文件系统中已经存在的目录mount 给Pod 的容器。
◆ 外部Storage Provider:Kubernetes可以对接第三方存储作为Volume 供给,例如NFS、GlusterFS、Ceph等。
10.2 Kubernetes中跟存储相关的概念有PersistentVolume(PV)和PersistentVolumeClaim(PVC):
◆ Persistent Volume(PV、持久卷)是集群之中的一块网络存储。跟Node 一样,也是集群的资源。PV 跟Volume (卷) 类似,不过会有独立于Pod 的生命周期。
◆ Persistent Volume Claim(PVC、持久卷消费者)作为用户对存储资源的需求,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。
10.2.1 PV又分为静态供给PV和动态PV供给:
1.静态供给(Static Provision):提前创建了PV,然后通过PVC 申请PV 并在Pod 中使用
2.动态供给(Dynamical Provision):即如果没有满足PVC 条件的PV,会动态创建PV。相比静态供给,动态供给有明显的优势:不需要提前创建PV,减少了管理员的工作量,效率高。
3.动态供给是通过StorageClass 实现的,StorageClass 定义了如何创建PV
10.2.2 Kubernetes存储管理——PV和PVC以及对应的rbd查看
kubectl get pv
kubectl get pvc
10.3Kubernetes通过访问模式给存储分为三大类:
◆ ReadWriteMany:多路读写,卷能被集群多个节点挂载并读写
◆ ReadWriteOnce:单路读写,卷只能被单个集群节点挂载读写
◆ ReadOnlyMany:多路只读,卷能被多个集群节点挂载且只能读
11.helm介绍
11.1 为什么使用helm?
Kubernetes虽然提供了多种容器编排对象,例如Deployment StatefulSet、DeamonSet、Job等,还有多种基础资源封装例如ConfigMap、Secret、Serivce等,但是一个应用往往有多个服务,有的可能还要依赖持久化存储,当这些服务之间直接互相依赖,需要有一定的组合的情况下,使用YAML文件的方式配置应用往往十分繁琐还容易出错,这时候就需要服务编排工具。
helm 类似于Linux系统下的包管理器,如yum/apt等,可以方便快捷的将之前打包好的yaml文件快速部署进kubernetes内,方便管理维护。只不过helm这儿管理的是在k8s上安装的各种容器。
• helm的作用:像centos7中的yum命令一样,管理软件包。
• tiller的作用:像centos7的软件仓库一样,简单说类似于/etc/yum.repos.d目录下的xxx.repo。
11.2Helm 三个重要概念:
◆ chart:包含了创建Kubernetes的一个应用实例的必要信息
◆ config:包含了应用发布配置信息
◆ release:是一个chart 及其配置的一个运行实例
11.3 Helm具有如下功能:
◆ 创建新的chart
◆ chart 打包成tgz 格式
◆ 上传chart 到chart 仓库或从仓库中下载chart
◆ 在Kubernetes集群中安装或卸载chart
◆ 管理用Helm安装的chart 的发布周期
11.3 chart 的基本结构
Helm的打包格式叫做chart,所谓chart就是一系列文件, 它描述了一组相关的k8s 集群资源。比如Service、Deployment、PersistentVolumeClaim、Secret、ConfigMap 等。Chart中的文件安装特定的目录结构组织, 最简单的chart 目录如下所示:
◆ charts:保存其他依赖的chart
◆ Chart.yaml:包含Chart的基本信息,包括chart版本,名称等
◆ templates:目录下存放应用一系列k8s 资源的yaml 模板
◆ _helpers.tpl:此文件中定义一些可重用的模板片断,此文件中的定义
在任何资源定义模板中可用
◆ NOTES.txt:介绍chart 部署后的帮助信息,如何使用chart等
◆ values.yaml:包含了必要的值定义(默认值), 用于存储templates
目录中模板文件中用到变量的值
11.4 Helm 架构
Helm 包含两个组件:Helm 客户端和Tiller 服务器。
11.4.1Helm 客户端是终端用户使用的命令行工具,用户可以:
1.在本地开发chart。
2.管理chart 仓库。
3.与Tiller 服务器交互。
4.在远程Kubernetes 集群上安装chart。
5.查看release 信息。
6.升级或卸载已有的release
11.4.2 Tiller 服务器运行在Kubernetes 集群中,它会处理Helm 客户端的请求,与Kubernetes API Server 交互。Tiller 服务器负责:
1.监听来自Helm 客户端的请求。
2.通过chart 构建release。
3.在Kubernetes 中安装chart,并跟踪release 的状态。
4.通过API Server 升级或卸载已有的release。
11.5 Helm 工作原理
11.5.1 Chart Install 过程:
Helm 从指定的目录或者TAR 文件中解析出Chart 结构信息。
Helm 将指定的Chart 结构和Values 信息通过gRPC传递给Tiller。
iller 根据Chart 和Values 生成一个Release。
Tiller 将Release 发送给Kubernetes 用于生成Release。
11.6 Helm 常用命令如下:
helm create:在本地创建新的chart
helm dependency:管理chart 依赖
helm intall:安装chart
helm lint:检查chart 配置是否有误
helm list:列出所有release
helm package:打包本地chart
helm repo:列出、增加、更新、删除chart 仓库
helm rollback:回滚release 到历史版本
helm pull:拉取远程chart 到本地
helm search:使用关键词搜索chart
helm uninstall:卸载release
helm upgrade:升级release