Hello Kubernetes

Posted by 石玉军 on 2018-12-13

上一篇文章中我们已经搭建起来了一个k8s集群,在本文中我们主要学习一下k8s中的一些基本概念、术语和常用的配置文件的定义。

在k8s中最常见的就是yaml文件了,通过一个简单的yaml文件我们就可以完成80%的功能,现在我们来编写一个简单的yaml文件nginx.yaml来启动一个nginx服务:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.9.6
ports:
- containerPort: 80

当我们使用如下命令以后k8s就会帮我们启动一个nginx服务

1
2
kubectl create -f nginx.yaml 
kubectl apply -f nginx.yaml

你可以使用如下命令来进行验证微服务是否已经启动成功

1
kubectl get pod

如果你想停止这两个微服务可以使用如下命令:

1
kubectl delete -f nginx.yaml

相信看到这里你对上方的nginx.yaml一定会充满好奇,下面就让我们来逐步解开k8s的面纱吧。

1. Master

每个k8s集群都最少需要一个Master节点来负责整个集群的管理和控制,它就是我们在上一篇文章中提到的主节点。Master主要包括以下进程:
1. kube-apiserver:k8s中所有资源增删改查等操作的唯一入口,也是集群控制的入口进程
2. kube-controller-manager:k8s中所有资源对象的自动化控制中心
3. kube-scheduler:负责资源调度的进程
4. etcd:k8s中所有的资源对象的数据都是保存在etcd中的

2. Node

除了Master在k8s集群中所有的机器都可以被称为Node节点,也就是上篇文章中的子节点。Node节点是集群中的工作负载节点,我们所有的微服务都是由Master负责调度到Node节点上进行执行的。Node节点主要包括以下进程:
1. kubelet:负责pod(下面会讲)对应的容器的创建、启动、停止等任务。
2. kube-proxy:负责k8s的通信与负载均衡机制的组件
3. Docker Engine:Daocker引擎,负责本机的容器创建和管理工作
在k8s中,我们可以使用如下命令来查看集群中的node节点

1
kubectl get node

通过如下命令查看某个node的详细信息

1
kubectl describe node node1

3. Pod

Pod是k8s中最基本也是最重要的概念,一个Pod主要包含两个组件:
1. 业务容器:一个pod中可以包含一个或多个业务容器
2.Pause:Pause是属于k8s平台的一部分,在Pod中单独设计一个Pause是为了两个方面的考虑。一是以Pause的状态来代表整个pod的状态,以起到监控应用的状态,二是为了当一个pod中包含多个容器时让这些容器共享Pause的Ip和挂载的Volume。
我们再来回顾一下文章开头的一个yaml文件中的各个属性的含义,不过相比文章开头的yaml此文件的属性要相对全一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
apiVersion: v1       #版本号
kind: Pod       #类型
metadata:       #元数据
  name: nginx       #Pod名称
spec:         #Pod中容器的详细定义
  containers:      #Pod中容器列表
  - name: nginx     #必选,容器名称
    image: nginx:1.9.6    #容器的镜像地址
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号列表
    - name: nginx    #端口号名称
      containerPort: 80   #容器需要监听的端口号
      hostPort: 8080    #容器所在主机需要监听的端口号类似于docker run -p 8080:80
    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     #内存清楚,容器启动的初始可用数量
    restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    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的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

4. Label

Label可以附加到k8s中的各种资源对象中,比如我们上方提到的Node、Pod以及接下来要学习的Service、RC、Deployment。我们可以给指定的资源对象绑定一个或多个label来实现多维度的资源分组管理功能。

Label的中文名称叫做标签,当一个应用被打上标签以后我们就可以通过Label Selector(标签选择器)去查询和筛选某些资源对象。听起来是不是和js的标签选择器差不多呢,其实就是差不多。Label Selector支持一下场景的表达式匹配方式
1. name = nginx
2. name != nginx
3. name in (nginx,mysql)
4. name not in (tomcat)
5. name = nginx ,env != test

如果我们要给我们的nginx服务加上一个Label的话,就应该这样操作

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1   #
kind: Pod
metadata:
name: nginx
labels: #标签
- name: nginx #标签名字
spec:
containers:
- name: nginx
image: nginx:1.9.6
ports:
- containerPort: 80

5. Replication Controller(RC)

RC是负责声明某中Pod的副本数量在任意时刻都符合某个预期值,RC的定义主要包括以下几个部分:
1. Pod期待的副本数
2. 用于筛选目标Pod的Label Selector
3. 到Pod数量小于目标Pod的时候用于创建新Pod的pod模板
使用RC最大的功能:

  1. 通过改变Pod的数量实现动态扩容
  2. Pod模板中的镜像版本实现滚动升级
    一个标准的RC应该是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1   
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 2 #副本数
selector: #标签选择器(LabelSelector)
matchLabels:
app: nginx
template: #模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.9.6
ports:
- containerPort: 80

6. Deployment

Deployment其实是相对于RC的一个升级,它相比于RC增加的功能就是让我们可以随时知道当前Pod的部署进度,配置文件上不同的就是版本号和类型了

1
2
3
4
5
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
·······

在Pod部署的时候我们可以通过执行以下命令来观察当前Pod的部署进度

1
kubectl get deployments

7. HPA

我们学习了RC以后知道了程序可以按照我们的逾期进行扩容,但是如果某一天突然流量超出我们的逾期了,这个情况k8s也为我们提供了解决方案,那就是HPA。

HPA可以通过追踪分析RC控制的所有Pod的的负载变化情况来确定是否进行针对性的调整。HPA主要有两种方式作为Pod负载的度量指标:
1. CPUUtilizationPercentage:目标Pod所有副本自身的CPU利用率的平均值
2. 应用程序自定义的度量指标。比如TPS或QPS
一个典型的HPA文件是这样的:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
kind: Deployment
name: nginx
minReplicas: 1 #最小容量
maxReplicas: 10 #最大扩容
targetCPUUtilizationPercentage: 30 #cpu利用率%

8. Service

因为Pod的地址信息会随着Pod的创建或销毁以及Master的调度而改变,当我们的服务想要对外提供服务时那么就势必需要一个固定对外暴露的端口,这个时候就到了Service出场的时候了。

首先Service会对外暴露一个固定不变的端口来接受请求,接受到请求以后能,它会通过Label Selector选择请求对应的Pod将请求转发过去。

一个service的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
sessionAffinity: ClientIP #使用本机ip
selector:
app: nginx #选择所有lable为nginx的pod
ports:
- port: 80
nodePort: 31080 #对外暴露端口

本文出自http://zhixiang.org.cn,转载请保留。