跳到主要内容

02、Kubernetes - 实战:pod命令行方式管理

一、Pod是什么

Pod是Kubernetes中能够创建和部署的最小单元,是Kubernetes集群中的一个应用实例,总是部署在同一个节点Node上。Pod中包含了一个或多个容器,还包括了存储、网络等各个容器共享的资源。Pod支持多种容器环境,Docker则是最流行的容器环境。

单容器Pod,最常见的应用方式。
多容器Pod,对于多容器Pod,Kubernetes会保证所有的容器都在同一台物理主机或虚拟主机中运行。多容器Pod是相对高阶的使用方式,除非应用耦合特别严重,一般不推荐使用这种方式。一个Pod内的容器共享IP地址和端口范围,容器之间可以通过 localhost 互相访问。

Pod带来的好处

Pod并不提供保证正常运行的能力,因为可能遭受Node节点的物理故障、网络分区等等的影响,整体的高可用是Kubernetes集群通过在集群内调度Node来实现的。通常情况下我们不要直接创建Pod,一般都是通过Controller来进行管理,但是了解Pod对于我们熟悉控制器非常有好处。
Pod做为一个可以独立运行的服务单元,简化了应用部署的难度,以更高的抽象层次为应用部署管提供了极大的方便。
Pod做为最小的应用实例可以独立运行,因此可以方便的进行部署、水平扩展和收缩、方便进行调度管理与资源的分配。
Pod中的容器共享相同的数据和网络地址空间,Pod之间也进行了统一的资源管理与分配。

Kubernetes中Pod控制器

pod的管理主要有RC(RS)、Deployment、StatefulSet、DaemonSet和Job(CronJob)等

Replication Controller

Replication Controller简称RC,简单来说,RC可以保证在任意时间运行Pod的副本数量,能够保证Pod总是可用的。总维持pod是指定的副本数量运行。

Replication Set
Replication Set简称RS,随着Kubernetes的发展,RS在RC的基础上做了一些扩展,官方已经推荐使用RS和Deployment来代替RC了。

apiVersion: v1
kind: ReplicationController/Replication Set
metadata:
  name: rc-test
  labels:
    name: rc
spec:
  replicas: 3
  selector:
    name: rc
 ...................................

Deployment

主要职责和RC一样的都是保证Pod的数量和健康,二者大部分功能都是完全一致的,可以看成是一个升级版的RC控制器。比如一些官方组件kube-dns、kube-proxy也都是使用的Deployment来管理的.

新特性如下:

RS的全部功能:Deployment具备上面描述的RC的全部功能
事件和状态查看:可以查看Deployment的升级详细进度和状态
回滚:当升级Pod的时候如果出现问题,可以使用回滚操作回滚到之前的任一版本
版本记录:每一次对Deployment的操作,都能够保存下来,这也是保证可以回滚到任一版本的基础
暂停和启动:对于每一次升级都能够随时暂停和启动

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: test
  labels:
    k8s-app: test
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
  ....................................

DaemonSet

DaemonSet适用于在每个Node都需要运行一个Pod的时候使用,比如:每一个Node上运行一个日志采集、性能监控的Pod,可以通过DaemonSet来实现

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-ds-test
spec:
  selector:
    matchLabels:
      name: node-ds-test
  template:
    metadata:
      labels:
...........................

StatefulSet

StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器API。在Pods管理的基础上,保证Pods的顺序和一致性。与Deployment一样,StatefulSet也是使用容器的Spec来创建Pod,与之不同StatefulSet创建的Pods在生命周期中会保持持久的标记

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
     matchLabels:
       app: nginx
  template:
    metadata:
...........................

Job/CronJob

K8S中,通常用Job来创建一个任务,注意job是执行一个的任务。如需要任务定时周期的去执行。CronJob就出场了,CronJob其实就是在Job的基础上加上了任务调度。

apiVersion: batch/v1
kind: Job/CronJob
metadata:
  name: job-test
spec:
  template:
    metadata:
      name: job-test
    spec:
      restartPolicy: Never

二、通过命令来管理pod

官方推荐我们使用yaml文件的形式来管理pod,我们先用命令的方式来管理pod:

以下就是一些常用的kubectl管理命令

#查看所有 pod 列表,  -n 后跟 namespace, 查看指定的命名空间  -o wide 查看详细信息
kubectl get pod
kubectl get pod -n kube  
kubectl get pod -o wide
# 查看 RC 和 service 列表, -o wide 查看详细信息
kubectl get rc,svc
kubectl get pod,svc -o wide  
kubectl get pod <pod-name> -o yaml
# 显示 Node 的详细信息
kubectl describe node server2
# 显示 Pod 的详细信息, 特别是查看 pod 无法创建的时候的日志
kubectl describe pod <pod-name>
eg:
kubectl describe pod nginx
# 根据 yaml 创建资源, apply 可以重复执行,create 不行
kubectl create -f pod.yaml
kubectl apply -f pod.yaml
# 基于 pod.yaml 定义的名称删除 pod 
kubectl delete -f pod.yaml 
# 删除所有包含某个 label 的pod 和 service
kubectl delete pod,svc -l name=<label-name>
# 删除所有 Pod
kubectl delete pod --all
# 查看 endpoint 列表
kubectl get endpoints
# 执行 pod 的命令
kubectl exec <pod-name> -- date
kubectl exec <pod-name> -- bash
kubectl exec <pod-name> -- ping 172.25.63.1
# 通过bash获得 pod 中某个容器的TTY,相当于登录容器
kubectl exec -it <pod-name> -c <container-name> -- bash
eg:
kubectl exec -it nginx -- bash
# 查看容器的日志
kubectl logs <pod-name>
kubectl logs -f <pod-name> 实时查看日志
kubectl log  <pod-name>  -c <container_name> 若 pod 只有一个容器,可以不加 -c 
# 查看注释
kubectl explain pod
kubectl explain pod.apiVersion

# 查看节点 labels
kubectl get node --show-labels

三、pod命令管理实践

创建自主式pod

运行一个pod:

可以使用kubectl run --help查看运行的帮助

[root@server1 ~]# kubectl run nginx --image=nginx
pod/nginx created

查看运行的pod:

[root@server1 ~]# kubectl get pod
NAME    READY   STATUS              RESTARTS   AGE
nginx   0/1     ContainerCreating   0          3m56s

查看默认namespace的pod:

[root@server1 ~]# kubectl get pod -n default
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          4m31s

查看pod的详细信息:

[root@server1 ~]# kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         server2/172.25.63.2			#这个pod运行在哪个节点上
Start Time:   Sat, 18 Apr 2020 00:43:38 +0800
Labels:       run=nginx					#pod的label
Annotations:  <none>
Status:       Running
IP:           10.244.1.2			#pod的ip地址
IPs:
  IP:  10.244.1.2
Containers:
  nginx:
  ......

此时,集群内部的任意节点可以访问pod,但是集群外部无法直接访问:
现在再运行一个容器来访问nginx:

[root@server1 ~]# kubectl run test -it --image=radial/busyboxplus --restart=Never
If you don't see a command prompt, try pressing enter.
/ 
/ curl 10.244.1.2			#访问第一个pod的ip地址即可。

上述命令中--restart=Never表示退出之后不重启,默认会重启。

当pod不使用时可以将其删除

删除pod:

[root@server1 ~]# kubectl delete pod nginx 
pod "nginx" deleted
[root@server1 ~]# kubectl delete pod test 
pod "test" deleted

 

指定pod控制器为deployment

默认创建pod时使用自主式的pod管理器,这种自主创建的pod再删除时会直接删除,我们也可以指定pod管理器deployment来创建pod,这种管理器在pod删除时会帮我们自动启动:

首先用两种方式创建pod:

[root@server1 ~]# kubectl run nginx --image=nginx
pod/nginx created
[root@server1 ~]# kubectl create deployment myapp --image=ikubernetes/myapp:v1deployment.apps/myapp created

查看pod信息:
[root@server1 ~]# kubectl get pod -o wide
NAME                     READY   STATUS              RESTARTS   AGE     IP           NODE      NOMINATED NODE   READINESS GATES
myapp-5d587c4d45-vw5z5   0/1     ContainerCreating   0          13s     <none>       server3   <none>           <none>
nginx                    1/1     Running             0          5m32s   10.244.1.3   server2   <none>           <none>

删除自主pod:
[root@server1 ~]# kubectl delete pod nginx 
pod "nginx" deleted
[root@server1 ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
myapp-5d587c4d45-vw5z5   1/1     Running   0          116s

可以看到已经被删除,接下来删除指定deployment的pod:

[root@server1 ~]# kubectl delete pod myapp-5d587c4d45-vw5z5
pod "myapp-5d587c4d45-vw5z5" deleted
[root@server1 ~]# kubectl get pod
NAME                     READY   STATUS              RESTARTS   AGE
myapp-5d587c4d45-nplqk   0/1     ContainerCreating   0          26s

可以看到删除pod后deployment又帮我们启动了pod。

pod拉伸

基于deployment我们也可以实现拉伸pod的目的:

[root@server1 ~]# kubectl scale --replicas=2 deployment myapp

 

拉伸成功,同理也可以实现缩减的效果。

集群内部pod之间访问

此时的pod在集群外部和pod外部并不能被访问,只能在pod内部被访问,要实现集群内部pod外部访问就要借助service,service是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service成为微服务。

解下来创建service:

[root@server1 ~]# kubectl expose deployment myapp --port=80 --target-port=80
service/myapp exposed

此时pod客户端可以通过service的名称访问后端的两个pod,其中Cluster ip为默认类型,自动分配一个仅集群内部可以访问的虚拟ip。

[root@server1 ~]# kubectl get deployments.apps 
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
myapp   2/2     2            2           7m24s
[root@server1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   4h25m
myapp        ClusterIP   10.104.223.76   <none>        80/TCP    32s
[root@server1 ~]# kubectl describe svc myapp 
Name:              myapp
Namespace:         default
Labels:            app=myapp
Annotations:       <none>
Selector:          app=myapp
Type:              ClusterIP
IP:                10.104.223.76
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.4:80,10.244.2.8:80		#两个pod的地址
Session Affinity:  None
Events:            <none>

 

之后测试访问:

[root@server1 ~]# kubectl run test -it --image=radial/busyboxplus
If you don't see a command prompt, try pressing enter.
/ 
/ curl 10.104.223.76

 

集群外部访问pod

当然这种方式也只能在集群内部访问,要想实现集群外部访问,我们可以使用NodePort类型暴露端口,让外部客户端访问Pod。

NodePort:在ClusterIp基础上为Service在每台机器上绑定一个端口,这样就可以通过NodeIP:NodePort来访问该服务。

由于集群已经创建,因此要实现集群外部访问需要更改集群网络类型:

[root@server1 ~]# kubectl edit svc myapp

将ClusterIp该为NodePort
 当然也可以在创建service时加--type=NodePort指定类型。

kubectl expose deployment myapp --port=80 --target-poet=80 --type=NodePort
kubectl get pod -o wide
kubectl get svc myapp

查看暴露出来的端口:

[root@server1 ~]# kubectl get svc myapp
NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
myapp   NodePort   10.104.223.76   <none>        80:32516/TCP   6m47s

端口为32516,因此可以使用以下方式访问pod:

[root@foundation63 kiosk]# curl 172.25.63.3:32516
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@foundation63 kiosk]# curl 172.25.63.2:32516
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

pod的应用版本更新和回滚

接下来实现pod的版本更新和回滚:

[root@server1 ~]# kubectl set image deployments myapp myapp=ikubernetes/myapp:v2 --record 
deployment.apps/myapp image updated

查看更新历史:

[root@server1 ~]# kubectl rollout history deployment myapp
deployment.apps/myapp 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployments myapp myapp=ikubernetes/myapp:v2 --record=true

查看版本:

[root@server1 ~]# curl 172.25.63.3:32516
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

可以看出已经更新成了v2版本。

回滚到v1:

[root@server1 ~]# kubectl rollout undo deployment myapp --to-revision=1
deployment.apps/myapp rolled back

查看版本:

[root@server1 ~]# curl 172.25.63.3:32516
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

    

可以看到版本已经回滚到v1了。