Kubernetes 中的大部分概念如 Node、 Pod、 ReplicationController、 Service 等都可以看作一种“资源对象”, 几乎所有的资源对象都可以通过 Kubernetes 提供的 kubectl 工具(或者 API 编程调用) 执行 增、 删、 改、 查 等操作并将其保存 在 etcd 中持久化存储。
Master
几乎所有的控制命令都是发给 Master 的,一般来说 Master 会单独部署在一个虚拟机或 X86服务器上
Master 的进程包括:
- Kubernetes API Server( kube- apiserver), 提供了 HTTP Rest 接口的关键服务进程, 是 Kubernetes 里所有资源的增、删、改、查等操作的唯一 入口,也是集群控制 的入口进程。
- Kubernetes Controller Manager( kube- controller- manager), Kubernetes 里所有资源对象的自动化控制中心, 可以理解为资源对象的“大总管”。
- Kubernetes Scheduler( kube- scheduler), 负责资源调度(Pod 调度)的程, 相当于公交公司的“ 调度室”。
其实 Master 节点上往往还启动了一个 etcd Server 进程, 因为 Kubernetes 里 的 所有 资源 对象 的 数据 全部 是 保存 在 etcd 中的。
Node
除了 Master,Kubernetes 集群中的其他机器被称为 Node 节点.
每个 Node 节点上都运行着以下一组关键进程。
- kubelet: 负责Pod 的创建 删除 启动 停止, 同时与 Master 节点密切协作, 实现集群管理的基本功能。
- kube- proxy: 实现 Kubernetes Service 的通信与负载均衡机制的重要组件。
- Docker Engine( dockerDocker 引擎, 负责本机的容器创建和管理工作。
查看节点
[root@centos ~]# kubectl get node
NAME STATUS AGE
127.0.0.1 Ready 2d
查看节点详细信息,包括磁盘状态
[root@centos ~]# kubectl describe node 127.0.0.1
Name: 127.0.0.1 # 节点名称
Role:
Labels: beta.kubernetes.io/arch=amd64 # 节点标签
beta.kubernetes.io/os=linux
kubernetes.io/hostname=127.0.0.1
Taints: <none>
CreationTimestamp: Fri, 02 Mar 2018 21:59:52 +0800 # 创建时间
Phase:
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
OutOfDisk False Mon, 05 Mar 2018 10:24:15 +0800 Fri, 02 Mar 2018 21:59:52 +0800 KubeletHasSufficientDisk kubelet has sufficient disk space available # 磁盘信息 True 表示磁盘满了.
MemoryPressure False Mon, 05 Mar 2018 10:24:15 +0800 Fri, 02 Mar 2018 21:59:52 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Mon, 05 Mar 2018 10:24:15 +0800 Fri, 02 Mar 2018 21:59:52 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
Ready True Mon, 05 Mar 2018 10:24:15 +0800 Sat, 03 Mar 2018 10:50:27 +0800 KubeletReady kubelet is posting ready status
Addresses: 127.0.0.1,127.0.0.1,127.0.0.1
Capacity:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 4
memory: 8002252Ki
pods: 110
Allocatable:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 4
memory: 8002252Ki
pods: 110
System Info:
Machine ID: 3ce150b846d1364ca00934cb4b7425e7
System UUID: 6648964A-8A37-49F8-AE2E-CD51D601E0A4
Boot ID: 6c79106a-2825-43e5-a49a-ce1837fed475
Kernel Version: 3.10.0-693.el7.x86_64
OS Image: CentOS Linux 7 (Core)
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://1.12.6
Kubelet Version: v1.5.2
Kube-Proxy Version: v1.5.2
ExternalID: 127.0.0.1
Non-terminated Pods: (6 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
default mysql-j6vpx 0 (0%) 0 (0%) 0 (0%) 0 (0%)
default myweb-cwhhl 0 (0%) 0 (0%) 0 (0%) 0 (0%)
default myweb-ljwtl 0 (0%) 0 (0%) 0 (0%) 0 (0%)
default myweb-n0vrj 0 (0%) 0 (0%) 0 (0%) 0 (0%)
default myweb-rnjq9 0 (0%) 0 (0%) 0 (0%) 0 (0%)
default myweb-sgfhs 0 (0%) 0 (0%) 0 (0%) 0 (0%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
0 (0%) 0 (0%) 0 (0%) 0 (0%)
No events.
Pod
Pod 是 kubernetes 中 最基本的单位,每个 Pod 都有一个根容器叫 Pause
为什么需要根容器?
- 一组容器作为一个 Pod,无法对整体进行简单的判断并作出行动,比如一个容器死了是整体都死了吗?因此需要一个无关的根容器来代表整个容器的状态.
- Pod 的多个业务容器共享 Pause 的 IP, 并共享容器挂载的卷,既解决了通信问题又解决了共享问题
kubernetes 中,每个Pod都分配了一个唯一的 IP, 称之为 Pod-IP, 不同 Pod 和其他 pod 是可以通信的
在 Kubernetes 里, 一个计算资源进行配额限定需要设定以下两个参数。
- Requests: 该资源的最小申请量,系统必须满足要求。
- Limits: 该资源最大允许使用的量, 不能被突破, 当容器试图使用超过这个量的资源时, 可能会被 Kubernetes Kill 并重启。
通常来说我们会把 Requests 的值设置为一个比较小的数值,符合容器平时的工作负载情况下的资源需求,而 Limit 设置为峰值负载情况下资源占用的最大量,比如下面这段,表明 MYSQL 容器申请至少0.25个 CPU 一级64MiB 内存,在运行过程中容器所使用的资源配额为0.5个 CPU 以及128MiB 内存:
spec:
containers:
- name: db
image: mysql
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Label
一个 Label 是一个 key=value 的键值对,由用户自主设定, Label 可以附加到各种资源对象上,例如 Node、Pod、Service、RC 等,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源对象上去,Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。
Label 定义后,可以通过 Label Selector 查询和筛选拥有某些 Label 的资源对象。查询类似 SQL的 where 查询条件:
- name = redis-slave 匹配name等于 redis-slave 的资源对象。
- env != production 匹配不具有标签 env=production 的资源对象, 比如 env=test 就满足此条件。
- name in (redis-slave,redis-master) 匹配所有包含 redis-slave 和 redis-master 的资源对象。
- name notin (php-frontend),匹配所有不具有标签 name=php-frontend 的资源对象
多个表达式可以组合实现,需要用”,” 分割,几个条件之间是 “AND” 的关系
name= redis- slave, env!= production
name notin (php- frontend), env!= production
Label 选择器的使用场景:
- kube-controller 进程通过资源对象 RC 定义标签来筛选要监控的副本数量,实现自动控制流程。
- kube-proxy 进程通过 service 的标签选择器来选择对应的 Pod,自动建立每个 service 到对应 Pod的请求转发路由表,从而实现 service 的智能负载均衡机制。
- 通过对某些 Node 定义特定标签,并且在 Pod 定义文件中使用 NodeSelector 这种标签调度策略,kube-scheduler 进程可实现 Pod“定向调度”的特性。
多 label
RC
RC 定义了一个期望的场景,即声明某种 Pod 的副本数在任何时候都符合预期,其包括:
- 副本数
- 用于筛选的 Pod 和 标签选择器
- 当 Pod 副本数小于预期数量时,用于创建新 Pod 的模板
RC 提交到集群–Master Controller Manager 组件收到通知,定期巡检当前存活的目标 Pod,并确保目标 Pod 实力数量刚好等于此 RC 的预期值,如果多于 Pod 副本,就会停掉一些,否则会创建一些 Pod。
动态缩放rc
[root@centos ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 2d
myweb 5 5 5 1d
[root@centos ~]# kubectl scale rc mysql --replicas=3
replicationcontroller "mysql" scaled
[root@centos ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 3 3 1 2d
myweb 5 5 5 1d
[root@centos ~]#
删除 RC 并不会影响通过该 RC 已经创建好的 Pod,为了删除所有 Pod,可以设置 replicas=0 然后更新该 RC,另外可以使用 stop 或 delete 删除 RC 和 RC 控制的全部 Pod。
Deployment
从 k8s 1.2引入的新概念, 与RC 相似度90%,目的是为了更好的解决 Pod 的编排问题。Deployment 在内部使用了 Replica Set 来实现目的。
Deployment 相对于 RC 的一个最大的升级就是随时知道当前 Pod “部署”的进度
Deployment 的场景:
- 创建一个 DP 对象来生成对应的 Replica Set 并完成 Pod 副本的创建过程。
- 检查 DP 的状态来看部署动作是否完成。
- 更新 DP 以创建新的 Pod(比如镜像升级)。
- 如果当前 DP 不稳定,回滚到一个早先的 DP 版本。
- 挂起或恢复一个 DP
例子,tomcat-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier,operator: In,values: [frontend]}
template:
metadata:
labels:
app: app-demo
tier: frontend
spec:
containers:
- name: tomcat-demo
image: tomcat
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
然后在集群中创建 deployment
[root@centos ~]# kubectl create -f tomcat-dp.yaml
deployment "frontend" created
然后查看
[root@centos ~]# kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
frontend 1 1 1 1 2m
其中
- DESIRED 为 Pod 副本数量的期望值,即定义的 Replica。
- CURRENT 为当前的 Replica 值,它会不断变化直到达到 DESIRED 值,表明整个部署过程完成。
- UP-TO-DATA 最新版本的 Pod 的副本数量,在滚动升级过程中,有多少个 Pod 副本已经升级成功了。
- AVAILABLE 当前集群中可用的 Pod 副本数量。
查看对应的 Replica Set
[root@centos ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend-141477217 1 1 1 11m
查看 pods
[root@centos ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
frontend-141477217-jcckp 1/1 Running 0 12m
HPA
HPA = Horizontal Pod Autoscaler 意思是横向自动扩容。
通过手工执行 kubectl scale 效率低,不符合自动化、智能化的定位。HPA 通过追踪分析 RC 控制的所有目标 Pod 的负载变化情况,来确定是否需要针对性的调整目标 Pod 的副本数,这是 HPA 的实现原理。
HPA 的Pod 负载度量指标:
- CPUutilizationPercentage,目标 Pod 所有副本自身 CPU 利用率的平均值。
- 引用程序自定义的度量指标,比如服务在每秒内的请求数(TPS 或 QPS)
例子
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name:php-apache
namespace: default
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90
命令方式实现
kubectl autoscale deployment php- apache --cpu- percent= 90 --min= 1 --max= 10
Service
之前的 Pod RC 都是为服务做“嫁衣”的
k8s 定义了一个服务的访问入口地址,前端通过这个入口访问其背后的一组由 Pod 副本组成的集群,service 与后端 Pod 通过 label selector 来实现对接。 而 RC 的作用是保证 service 的服务能能力和服务质量能够始终处于预期的标准。
每个 Pod 都会被分配一个单独的 IP 地址,而且每个 Pod 都提供一个独立的 endpoint 以被客户端访问,现在多个 Pod 组成的集群提供服务,一般是需要部署一个负载均衡器实现转发。在 k8s 中,node 上的 kube-proxy 就是一个软件负载均衡器,它负责把对 service 的请求转发到后端的某个 Pod 实例上,部署实现服务的负载均衡与会话保持机制,每个 service 分配一个全局唯一的虚拟 IP 地址,这个虚拟 IP 被称为 cluster IP,其在 service 的整个生命周期内是不变的。
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
ports:
- port: 8080
selector:
tier: frontend
这里的标签与之前创建的 Tomcat 对应,查看暴露的地址和端口
[root@centos ~]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.10.115:6443 2d
mysql 172.17.0.3:3306 3m
tomcat-service 172.17.0.2:8080 37s
查看 service 的 cluster IP:
[root@centos ~]# kubectl get svc tomcat-service -o yaml
得到如下内容
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2018-03-05T06:46:41Z
name: tomcat-service
namespace: default
resourceVersion: "256242"
selfLink: /api/v1/namespaces/default/services/tomcat-service
uid: f6544c3e-2040-11e8-b481-fa163eee21c2
spec:
clusterIP: 10.254.1.165
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
tier: frontend
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
其中 targetPort 属性用来确定提供该服务的容器暴露(EXPOSE)的端口,而 port 则定义 service 的虚拟端口,因为前面 Tomcat 没有指定 targetport,则默认与 port 相同。
多端口问题
其样例:
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
ports:
- port: 8080
name: service-port
- port: 8005
name: shutdown-port
selector:
tier: frontend
为什么要给多端口命名,这就需要涉及 k8s 的服务发现了。
服务发现
首先,每个 k8s 中的 service 都有一个唯一的 cluster IP 以及唯一的名字,而名字是由开发者自定义的,部署的时候也没必要改变,所以完全可以固定在配置中。
早期 k8s 采用 linux 环境变量的方式解决问题。
这种方式不太方便,后来 k8s 通过 ADD-On 增值包的方式引入了 DNS 系统,把服务名作为 DNS 域名。
外部系统访问 service 的问题
采用nodeport 访问最为直接,但是 nodeport 无法解决例如负载均衡的问题,需要有一个 load balancer
Volume (存储卷)
k8s 的 volume 是 Pod 中能够给多容器访问的共享目录,与 docker 的 volume 类似,但不等价。首先,k8s 的 volume 定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下,其次,k8s 的 volume 与 Pod 的生命周期相同,但是与容器的生命周期不相关。最后,k8s 支持多种类型的 volume,例如 ceph 等分布式文件系统。
k8s 的 volume 类型有:emptyDir(初始为空的,用来存放一些临时文件)、hostPath(主机文件或目录,存放日子等需要永久保存的文件)、gcePersistentDisk(谷歌公有云的永久磁盘,数据不会被删除,但是有限制条件)、awsElasticBlockStore(与前者类似)、NFS、其他类型的(iscsi等)。
Persistent volume
简称 PV,可以理解为 k8s 集群中的某个网络存储中对应的一块存储:
- PV 只能是网络存储,不属于任何 Node,但是可以在 Node 上访问。
- PV 并不是定义在 Pod 上,而是独立在 Pod 之外。
- PV 目前的类型有 GCE NFS RBD iSCSCI aswElasticBlockStore GlusterFS
Namespace
中文名命令空间,可以实现多租户的资源隔离,通过将集群内部的资源对象分配到不同的 namespace 中,形成逻辑上分组的不同项目、小组或用户组,便于不同分组在共享使用整个集群的资源的同时还能被分别管理。
默认会有一个 default 的 namespace。
[root@centos ~]# kubectl get namespaces
NAME STATUS AGE
default Active 2d
kube-system Active 2d
如果不特别指明,则创建的 Pod RC service 都会被分配到 default 中。
定义 namespace,创建一个 namespace-demo.yaml 的文件
apiVersion: v1
kind: Namespace
metadata:
name: development
然后创建查看 namespace
[root@centos ~]# kubectl create -f namespace-demo.yaml
namespace "development" created
[root@centos ~]# kubectl get namespaces
NAME STATUS AGE
default Active 2d
development Active 4s
kube-system Active 2d
添加一个pod 的配置,直到其 namespace 为 development
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: development
spec:
containers:
- image: busybox
command:
- sleep
- "36000"
name: busybox
创建
[root@centos ~]# kubectl create -f busybox.yaml
pod "busybox" created
查看
[root@centos ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
frontend-141477217-jcckp 1/1 Running 0 1h
mysql-7p27m 1/1 Running 0 42m
myweb-0n7b9 1/1 Running 0 42m
myweb-5dcff 1/1 Running 0 42m
myweb-mbxk4 1/1 Running 0 42m
myweb-md64b 1/1 Running 0 42m
myweb-rkql9 1/1 Running 0 42m
直接查看不显示,需要加参数
[root@centos ~]# kubectl get pods --namespace=development
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 57s