# 学习 k8s 的基础知识
此笔记详细参考:https://kubernetes.io/zh/docs/tutorials/kubernetes-basics/
# 部署应用
# k8s 部署
一旦运行了 Kubernetes 集群,就可以在其上部署容器化应用程序。 为此,您需要创建 Kubernetes Deployment 配置。Deployment 指挥 Kubernetes 如何创建和更新应用程序的实例。创建 Deployment 后,Kubernetes master 将应用程序实例调度到集群中的各个节点上。
# 使用 kubectl 创建 Deployment
# 查看 client 和 server 版本
kubectl version
# 查看集群中的节点
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 85s v1.17.3
# 创建应用
# 需要应用名称 和完整的 image 地址
$ kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
deployment.apps/kubernetes-bootcamp created
# 获取你的应用,可以看到有一个应用,运行在一个节点上
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1/1 1 1 114s
# 此时该应用运行在内部的一个 pods:一个私有的、隔离的网络上,默认情况下,他们可以同同一个 k8s 集群中的其他 pods 和 services看到,不能在外网上看到
# 可以通过 kubectl 通过 API 与应用程序进行交互
# 可以新开一个终端,然后启动一个代理
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
# 现在终端和 k8s 集群之间有了链接,可以通过代理之间访问 API
# 比如可以通过代理访问 version 信息
$ curl http://localhost:8001/version
{
"major": "1",
"minor": "17",
"gitVersion": "v1.17.3",
"gitCommit": "06ad960bfd03b39c8310aaf92d1e7c12ce618213",
"gitTreeState": "clean",
"buildDate": "2020-02-11T18:07:13Z",
"goVersion": "go1.13.6",
"compiler": "gc",
"platform": "linux/amd64"
}
# API 服务器将根据 pod 名称为每个 pod 自动创建一个断点,该端点也可以通过代理访问,首先要获得断点的名称
# 下面把获得的断点名称放到 POD_NAME 的环境变量中
# 注意:通过 kubectl get pods 能看到所有的 pod 的端点名称;后面这个看效果是直接获取到了一个 name
$ export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
$ echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-69fbc6f4cf-ppc9j
# 后续会用到该知识点
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
# 了解你的应用
# 目标
- 了解 Kubernetes Pod。
- 了解 Kubernetes 工作节点。
- 对已部署的应用故障排除。
# 查看 pod 和工作节点
# Kubernetes Pods
Pod 托管你的应用实例。Pod 是 Kubernetes 抽象出来的,表示一组一个或多个应用程序容器(如 Docker 或 rkt ),以及这些容器的一些共享资源。这些资源包括:
- 共享存储,当作卷
- 网络,作为唯一的集群 IP 地址
- 有关每个容器如何运行的信息,例如容器映像版本或要使用的特定端口。
# 工作节点
一个 pod 总是运行在 工作节点。工作节点是 Kubernetes 中的参与计算的机器,可以是虚拟机或物理计算机,具体取决于集群。每个工作节点由主节点管理。工作节点可以有多个 pod ,Kubernetes 主节点会自动处理在群集中的工作节点上调度 pod 。 主节点的自动调度考量了每个工作节点上的可用资源。
每个 Kubernetes 工作节点至少运行:
- Kubelet,负责 Kubernetes 主节点和工作节点之间通信的过程; 它管理 Pod 和机器上运行的容器。
- 容器运行时(如 Docker ,rkt )负责从仓库中提取容器镜像,解压缩容器以及运行应用程序。
如果它们紧耦合并且需要共享磁盘等资源,这些容器应在一个 Pod 中编排。
# 使用 kubectl 进行故障排除
- kubectl get - 列出资源
- kubectl describe - 显示有关资源的详细信息
- kubectl logs - 打印 pod 和其中容器的日志
- kubectl exec - 在 pod 中的容器上执行命令
# 检查应用程序配置
# 检查现有的 pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-nw2d8 1/1 Running 0 35s
# 可以查看该 pod 内的 容器和镜像 等信息
# 可以看到返回的信息数据很多
$ kubectl describe pods
Name: kubernetes-bootcamp-765bf4c7b4-nw2d8
Namespace: default
Priority: 0
Node: minikube/172.17.0.13
Start Time: Wed, 08 Apr 2020 03:16:46 +0000
Labels: pod-template-hash=765bf4c7b4
run=kubernetes-bootcamp
Annotations: <none>
Status: Running
IP: 172.18.0.6
IPs:
IP: 172.18.0.6
Controlled By: ReplicaSet/kubernetes-bootcamp-765bf4c7b4
Containers:
kubernetes-bootcamp:
Container ID: docker://3854a4a1e21d6c8e192e8121d9c07b7e03fe8fb90e3f3dfaa66b4185ba395735
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Image ID: docker-pullable://jocatalin/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 08 Apr 2020 03:16:52 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-h8pmg (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-h8pmg:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-h8pmg
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 105s (x3 over 110s) default-scheduler 0/1 nodes are available: 1 node(s) had taints that the pod didnt tolerate.
Normal Scheduled 102s default-scheduler Successfully assigned default/kubernetes-bootcamp-765bf4c7b4-nw2d8 to minikube
Normal Pulled 97s kubelet, minikube Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
Normal Created 97s kubelet, minikube Created container kubernetes-bootcamp
Normal Started 96s kubelet, minikube Started container kubernetes-bootcamp
# 该命令输出的信息是人类可读的,并非是脚本化的原始文件
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
50
51
52
53
54
55
56
57
58
59
60
# 在终端中显示应用
pods 是在私有网络中运行的,因此先创建一个代理
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
# 获取 pod 名称,并存储在变量中
$ export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
$ echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-765bf4c7b4-nw2d8
# 通过 API 获取该 POD 的信息
$ curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-nw2d8 | v=1
2
3
4
5
6
7
8
9
10
11
# 显示容器日志
应用程序发送到 STDOUT 的任何内容都会成为 pod 中容器的日志。
# 查看该 POD 的容器日志
$ kubectl logs $POD_NAME
2
# 在容器上执行命令
一旦 Pod 启动并运行,我们就可以直接在容器上执行命令。为此,我们使用 exec 命令并使用 Pod 的名称作为参数。让我们列出环境变量:
$ kubectl exec $POD_NAME env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubernetes-bootcamp-765bf4c7b4-nw2d8
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
...
2
3
4
5
6
在 Pod 的容器中启动一个 bash 程序。注意的是:由于当前 pod 只有一个容器,容器名称是可以省略的
$ kubectl exec -ti $POD_NAME bash
root@kubernetes-bootcamp-765bf4c7b4-nw2d8:/#
# 这就进入了一个 pod 内的容器
# 在该 bash 环境下,可以执行 bash 指令,比如 ls 等
# 看看这个 js 中的内容。里面就是我们部署容器的时候运行的一个 node js 程序,他监听了 8080 端口,并输出一些信息
root@kubernetes-bootcamp-765bf4c7b4-nw2d8:/# cat server.js
# 由于在容器内部,所以可以直接访问 localhost
root@kubernetes-bootcamp-765bf4c7b4-nw2d8:/# curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-nw2d8 | v=1
# 退出与该容器的联机
root@kubernetes-bootcamp-765bf4c7b4-nw2d8:/# exit
2
3
4
5
6
7
8
9
10
11
12
13
14
# 公开的暴露你的应用
# 目标
- 了解 Kubernetes 中的服务
- 了解标签和 LabelSelector 对象如何与服务相关
- 使用服务在 Kubernetes 集群外公开应用程序
# 服务概述
Pod 是有生命周期的,当工作节点死亡,在该节点上运行的 Pod 也会丢失,然后可能会通过 ReplicaSet 来创建新的 Pod 来恢复成原来的状态。
集群中的每个 Pod 都有一个唯一的 IP 地址,因此需要一种自动协调 Pod 之间的方法
Kubernetes 中的服务是一种抽象,定义了 Pod 的逻辑集合和访问 Pod 的策略,可以通过 YML(首选)或 JSON 定义服务。如果没有服务,尽管每个 Pod 有 一个唯一的地址,但是也不会暴露在集群外部。服务允许你的应用程序接受流量。
在 ServiceSpec 中通过 type 可以指定以何种方式公开服务:
- ClusterIP(默认):在群集的内部 IP上公开服务。这种类型使得只能从群集内部访问服务。
- NodePort:使用 NAT 在群集中每个选定节点的相同端口上公开服务。使用可以从群集外部访问服务
:
。<NodeIP>:<NodePort>
ClusterIP 的超集。 - LoadBalancer :在当前云中创建一个外部负载平衡器(如果支持),并为该服务分配一个固定的外部 IP。NodePort 的超集。
- ExternalName:
externalName
通过返回带有该名称的 CNAME 记录,使用任意名称(在规范中指定)公开服务。不使用代理。此类型需要 v1.7 或更高版本kube-dns
。
服务在一组 Pod 之间路由流量。服务是允许 Pod 在 Kubernetes 中死亡和复制而又不影响您的应用程序的抽象。
简单说:服务类似一个 nginx,可以决定路由到哪些 pod 上去
# 使用 expose 暴露你的程序
# 创建新服务 services
# 先找到一个 pod ,确定你的应用还在运行
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-bsmcs 1/1 Running 0 2m19s
# 列出集群中的服务
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m57s
2
3
4
5
6
7
8
9
上述有一个 kubernetes 的服务,这个是 minikube 启动集群时默认创建的。
# 关于这个 deployment/kubernetes-bootcamp 前面的 deployment 是我们不熟应用时的指令
# 如果这里使用 services/xxx 一样的概念
$ kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
service/kubernetes-bootcamp exposed
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9m17s
kubernetes-bootcamp NodePort 10.104.184.115 <none> 8080:31880/TCP 57s
2
3
4
5
6
7
8
9
xx
$ kubectl describe services/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
Labels: run=kubernetes-bootcamp
Annotations: <none>
Selector: run=kubernetes-bootcamp
Type: NodePort
IP: 10.104.184.115
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31880/TCP
Endpoints: 172.18.0.3:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 这个是暴露的端口,
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=31880
# 但是这个 ip 结果居然是 172.17.0.49 也就是 kubernetes 暴露的 IP
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-bsmcs | v=1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 使用标签 labels
deployment 为 pod 自动创建了一个标签
# 通过描述来获取标签信息
$ kubectl describe deployment
Name: kubernetes-bootcamp
Namespace: default
CreationTimestamp: Wed, 08 Apr 2020 05:23:49 +0000
Labels: run=kubernetes-bootcamp
2
3
4
5
6
可以通过这个标签来获取 pod 列表,通过 -l
参数
$ kubectl get pods -l run=kubernetes-bootcamp
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-bsmcs 1/1 Running 0 24m
2
3
还可以用标签来获取服务
$ kubectl get services -l run=kubernetes-bootcamp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-bootcamp NodePort 10.104.184.115 <none> 8080:31880/TCP 16m
2
3
# 获取 pod name
$ export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
$ echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-765bf4c7b4-bsmcs
2
3
4
给应用添加新标签,使用 label 参数,后面跟 象类型、对象名称和新标签
$ kubectl label pod $POD_NAME app=v1
pod/kubernetes-bootcamp-765bf4c7b4-bsmcs labeled
2
查看这个 pod 的标签列表
$ kubectl describe pods $POD_NAME
Name: kubernetes-bootcamp-765bf4c7b4-bsmcs
Namespace: default
Priority: 0
Node: minikube/172.17.0.49
Start Time: Wed, 08 Apr 2020 05:24:06 +0000
Labels: app=v1
pod-template-hash=765bf4c7b4
run=kubernetes-bootcamp
...
# 可以看到多了 app=v1
# 那么就可以通过标签来获取 pod 列表了
$ kubectl get pods -l app=v1
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-bsmcs 1/1 Running 0 28m
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 删除服务
可以使用 delete service
命令,标签也可以在这里使用
$ kubectl delete service -l run=kubernetes-bootcamp
service "kubernetes-bootcamp" deleted
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 30m
# 会发现服务没有了
# 使用之前的访问地址,发现不能访问了,表示该应用不被暴露在集群之外了
$ curl $(minikube ip):$NODE_PORT
curl: (7) Failed to connect to 172.17.0.49 port 31880: Connection refused
# 可以通过命令执行,来确认该应用程序还存活
$ kubectl exec -ti $POD_NAME curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-bsmcs | v=1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这里已经看到应用程序确实还活跃,要关闭应用程序的话,需要删除部署,因为部署正在管理应用程序
# 伸缩应用
在之前的模块中,我们创建了一个 Deployment (opens new window),然后通过 Service (opens new window)让其可以开放访问。Deployment 仅为跑这个应用程序创建了一个 Pod。 当流量增加时,我们需要扩容应用程序满足用户需求。
扩缩 是通过改变 Deployment 中的副本数量来实现的。
# 扩展
# 找到我们的部署
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1/1 1 1 3m31s
2
3
4
列表字段含义:
- NAME:集群中 deployment 的名称
- READY:当前所需副本的比率
- UP-TO-DATE:已更新到所需状态的数量
- AVAILABLE:有多少应用程序副本供用户使用
- AGE:应用程序运行的时间
查看 deployment 运行的副本
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
kubernetes-bootcamp-765bf4c7b4 1 1 1 38m
# DESIRED:部署程序时期望的副本数量
# CURRENT:当前正在运行的副本数量
2
3
4
5
6
注意:副本集的名称总是格式化为 [DEPLOYMENT-NAME]-[RANDOM-STRING]
,随机字符串是随机生成的,使用 pod-template-hash
作为随机数种子
接下来,我们将部署扩展到 4 个副本。使用 kubectl scale
命令
# 部署类型/应用名称 所需要的数量
$ kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment.apps/kubernetes-bootcamp scaled
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 4/4 4 4 45m
# 查看 pod 的数量
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubernetes-bootcamp-765bf4c7b4-kvzml 1/1 Running 0 45m 172.18.0.2 minikube <none> <none>
kubernetes-bootcamp-765bf4c7b4-mc5sl 1/1 Running 0 67s 172.18.0.8 minikube <none> <none>
kubernetes-bootcamp-765bf4c7b4-rcfbm 1/1 Running 0 67s 172.18.0.9 minikube <none> <none>
kubernetes-bootcamp-765bf4c7b4-tphzj 1/1 Running 0 67s 172.18.0.7 minikube <none> <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
现在有 4 个 pod,有不同的 IP 地址。这个更改已经注册到 Deployment events log 中,可以通过以下命令验证
$ kubectl describe deployments/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
CreationTimestamp: Wed, 08 Apr 2020 06:14:57 +0000
Labels: run=kubernetes-bootcamp
Annotations: deployment.kubernetes.io/revision: 1
Selector: run=kubernetes-bootcamp
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
.... 看到有 4 个副本
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 47m deployment-controller Scaled up replica set kubernetes-bootcamp-765bf4c7b4 to 1
Normal ScalingReplicaSet 3m15s deployment-controller Scaled up replica set kubernetes-bootcamp-765bf4c7b4 to 4
# 另外,在 events 中,有一条日志是变成了 4 个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 负载均衡 Load Balancing
让我们检查服务是否在负载平衡流量。为了找出暴露的 IP 和端口,我们可以使用前面模块中学习到的 describe 服务:
$ kubectl describe services/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
Labels: run=kubernetes-bootcamp
Annotations: <none>
Selector: run=kubernetes-bootcamp
Type: NodePort
IP: 10.96.156.129
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31244/TCP
Endpoints: 172.18.0.2:8080,172.18.0.7:8080,172.18.0.8:8080 + 1 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 拿到这个服务暴露的端口
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=31244
# 访问这个服务,会发现被自动均衡负载了
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-tphzj | v=1
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-mc5sl | v=1
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-765bf4c7b4-kvzml | v=1
# 这里笔者还是不清楚,这里的 minikube ip 是怎么访问到这个服务的
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
# 缩减
和扩展的时候使用的命令一致
$ kubectl scale deployments/kubernetes-bootcamp --replicas=2
deployment.apps/kubernetes-bootcamp scaled
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 2/2 2 2 7m56s
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubernetes-bootcamp-765bf4c7b4-f66cb 1/1 Running 0 7m25s 172.18.0.8 minikube <none> <none>
kubernetes-bootcamp-765bf4c7b4-p27l7 1/1 Running 0 7m59s 172.18.0.4 minikube <none> <none>
2
3
4
5
6
7
8
9
10
11
# 更新你的应用
滚动更新 允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。新的 Pod 将在具有可用资源的节点上进行调度。
滚动更新允许以下操作:
- 将应用程序从一个环境提升到另一个环境(通过容器镜像更新)
- 回滚到以前的版本
- 持续集成和持续交付应用程序,无需停机
# 更新应用程序的版本
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 0/4 4 0 9s
# 列出正在运行的 pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-5dnsj 1/1 Running 0 21s
kubernetes-bootcamp-765bf4c7b4-fhpjw 1/1 Running 0 21s
kubernetes-bootcamp-765bf4c7b4-l2xck 1/1 Running 0 21s
kubernetes-bootcamp-765bf4c7b4-t7f7v 1/1 Running 0 21s
# 查看当前 pod 的image 版本
$ kubectl describe pods
...
Containers:
kubernetes-bootcamp:
Container ID: docker://27adad6a06a62863b135e6aa1563cb214fa8c5503c746a17c37805566ed31aa2
Image: gcr.io/google-samples/kubernetes-bootcamp:v1 # 主要看这个镜像版本
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
开始滚动更新
$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
deployment.apps/kubernetes-bootcamp image updated
# 查看 pod 状态
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-765bf4c7b4-5dnsj 0/1 Terminating 0 4m5s
kubernetes-bootcamp-765bf4c7b4-fhpjw 0/1 Terminating 0 4m5s
kubernetes-bootcamp-765bf4c7b4-l2xck 0/1 Terminating 0 4m5s
kubernetes-bootcamp-765bf4c7b4-t7f7v 0/1 Terminating 0 4m5s
kubernetes-bootcamp-7d6f8694b6-9t5pd 1/1 Running 0 38s
kubernetes-bootcamp-7d6f8694b6-cgljl 1/1 Running 0 38s
kubernetes-bootcamp-7d6f8694b6-h2gtl 1/1 Running 0 40s
kubernetes-bootcamp-7d6f8694b6-k7hkm 1/1 Running 0 40s
# 可以看到有终止状态,等一会,就变成新的 pod 了
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-7d6f8694b6-9t5pd 1/1 Running 0 41s
kubernetes-bootcamp-7d6f8694b6-cgljl 1/1 Running 0 41s
kubernetes-bootcamp-7d6f8694b6-h2gtl 1/1 Running 0 43s
kubernetes-bootcamp-7d6f8694b6-k7hkm 1/1 Running 0 43s
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 验证一个更新
首先,让我们检查应用程序是否正在运行。为了找出暴露的 IP 和端口,我们可以使用描述服务:
$ kubectl describe services/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
Labels: run=kubernetes-bootcamp
Annotations: <none>
Selector: run=kubernetes-bootcamp
Type: NodePort
IP: 10.109.203.10
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 30410/TCP
Endpoints: 172.18.0.10:8080,172.18.0.11:8080,172.18.0.12:8080 + 1 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# 拿到暴露的端口
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=30410
# 验证是否更新
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7d6f8694b6-9t5pd | v=2
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7d6f8694b6-9t5pd | v=2
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7d6f8694b6-h2gtl | v=2
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7d6f8694b6-k7hkm | v=2
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
更新也可以通过运行 rollout 状态命令来确认:
$ kubectl rollout status deployments/kubernetes-bootcamp
deployment "kubernetes-bootcamp" successfully rolled out
# 查看当前的镜像版本。使用 describe 命令
$ kubectl describe pods
2
3
4
5
# 回滚更新
# 先升级部署使用 v10 的镜像
$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
deployment.apps/kubernetes-bootcamp image updated
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 3/4 2 3 11m
# 但是没有达到我们预期的 pod 数量
# 查看当前的 pods
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-7d6f8694b6-9t5pd 1/1 Running 0 8m41s
kubernetes-bootcamp-7d6f8694b6-h2gtl 1/1 Running 0 8m43s
kubernetes-bootcamp-7d6f8694b6-k7hkm 1/1 Running 0 8m43s
kubernetes-bootcamp-886577c5d-5kdnv 0/1 ImagePullBackOff 0 93s
kubernetes-bootcamp-886577c5d-qpb4g 0/1 ImagePullBackOff 0 93s
# 在描述命令上,能看到更多的 pod 信息
$ kubectl describe pods
...
Warning Failed 73s (x4 over 2m43s) kubelet, minikube Failed to pull image "gcr.io/google-samples/kubernetes-bootcamp:v10": rpc error: code = Unknown desc = Error response from daemon: manifest for gcr.io/google-samples/kubernetes-bootcamp:v10 not found: manifest unknown: Failed to fetch "v10" from request "/v2/google-samples/kubernetes-bootcamp/manifests/v10".
# 通观察,可以发现根本就没有 v10 这个镜像。 上述的 pods 表示有 3 个可用,有 2 个更新失败了
# 这意味着,在滚动更新过程中,新的版本启动失败了,老的丢掉了一个
# 这个时候使用回滚更新
$ kubectl rollout undo deployments/kubernetes-bootcamp
deployment.apps/kubernetes-bootcamp rolled back
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-7d6f8694b6-9b9jb 1/1 Running 0 17s
kubernetes-bootcamp-7d6f8694b6-9t5pd 1/1 Running 0 13m
kubernetes-bootcamp-7d6f8694b6-h2gtl 1/1 Running 0 13m
kubernetes-bootcamp-7d6f8694b6-k7hkm 1/1 Running 0 13m
# 就会发现,死掉的哪一个又活过来了
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