03 Kubernetes快速入门

unlisted · suofeiya's blog

#kubernetes

Table of Contents

写在前面 #

kubernetes中涉及很多概念,包含云生态社区中各类技术,学习成本比较高,k8s中通常以编写yaml文件完成资源的部署,对于较多入门的人来说是个较高的门坎,本文以命令行的形式带领大家快速入门,俯瞰kubernetes核心概念,快速入门。

1. 基础概念 #

1.1 集群与节点 #

kubernetes是一个开源的容器引擎管理平台,实现容器化应用的自动化部署,任务调度,弹性伸缩,负载均衡等功能,cluster是由master和node两种角色组成

imgkubernetes集群概念

1、查看master组件角色

1[root@node-1 ~]# kubectl get componentstatuses 
2NAME                 STATUS    MESSAGE             ERROR
3scheduler            Healthy   ok                  
4controller-manager   Healthy   ok                  
5etcd-0               Healthy   {"health":"true"}   

2、 查看node节点列表

1[root@node-1 ~]# kubectl get nodes
2NAME     STATUS   ROLES    AGE   VERSION
3node-1   Ready    master   26h   v1.14.1
4node-2   Ready    <none>   26h   v1.14.1
5node-3   Ready    <none>   26h   v1.14.1

3、查看node节点详情

 1[root@node-1 ~]# kubectl describe node node-3
 2Name:               node-3
 3Roles:              <none>
 4Labels:             beta.kubernetes.io/arch=amd64。#标签和Annotations
 5                    beta.kubernetes.io/os=linux
 6                    kubernetes.io/arch=amd64
 7                    kubernetes.io/hostname=node-3
 8                    kubernetes.io/os=linux
 9Annotations:        flannel.alpha.coreos.com/backend-data: {"VtepMAC":"22:f8:75:bb:da:4e"}
10                    flannel.alpha.coreos.com/backend-type: vxlan
11                    flannel.alpha.coreos.com/kube-subnet-manager: true
12                    flannel.alpha.coreos.com/public-ip: 10.254.100.103
13                    kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
14                    node.alpha.kubernetes.io/ttl: 0
15                    volumes.kubernetes.io/controller-managed-attach-detach: true
16CreationTimestamp:  Sat, 10 Aug 2019 17:50:00 +0800
17Taints:             <none>
18Unschedulable:      false。#是否禁用调度cordon命令控制的标识位
19Conditions:     #资源调度能力MemoryPressure内存是否有压力即内存不足
20                #DiskPressure磁盘压力
21                #PIDPressure磁盘压力
22                #Ready是否就绪表明节点是否处于正常工作状态表示资源充足+相关进程状态正常
23  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
24  ----             ------  -----------------                 ------------------                ------                       -------
25  MemoryPressure   False   Sun, 11 Aug 2019 20:32:07 +0800   Sat, 10 Aug 2019 17:50:00 +0800   KubeletHasSufficientMemory   kubelet has sufficient memory available
26  DiskPressure     False   Sun, 11 Aug 2019 20:32:07 +0800   Sat, 10 Aug 2019 17:50:00 +0800   KubeletHasNoDiskPressure     kubelet has no disk pressure
27  PIDPressure      False   Sun, 11 Aug 2019 20:32:07 +0800   Sat, 10 Aug 2019 17:50:00 +0800   KubeletHasSufficientPID      kubelet has sufficient PID available
28  Ready            True    Sun, 11 Aug 2019 20:32:07 +0800   Sat, 10 Aug 2019 18:04:20 +0800   KubeletReady                 kubelet is posting ready status
29Addresses:     #地址和主机名
30  InternalIP:  10.254.100.103
31  Hostname:    node-3
32Capacity:      #容器的资源容量
33 cpu:                2
34 ephemeral-storage:  51473868Ki
35 hugepages-2Mi:      0
36 memory:             3880524Ki
37 pods:               110
38Allocatable:    #已分配资源情况
39 cpu:                2
40 ephemeral-storage:  47438316671
41 hugepages-2Mi:      0
42 memory:             3778124Ki
43 pods:               110
44System Info:     #系统信息如内核版本操作系统版本cpu架构node节点软件版本
45 Machine ID:                 0ea734564f9a4e2881b866b82d679dfc
46 System UUID:                D98ECAB1-2D9E-41CC-9A5E-51A44DC5BB97
47 Boot ID:                    6ec81f5b-cb05-4322-b47a-a8e046d9bf79
48 Kernel Version:             3.10.0-957.el7.x86_64
49 OS Image:                   CentOS Linux 7 (Core)
50 Operating System:           linux
51 Architecture:               amd64
52 Container Runtime Version:  docker://18.3.1 .     #Container Runtime为docker,版本为18.3.1
53 Kubelet Version:            v1.14.1               #kubelet版本
54 Kube-Proxy Version:         v1.14.1               #kube-proxy版本
55PodCIDR:                     10.244.2.0/24         #pod使用的网络
56Non-terminated Pods:         (4 in total)        #下面是每个pod资源占用情况
57  Namespace                  Name                           CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
58  ---------                  ----                           ------------  ----------  ---------------  -------------  ---
59  kube-system                coredns-fb8b8dccf-hrqm8        100m (5%)     0 (0%)      70Mi (1%)        170Mi (4%)     26h
60  kube-system                coredns-fb8b8dccf-qwwks        100m (5%)     0 (0%)      70Mi (1%)        170Mi (4%)     26h
61  kube-system                kube-flannel-ds-amd64-zzm2g    100m (5%)     100m (5%)   50Mi (1%)        50Mi (1%)      26h
62  kube-system                kube-proxy-x8zqh               0 (0%)        0 (0%)      0 (0%)           0 (0%)         26h
63Allocated resources:   #已分配资源情况
64  (Total limits may be over 100 percent, i.e., overcommitted.)
65  Resource           Requests    Limits
66  --------           --------    ------
67  cpu                300m (15%)  100m (5%)
68  memory             190Mi (5%)  390Mi (10%)
69  ephemeral-storage  0 (0%)      0 (0%)
70Events:              <none>

1.2 容器与应用 #

kubernetes是容器编排引擎,其负责容器的调度,管理和容器的运行,但kubernetes调度最小单位并非是container,而是pod,pod中可包含多个container,通常集群中不会直接运行pod,而是通过各种工作负载的控制器如Deployments,ReplicaSets,DaemonSets的方式运行,为啥?因为控制器能够保证pod状态的一致性,正如官方所描述的一样“make sure the current state match to the desire state”,确保当前状态和预期的一致,简单来说就是pod异常了,控制器会在其他节点重建,确保集群当前运行的pod和预期设定的一致。

imgcontainer与pod

1.3 服务访问 #

kubernetes中pod是实际运行的载体,pod依附于node中,node可能会出现故障,kubernetes的控制器如replicasets会在其他node上重新拉起一个pod,新的pod会分配一个新的IP;再者,应用部署时会包含多个副本replicas,如同个应用deployments部署了3个pod副本,pod相当于后端的Real Server,如何实现这三个应用访问呢?对于这种情况,我们一般会在Real Server前面加一个负载均衡Load Balancer,service就是pod的负载均衡调度器,service将动态的pod抽象为一个服务,应用程序直接访问service即可,service会自动将请求转发到后端的pod。负责service转发规则有两种机制:iptables和ipvs,iptables通过设置DNAT等规则实现负载均衡,ipvs通过ipvsadm设置转发规。

imgservice概念

根据服务不同的访问方式,service分为如下几种类型:ClusterIP,NodePort,LoadBalancer和_ExternalName,可通过type设置。

pod是动态变化的,ip地址可能会变化(如node故障),副本数可能会变化,如应用扩展scale up,应用锁容scale down等,service如何识别到pod的动态变化呢?答案是labels,通过labels自动会过滤出某个应用的Endpoints,当pod变化时会自动更新Endpoints,不同的应用会有由不同的label组成。labels相关可以参考下https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/

imgservice与labels

2. 创建应用 #

我们开始部署一个应用即deployments,kubernetes中包含各种workload如无状态话的Deployments,有状态化的StatefulSets,守护进程的DaemonSets,每种workload对应不同的应用场景,我们先以Deployments为例入门,其他workload均以此类似,一般而言,在kubernetes中部署应用均以yaml文件方式部署,对于初学者而言,编写yaml文件太冗长,不适合初学,我们先kubectl命令行方式实现API的接入。

1、部署nginx应用,部署三个副本

1[root@node-1 ~]# kubectl run nginx-app-demo --image=nginx:1.7.9 --port=80 --replicas=3 
2kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
3deployment.apps/nginx-app-demo created

2、查看应用列表,可以看到当前pod的状态均已正常,Ready是当前状态,AVAILABLE是目标状态

1[root@node-1 ~]# kubectl get deployments
2NAME             READY   UP-TO-DATE   AVAILABLE   AGE
3nginx-app-demo   3/3     3            3           72s

3、查看应用的详细信息,如下我们可以知道Deployments是通过ReplicaSets控制副本数的,由Replicaset控制pod数

 1[root@node-1 ~]# kubectl describe deployments nginx-app-demo 
 2Name:                   nginx-app-demo     #应用名称
 3Namespace:              default            #命名空间
 4CreationTimestamp:      Sun, 11 Aug 2019 21:52:32 +0800
 5Labels:                 run=nginx-app-demo #labels很重要后续service通过labels实现访问
 6Annotations:            deployment.kubernetes.io/revision: 1 #滚动升级版本号
 7Selector:               run=nginx-app-demo #labels的选择器selector
 8Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable #副本控制器
 9StrategyType:           RollingUpdate     #升级策略为RollingUpdate
10MinReadySeconds:        0
11RollingUpdateStrategy:  25% max unavailable, 25% max surge #RollingUpdate升级策略即最大不超过25%的pod
12Pod Template:   #容器应用模版包含镜像port存储等
13  Labels:  run=nginx-app-demo
14  Containers:
15   nginx-app-demo:
16    Image:        nginx:1.7.9
17    Port:         80/TCP
18    Host Port:    0/TCP
19    Environment:  <none>
20    Mounts:       <none>
21  Volumes:        <none>
22Conditions:  #当前状态
23  Type           Status  Reason
24  ----           ------  ------
25  Available      True    MinimumReplicasAvailable
26  Progressing    True    NewReplicaSetAvailable
27OldReplicaSets:  <none>
28NewReplicaSet:   nginx-app-demo-7bdfd97dcd (3/3 replicas created) #ReplicaSets控制器名称
29Events:  #运行事件
30  Type    Reason             Age    From                   Message
31  ----    ------             ----   ----                   -------
32  Normal  ScalingReplicaSet  3m24s  deployment-controller  Scaled up replica set nginx-app-demo-7bdfd97dcd to 3

4、查看replicasets情况,通过查看可知replicasets副本控制器生成了三个pod

 11. 查看replicasets列表
 2  [root@node-1 ~]# kubectl get replicasets
 3NAME                        DESIRED   CURRENT   READY   AGE
 4nginx-app-demo-7bdfd97dcd   3         3         3       9m9s
 5
 62. 查看replicasets详情
 7[root@node-1 ~]# kubectl describe replicasets nginx-app-demo-7bdfd97dcd 
 8Name:           nginx-app-demo-7bdfd97dcd
 9Namespace:      default
10Selector:       pod-template-hash=7bdfd97dcd,run=nginx-app-demo
11Labels:         pod-template-hash=7bdfd97dcd #labels增加了一个hash的label识别replicasets
12                run=nginx-app-demo
13Annotations:    deployment.kubernetes.io/desired-replicas: 3 #滚动升级的信息副本树最大数应用版本
14                deployment.kubernetes.io/max-replicas: 4
15                deployment.kubernetes.io/revision: 1
16Controlled By:  Deployment/nginx-app-demo #副本的父控制为nginx-app-demo这个Deployments
17Replicas:       3 current / 3 desired
18Pods Status:    3 Running / 0 Waiting / 0 Succeeded / 0 Failed
19Pod Template:  #容器模板继承于deployments
20  Labels:  pod-template-hash=7bdfd97dcd
21           run=nginx-app-demo
22  Containers:
23   nginx-app-demo:
24    Image:        nginx:1.7.9
25    Port:         80/TCP
26    Host Port:    0/TCP
27    Environment:  <none>
28    Mounts:       <none>
29  Volumes:        <none>
30Events: #事件日志生成了三个不同的pod
31  Type    Reason            Age    From                   Message
32  ----    ------            ----   ----                   -------
33  Normal  SuccessfulCreate  9m25s  replicaset-controller  Created pod: nginx-app-demo-7bdfd97dcd-hsrft
34  Normal  SuccessfulCreate  9m25s  replicaset-controller  Created pod: nginx-app-demo-7bdfd97dcd-qtbzd
35  Normal  SuccessfulCreate  9m25s  replicaset-controller  Created pod: nginx-app-demo-7bdfd97dcd-7t72x

5、查看pod的情况,实际应用部署的载体,pod中部署了一个nginx的容器并分配了一个ip,可通过该ip直接访问应用

 11. 查看pod的列表和replicasets生成的名称一致
 2[root@node-1 ~]# kubectl get pods
 3NAME                              READY   STATUS    RESTARTS   AGE
 4nginx-app-demo-7bdfd97dcd-7t72x   1/1     Running   0          13m
 5nginx-app-demo-7bdfd97dcd-hsrft   1/1     Running   0          13m
 6nginx-app-demo-7bdfd97dcd-qtbzd   1/1     Running   0          13m
 7
 8查看pod的详情
 9[root@node-1 ~]# kubectl describe pods nginx-app-demo-7bdfd97dcd-7t72x 
10Name:               nginx-app-demo-7bdfd97dcd-7t72x
11Namespace:          default
12Priority:           0
13PriorityClassName:  <none>
14Node:               node-3/10.254.100.103
15Start Time:         Sun, 11 Aug 2019 21:52:32 +0800
16Labels:             pod-template-hash=7bdfd97dcd  #labels名称
17                    run=nginx-app-demo
18Annotations:        <none>
19Status:             Running
20IP:                 10.244.2.4 #pod的ip地址
21Controlled By:      ReplicaSet/nginx-app-demo-7bdfd97dcd #副本控制器为replicasets
22Containers:   #容器的信息包括容器id镜像丢按扣状态环境变量等信息
23  nginx-app-demo:
24    Container ID:   docker://5a0e5560583c5929e9768487cef43b045af4c6d3b7b927d9daf181cb28867766
25    Image:          nginx:1.7.9
26    Image ID:       docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
27    Port:           80/TCP
28    Host Port:      0/TCP
29    State:          Running
30      Started:      Sun, 11 Aug 2019 21:52:40 +0800
31    Ready:          True
32    Restart Count:  0
33    Environment:    <none>
34    Mounts:
35      /var/run/secrets/kubernetes.io/serviceaccount from default-token-txhkc (ro)
36Conditions: #容器的状态条件
37  Type              Status
38  Initialized       True 
39  Ready             True 
40  ContainersReady   True 
41  PodScheduled      True 
42Volumes:    #容器卷
43  default-token-txhkc:
44    Type:        Secret (a volume populated by a Secret)
45    SecretName:  default-token-txhkc
46    Optional:    false
47QoS Class:       BestEffort #QOS类型
48Node-Selectors:  <none> #污点类型
49Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
50                 node.kubernetes.io/unreachable:NoExecute for 300s
51Events:  #事件状态拉镜像启动容器
52  Type    Reason     Age   From               Message
53  ----    ------     ----  ----               -------
54  Normal  Scheduled  14m   default-scheduler  Successfully assigned default/nginx-app-demo-7bdfd97dcd-7t72x to node-3
55  Normal  Pulling    14m   kubelet, node-3    Pulling image "nginx:1.7.9"
56  Normal  Pulled     14m   kubelet, node-3    Successfully pulled image "nginx:1.7.9"
57  Normal  Created    14m   kubelet, node-3    Created container nginx-app-demo
58  Normal  Started    14m   kubelet, node-3    Started container nginx-app-demo

3. 访问应用 #

kubernetes为每个pod都分配了一个ip地址,可通过该地址直接访问应用,相当于访问RS,但一个应用是一个整体,由多个副本数组成,需要依赖于service来实现应用的负载均衡,service我们探讨ClusterIP和NodePort的访问方式。

1、设置pod的内容,为了方便区分,我们将三个pod的nginx站点内容设置为不同,以观察负载均衡的效果

 1查看pod列表
 2[root@node-1 ~]# kubectl get pods
 3NAME                              READY   STATUS    RESTARTS   AGE
 4nginx-app-demo-7bdfd97dcd-7t72x   1/1     Running   0          28m
 5nginx-app-demo-7bdfd97dcd-hsrft   1/1     Running   0          28m
 6nginx-app-demo-7bdfd97dcd-qtbzd   1/1     Running   0          28m
 7
 8进入pod容器中
 9[root@node-1 ~]# kubectl exec -it nginx-app-demo-7bdfd97dcd-7t72x /bin/bash
10
11设置站点内容
12[root@nginx-app-demo-7bdfd97dcd-7t72x:/# echo "web1" >/usr/share/nginx/html/index.html
13 
14以此类推设置另外两个pod的内容为web2和web3
15[root@nginx-app-demo-7bdfd97dcd-hsrft:/# echo web2 >/usr/share/nginx/html/index.html
16[root@nginx-app-demo-7bdfd97dcd-qtbzd:/# echo web3 >/usr/share/nginx/html/index.html

2、获取pod的ip地址,如何快速获取pod的ip地址呢,可以通过-o wide参数显示更多的内容,会包含pod所属node和ip

1[root@node-1 ~]# kubectl get pods -o wide 
2NAME                              READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
3nginx-app-demo-7bdfd97dcd-7t72x   1/1     Running   0          34m   10.244.2.4   node-3   <none>           <none>
4nginx-app-demo-7bdfd97dcd-hsrft   1/1     Running   0          34m   10.244.1.2   node-2   <none>           <none>
5nginx-app-demo-7bdfd97dcd-qtbzd   1/1     Running   0          34m   10.244.1.3   node-2   <none>           <none>

3、访问pod的ip,查看站点内容,不同的pod站点内容和上述步骤设置一致。

1[root@node-1 ~]# curl http://10.244.2.4
2web1
3[root@node-1 ~]# curl http://10.244.1.2
4web2
5[root@node-1 ~]# curl http://10.244.1.3
6web3

3.1 ClusterIP访问 #

通过pod的ip直接访问应用,对于单个pod的应用可以实现,对于多个副本replicas的应用则不符合要求,需要通过service来实现负载均衡,service需要设置不同的type,默认为ClusterIP即集群内部访问,如下通过expose子命令将服务暴露到service。

1、暴露service,其中port表示代理监听端口,target-port代表是容器的端口,type设置的是service的类型

1[root@node-1 ~]# kubectl expose deployment nginx-app-demo --name nginx-service-demo \
2--port=80 \
3--protocol=TCP \
4--target-port=80 \
5--type ClusterIP 
6service/nginx-service-demo exposed

2、查看service的详情,可以看到service通过labels选择器selector自动将pod的ip生成endpoints

 1查看service列表显示有两个kubernetes为默认集群创建的service
 2[root@node-1 ~]# kubectl get services
 3NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
 4kubernetes           ClusterIP   10.96.0.1    <none>        443/TCP   29h
 5nginx-service-demo   ClusterIP   10.102.1.1   <none>        80/TCP    2m54s
 6
 7查看service详情可以看到Labels的Seletor和前面Deployments设置一致Endpoints将pod组成一个列表
 8[root@node-1 ~]# kubectl describe services nginx-service-demo 
 9Name:              nginx-service-demo   #名称
10Namespace:         default              #命名空间
11Labels:            run=nginx-app-demo   #标签名称
12Annotations:       <none>
13Selector:          run=nginx-app-demo   #标签选择器
14Type:              ClusterIP            #service类型为ClusterIP
15IP:                10.102.1.1           #服务的ip即vip集群内部会自动分配一个
16Port:              <unset>  80/TCP      #服务端口即ClusterIP对外访问的端口
17TargetPort:        80/TCP               #容器端口
18Endpoints:         10.244.1.2:80,10.244.1.3:80,10.244.2.4:80 #访问地址列表
19Session Affinity:  None                 #负载均衡调度算法
20Events:            <none>

3、访问service的地址,可以访问的内容可知,service自动实现了pods的负载均衡,调度策略为轮询,为何?因为service默认的调度策略Session Affinity为None,即是轮训,可以设置为ClientIP,实现会话保持,相同客户端IP的请求会调度到相同的pod上。

1[root@node-1 ~]# curl http://10.102.1.1
2web3
3[root@node-1 ~]# curl http://10.102.1.1
4web1
5[root@node-1 ~]# curl http://10.102.1.1
6web2
7[root@node-1 ~]# curl http://10.102.1.1

4、ClusterIP原理深入剖析,service后端实现有两种机制:iptables和ipvs,环境安装采用iptables,iptables通过nat的链生成访问规则,KUBE-SVC-R5Y5DZHD7Q6DDTFZ为入站DNAT转发规则,KUBE-MARK-MASQ为出站转发

1[root@node-1 ~]# iptables -t nat -L -n
2Chain KUBE-SERVICES (2 references)
3target     prot opt source               destination         
4KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.102.1.1           /* default/nginx-service-demo: cluster IP */ tcp dpt:80
5KUBE-SVC-R5Y5DZHD7Q6DDTFZ  tcp  --  0.0.0.0/0            10.102.1.1           /* default/nginx-service-demo: cluster IP */ tcp dpt:80
6
7出站KUBE-MARK-MASQ源地址段不是10.244.0.0/16访问10.102.1.1的目标端口80时将请求转发给KUBE-MARK-MASQ链
8入站KUBE-SVC-R5Y5DZHD7Q6DDTFZ任意原地址访问目标10.102.1.1的目标端口80时将请求转发给KUBE-SVC-R5Y5DZHD7Q6DDTFZ链

5、查看入站请求规则,入站请求规则将会映射到不同的链,不同链将会转发到不同pod的ip上。

 11. 查看入站规则KUBE-SVC-R5Y5DZHD7Q6DDTFZ请求将转发至三条链
 2[root@node-1 ~]# iptables -t nat -L KUBE-SVC-R5Y5DZHD7Q6DDTFZ -n
 3Chain KUBE-SVC-R5Y5DZHD7Q6DDTFZ (1 references)
 4target     prot opt source               destination         
 5KUBE-SEP-DSWLUQNR4UPH24AX  all  --  0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.33332999982
 6KUBE-SEP-56SLMGHHOILJT36K  all  --  0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.50000000000
 7KUBE-SEP-K6G4Z74HQYF6X7SI  all  --  0.0.0.0/0            0.0.0.0/0 
 8
 92. 查看实际转发的三条链的规则,实际映射到不同的pod的ip地址上
10[root@node-1 ~]# iptables -t nat -L KUBE-SEP-DSWLUQNR4UPH24AX  -n
11Chain KUBE-SEP-DSWLUQNR4UPH24AX (1 references)
12target     prot opt source               destination         
13KUBE-MARK-MASQ  all  --  10.244.1.2           0.0.0.0/0           
14DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.1.2:80
15
16[root@node-1 ~]# iptables -t nat -L KUBE-SEP-56SLMGHHOILJT36K  -n
17Chain KUBE-SEP-56SLMGHHOILJT36K (1 references)
18target     prot opt source               destination         
19KUBE-MARK-MASQ  all  --  10.244.1.3           0.0.0.0/0           
20DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.1.3:80
21
22[root@node-1 ~]# iptables -t nat -L KUBE-SEP-K6G4Z74HQYF6X7SI   -n
23Chain KUBE-SEP-K6G4Z74HQYF6X7SI (1 references)
24target     prot opt source               destination         
25KUBE-MARK-MASQ  all  --  10.244.2.4           0.0.0.0/0           
26DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.2.4:80     

3.2 NodePort访问 #

Service通过ClusterIP只能提供集群内部的应用访问,外部无法直接访问应用,如果需要外部访问有如下几种方式:NodePort,LoadBalancer和Ingress,其中LoadBalancer需要由云服务提供商实现,Ingress需要安装单独的Ingress Controller,日常测试可以通过NodePort的方式实现,NodePort可以将node的某个端口暴露给外部网络访问。

1、修改type的类型由ClusterIP修改为NodePort类型(或者重新创建,指定type的类型为NodePort)

 11. 通过patch修改type的类型
 2[root@node-1 ~]# kubectl patch services nginx-service-demo -p '{"spec":{"type": "NodePort"}}'
 3service/nginx-service-demo patched
 4
 52. 确认yaml文件配置分配了一个NodePort端口即每个node上都会监听该端口
 6[root@node-1 ~]# kubectl get services nginx-service-demo -o yaml
 7apiVersion: v1
 8kind: Service
 9metadata:
10  creationTimestamp: "2019-08-11T14:35:59Z"
11  labels:
12    run: nginx-app-demo
13  name: nginx-service-demo
14  namespace: default
15  resourceVersion: "157676"
16  selfLink: /api/v1/namespaces/default/services/nginx-service-demo
17  uid: 55e29b78-bc45-11e9-b073-525400490421
18spec:
19  clusterIP: 10.102.1.1
20  externalTrafficPolicy: Cluster
21  ports:
22  - nodePort: 32416 #自动分配了一个NodePort端口
23    port: 80
24    protocol: TCP
25    targetPort: 80
26  selector:
27    run: nginx-app-demo
28  sessionAffinity: None
29  type: NodePort #类型修改为NodePort
30status:
31  loadBalancer: {}
32  
333. 查看service列表可以知道service的type已经修改为NodePort,同时还保留ClusterIP的访问IP
34[root@node-1 ~]# kubectl get services
35NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
36kubernetes           ClusterIP   10.96.0.1    <none>        443/TCP        30h
37nginx-service-demo   NodePort    10.102.1.1   <none>        80:32416/TCP   68m

2、通过NodePort访问应用程序,每个node的地址相当于vip,可以实现相同的负载均衡效果,同时CluserIP功能依可用

 11. NodePort的负载均衡
 2[root@node-1 ~]# curl http://node-1:32416
 3web1
 4[root@node-1 ~]# curl http://node-2:32416
 5web1
 6[root@node-1 ~]# curl http://node-3:32416
 7web1
 8[root@node-1 ~]# curl http://node-3:32416
 9web3
10[root@node-1 ~]# curl http://node-3:32416
11web2
12
132. ClusterIP的负载均衡
14[root@node-1 ~]# curl http://10.102.1.1
15web2
16[root@node-1 ~]# curl http://10.102.1.1
17web1
18[root@node-1 ~]# curl http://10.102.1.1
19web1
20[root@node-1 ~]# curl http://10.102.1.1
21web3

3、NodePort转发原理,每个node上通过kube-proxy监听NodePort的端口,由后端的iptables实现端口的转发

 11. NodePort监听端口
 2[root@node-1 ~]# netstat -antupl |grep 32416
 3tcp6       0      0 :::32416                :::*                    LISTEN      32052/kube-proxy 
 4
 52. 查看nat表的转发规则有两条规则KUBE-MARK-MASQ出口和KUBE-SVC-R5Y5DZHD7Q6DDTFZ入站方向
 6Chain KUBE-NODEPORTS (1 references)
 7target     prot opt source               destination         
 8KUBE-MARK-MASQ  tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/nginx-service-demo: */ tcp dpt:32416
 9KUBE-SVC-R5Y5DZHD7Q6DDTFZ  tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/nginx-service-demo: */ tcp dpt:32416
10
113. 查看入站的请求规则链KUBE-SVC-R5Y5DZHD7Q6DDTFZ 
12[root@node-1 ~]# iptables -t nat -L KUBE-SVC-R5Y5DZHD7Q6DDTFZ  -n
13Chain KUBE-SVC-R5Y5DZHD7Q6DDTFZ (2 references)
14target     prot opt source               destination         
15KUBE-SEP-DSWLUQNR4UPH24AX  all  --  0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.33332999982
16KUBE-SEP-56SLMGHHOILJT36K  all  --  0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.50000000000
17KUBE-SEP-K6G4Z74HQYF6X7SI  all  --  0.0.0.0/0            0.0.0.0/0          
18
194. 继续查看转发链包含有DNAT转发和KUBE-MARK-MASQ和出站返回的规则
20[root@node-1 ~]# iptables -t nat -L KUBE-SEP-DSWLUQNR4UPH24AX  -n
21Chain KUBE-SEP-DSWLUQNR4UPH24AX (1 references)
22target     prot opt source               destination         
23KUBE-MARK-MASQ  all  --  10.244.1.2           0.0.0.0/0           
24DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.1.2:80
25
26[root@node-1 ~]# iptables -t nat -L KUBE-SEP-56SLMGHHOILJT36K  -n
27Chain KUBE-SEP-56SLMGHHOILJT36K (1 references)
28target     prot opt source               destination         
29KUBE-MARK-MASQ  all  --  10.244.1.3           0.0.0.0/0           
30DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.1.3:80
31
32
33[root@node-1 ~]# iptables -t nat -L KUBE-SEP-K6G4Z74HQYF6X7SI   -n
34Chain KUBE-SEP-K6G4Z74HQYF6X7SI (1 references)
35target     prot opt source               destination         
36KUBE-MARK-MASQ  all  --  10.244.2.4           0.0.0.0/0           
37DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp to:10.244.2.4:80

4. 扩展应用 #

当应用程序的负载比较高无法满足应用请求时,一般我们会通过扩展RS的数量来实现,在kubernetes中,扩展RS实际上通过扩展副本数replicas来实现,扩展RS非常便利,快速实现弹性伸缩。kubernets能提供两种方式的伸缩能力:1. 手动伸缩能力scale up和scale down,2. 动态的弹性伸缩horizontalpodautoscalers,基于CPU的利用率实现自动的弹性伸缩,需要依赖与监控组件如metrics server,当前未实现,后续再做深入探讨,本文以手动的scale的方式扩展应用的副本数。

imgDeployments副本扩展

1、手动扩展副本数

1[root@node-1 ~]# kubectl scale  --replicas=4 deployment nginx-app-demo 
2deployment.extensions/nginx-app-demo scaled

2、查看副本扩展情况,deployments自动部署一个应用

1[root@node-1 ~]# kubectl get deployments
2NAME             READY   UP-TO-DATE   AVAILABLE   AGE
3nginx-app-demo   4/4     4            4           133m

3、此时service的情况会怎样呢?查看service详情,新扩展的pod会自动更新到service的endpoints中,自动服务发现

 1查看service详情
 2[root@node-1 ~]# kubectl describe services nginx-service-demo 
 3Name:                     nginx-service-demo
 4Namespace:                default
 5Labels:                   run=nginx-app-demo
 6Annotations:              <none>
 7Selector:                 run=nginx-app-demo
 8Type:                     NodePort
 9IP:                       10.102.1.1
10Port:                     <unset>  80/TCP
11TargetPort:               80/TCP
12NodePort:                 <unset>  32416/TCP
13Endpoints:                10.244.1.2:80,10.244.1.3:80,10.244.2.4:80 + 1 more...#地址已自动加入
14Session Affinity:         None
15External Traffic Policy:  Cluster
16Events:                   <none>
17
18查看endpioints详情
19[root@node-1 ~]# kubectl describe endpoints nginx-service-demo  
20Name:         nginx-service-demo
21Namespace:    default
22Labels:       run=nginx-app-demo
23Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2019-08-11T16:04:56Z
24Subsets:
25  Addresses:          10.244.1.2,10.244.1.3,10.244.2.4,10.244.2.5
26  NotReadyAddresses:  <none>
27  Ports:
28    Name     Port  Protocol
29    ----     ----  --------
30    <unset>  80    TCP
31
32Events:  <none>

4、测试,将新加入的pod站点内容设置为web4,参考前面的设置方法,测试service的ip,查看负载均衡效果

 1[root@node-1 ~]# curl http://10.102.1.1
 2web4
 3[root@node-1 ~]# curl http://10.102.1.1
 4web4
 5[root@node-1 ~]# curl http://10.102.1.1
 6web2
 7[root@node-1 ~]# curl http://10.102.1.1
 8web3
 9[root@node-1 ~]# curl http://10.102.1.1
10web1
11[root@node-1 ~]# curl http://10.102.1.1
12web2
13[root@node-1 ~]# curl http://10.102.1.1
14web1

由此可知,弹性伸缩会自动自动加入到service中实现服务自动发现和负载均衡,应用的扩展相比于传统应用快速非常多。此外,kubernetes还支持自动弹性扩展的能力,即Horizontal Pod AutoScaler,自动横向伸缩能力,配合监控系统根据CPU的利用率弹性扩展Pod个数,详情可以参考文档kubernetes系列教程(十九)使用metric-server让HPA弹性伸缩愉快运行

5. 滚动升级 #

在kubernetes中更新应用程序时可以将应用程序打包到镜像中,然后更新应用程序的镜像以实现升级。默认Deployments的升级策略为RollingUpdate,其每次会更新应用中的25%的pod,新建新的pod逐个替换,防止应用程序在升级过程中不可用。同时,如果应用程序升级过程中失败,还可以通过回滚的方式将应用程序回滚到之前的状态,回滚时通过replicasets的方式实现。

img滚动更新

1、更换nginx的镜像,将应用升级至最新版本,打开另外一个窗口使用kubectl get pods -w观察升级过程

1[root@node-1 ~]# kubectl set image deployments/nginx-app-demo nginx-app-demo=nginx:latest
2deployment.extensions/nginx-app-demo image updated

2、观察升级过程,通过查看可知,升级过程中是通过新建+删除的方式逐个替换pod的方式

 1[root@node-1 ~]# kubectl get pods -w
 2NAME                              READY   STATUS    RESTARTS   AGE
 3nginx-app-demo-7bdfd97dcd-7t72x   1/1     Running   0          145m
 4nginx-app-demo-7bdfd97dcd-hsrft   1/1     Running   0          145m
 5nginx-app-demo-7bdfd97dcd-j6lgd   1/1     Running   0          12m
 6nginx-app-demo-7bdfd97dcd-qtbzd   1/1     Running   0          145m
 7nginx-app-demo-5cc8746f96-xsxz4   0/1     Pending   0          0s #新建一个pod
 8nginx-app-demo-5cc8746f96-xsxz4   0/1     Pending   0          0s
 9nginx-app-demo-7bdfd97dcd-j6lgd   1/1     Terminating   0          14m #删除旧的pod替换
10nginx-app-demo-5cc8746f96-xsxz4   0/1     ContainerCreating   0          0s
11nginx-app-demo-5cc8746f96-s49nv   0/1     Pending             0          0s #新建第二个pod
12nginx-app-demo-5cc8746f96-s49nv   0/1     Pending             0          0s
13nginx-app-demo-5cc8746f96-s49nv   0/1     ContainerCreating   0          0s
14nginx-app-demo-7bdfd97dcd-j6lgd   0/1     Terminating         0          14m #更换第二个pod
15nginx-app-demo-5cc8746f96-s49nv   1/1     Running             0          7s
16nginx-app-demo-7bdfd97dcd-qtbzd   1/1     Terminating         0          146m
17nginx-app-demo-5cc8746f96-txjqh   0/1     Pending             0          0s
18nginx-app-demo-5cc8746f96-txjqh   0/1     Pending             0          0s
19nginx-app-demo-5cc8746f96-txjqh   0/1     ContainerCreating   0          0s
20nginx-app-demo-7bdfd97dcd-j6lgd   0/1     Terminating         0          14m
21nginx-app-demo-7bdfd97dcd-j6lgd   0/1     Terminating         0          14m
22nginx-app-demo-5cc8746f96-xsxz4   1/1     Running             0          9s
23nginx-app-demo-5cc8746f96-txjqh   1/1     Running             0          1s
24nginx-app-demo-7bdfd97dcd-hsrft   1/1     Terminating         0          146m
25nginx-app-demo-7bdfd97dcd-qtbzd   0/1     Terminating         0          146m
26nginx-app-demo-5cc8746f96-rcpmw   0/1     Pending             0          0s
27nginx-app-demo-5cc8746f96-rcpmw   0/1     Pending             0          0s
28nginx-app-demo-5cc8746f96-rcpmw   0/1     ContainerCreating   0          0s
29nginx-app-demo-7bdfd97dcd-7t72x   1/1     Terminating         0          146m
30nginx-app-demo-7bdfd97dcd-7t72x   0/1     Terminating         0          147m
31nginx-app-demo-7bdfd97dcd-hsrft   0/1     Terminating         0          147m
32nginx-app-demo-7bdfd97dcd-hsrft   0/1     Terminating         0          147m
33nginx-app-demo-5cc8746f96-rcpmw   1/1     Running             0          2s
34nginx-app-demo-7bdfd97dcd-7t72x   0/1     Terminating         0          147m
35nginx-app-demo-7bdfd97dcd-7t72x   0/1     Terminating         0          147m
36nginx-app-demo-7bdfd97dcd-hsrft   0/1     Terminating         0          147m
37nginx-app-demo-7bdfd97dcd-hsrft   0/1     Terminating         0          147m
38nginx-app-demo-7bdfd97dcd-qtbzd   0/1     Terminating         0          147m
39nginx-app-demo-7bdfd97dcd-qtbzd   0/1     Terminating         0          147m

3、再次查看deployments的详情可知道,deployments已经更换了新的replicasets,原来的replicasets的版本为1,可用于回滚。

 1[root@node-1 ~]# kubectl describe deployments nginx-app-demo 
 2Name:                   nginx-app-demo
 3Namespace:              default
 4CreationTimestamp:      Sun, 11 Aug 2019 21:52:32 +0800
 5Labels:                 run=nginx-app-demo
 6Annotations:            deployment.kubernetes.io/revision: 2 #新的版本号用于回滚
 7Selector:               run=nginx-app-demo
 8Replicas:               4 desired | 4 updated | 4 total | 4 available | 0 unavailable
 9StrategyType:           RollingUpdate
10MinReadySeconds:        0
11RollingUpdateStrategy:  25% max unavailable, 25% max surge
12Pod Template:
13  Labels:  run=nginx-app-demo
14  Containers:
15   nginx-app-demo:
16    Image:        nginx:latest
17    Port:         80/TCP
18    Host Port:    0/TCP
19    Environment:  <none>
20    Mounts:       <none>
21  Volumes:        <none>
22Conditions:
23  Type           Status  Reason
24  ----           ------  ------
25  Available      True    MinimumReplicasAvailable
26  Progressing    True    NewReplicaSetAvailable
27OldReplicaSets:  <none>
28NewReplicaSet:   nginx-app-demo-5cc8746f96 (4/4 replicas created) #新的replicaset实际是替换新的replicasets
29Events:
30  Type    Reason             Age    From                   Message
31  ----    ------             ----   ----                   -------
32  Normal  ScalingReplicaSet  19m    deployment-controller  Scaled up replica set nginx-app-demo-7bdfd97dcd to 4
33  Normal  ScalingReplicaSet  4m51s  deployment-controller  Scaled up replica set nginx-app-demo-5cc8746f96 to 1
34  Normal  ScalingReplicaSet  4m51s  deployment-controller  Scaled down replica set nginx-app-demo-7bdfd97dcd to 3
35  Normal  ScalingReplicaSet  4m51s  deployment-controller  Scaled up replica set nginx-app-demo-5cc8746f96 to 2
36  Normal  ScalingReplicaSet  4m43s  deployment-controller  Scaled down replica set nginx-app-demo-7bdfd97dcd to 2
37  Normal  ScalingReplicaSet  4m43s  deployment-controller  Scaled up replica set nginx-app-demo-5cc8746f96 to 3
38  Normal  ScalingReplicaSet  4m42s  deployment-controller  Scaled down replica set nginx-app-demo-7bdfd97dcd to 1
39  Normal  ScalingReplicaSet  4m42s  deployment-controller  Scaled up replica set nginx-app-demo-5cc8746f96 to 4
40  Normal  ScalingReplicaSet  4m42s  deployment-controller  Scaled down replica set nginx-app-demo-7bdfd97dcd to 0

4、查看滚动升级的版本,可以看到有两个版本,分别对应的两个不同的replicasets

 1[root@node-1 ~]# kubectl rollout history deployment nginx-app-demo 
 2deployment.extensions/nginx-app-demo 
 3REVISION  CHANGE-CAUSE
 41         <none>
 52         <none>
 6
 7查看replicasets列表,旧的包含pod为0
 8[root@node-1 ~]# kubectl get replicasets
 9NAME                        DESIRED   CURRENT   READY   AGE
10nginx-app-demo-5cc8746f96   4         4         4       9m2s
11nginx-app-demo-7bdfd97dcd   0         0         0       155m

5、测试应用的升级情况,发现nginx已经升级到最新nginx/1.17.2版本

 1[root@node-1 ~]# curl -I http://10.102.1.1
 2HTTP/1.1 200 OK
 3Server: nginx/1.17.2 #nginx版本信息
 4Date: Sun, 11 Aug 2019 16:30:03 GMT
 5Content-Type: text/html
 6Content-Length: 612
 7Last-Modified: Tue, 23 Jul 2019 11:45:37 GMT
 8Connection: keep-alive
 9ETag: "5d36f361-264"
10Accept-Ranges: bytes

6、回滚到旧的版本

 1[root@node-1 ~]# kubectl rollout undo deployment nginx-app-demo --to-revision=1
 2deployment.extensions/nginx-app-demo rolled back
 3
 4再次测应用,已经回滚到旧版本
 5[root@node-1 ~]# curl -I http://10.102.1.1
 6HTTP/1.1 200 OK
 7Server: nginx/1.7.9
 8Date: Sun, 11 Aug 2019 16:34:33 GMT
 9Content-Type: text/html
10Content-Length: 612
11Last-Modified: Tue, 23 Dec 2014 16:25:09 GMT
12Connection: keep-alive
13ETag: "54999765-264"
14Accept-Ranges: bytes

6. 故障迁移 #

img故障迁移

集群中的node节点物理服务器可能会因为各种原因导致机器不可用,如硬件故障,软件故障,网络故障等原因,当发生故障时容器可能会出现不可用,进而影响业务的使用。kubernetes内置已提供了应用的容错能力,通过工作负载Workload如Deployments,StatefulSets来控制,当node节点异常时会自动将其上的pod迁移至其他node节点上,保障应用的高可用。

Kubeadm默认部署的集群,默认当节点异常时,需要5min后才能迁移,因为默认pod中设置了污点容忍tolerations,当检测到节点状态是not-ready或者unreachable时,容忍tolerationSeconds时长300s后才做驱逐,如下是看pod详情中设置的污点容忍信息

1  tolerations:
2  - effect: NoExecute
3    key: node.kubernetes.io/not-ready
4    operator: Exists
5    tolerationSeconds: 300
6  - effect: NoExecute
7    key: node.kubernetes.io/unreachable
8    operator: Exists
9    tolerationSeconds: 300

如下是手动创建的yaml文件,通过调整污点容忍的时长为2s,当节点异常时,其上的pod能够实现快速迁移到其他node节点

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  labels:
 5    run: test
 6  name: test
 7spec:
 8  replicas: 3
 9  selector:
10    matchLabels:
11      run: test
12  template:
13    metadata:
14      labels:
15        run: test
16    spec:
17      containers:
18      - image: nginx:1.7.9
19        name: test
20        ports:
21        - containerPort: 3
22        resources: {}
23      tolerations:
24      - effect: NoExecute
25        key: node.kubernetes.io/not-ready
26        operator: Exists
27        tolerationSeconds: 2 
28      - effect: NoExecute
29        key: node.kubernetes.io/unreachable
30        operator: Exists
31        tolerationSeconds: 2 

写在最后 #

本文以命令行的方式实践探索kubernetes中涉及的最重要的几个概念:应用部署,负载均衡,弹性伸缩和滚动升级,故障迁移,并以命令行的形式实际操作,读者可以参照文档实现快速入门,后续会大部分以yaml文件的形式部署和kubernets交互。

参考文档 #

基础概念:https://kubernetes.io/docs/tutorials/kubernetes-basics/

部署应用:https://kubernetes.io/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/

访问应用:https://kubernetes.io/docs/tutorials/kubernetes-basics/explore/explore-intro/

外部访问:https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/

访问应用:https://kubernetes.io/docs/tutorials/kubernetes-basics/scale/scale-intro/

滚动升级:https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/

『 转载 』该文章来源于网络,侵删。