Kubectl语法

​ 一旦K8s集群搭建完成后,我们就可以再其部署容器化应用。在此之前我们需要先了解,kubectl的语法,以便后续管理和维护k8s集群。

​ kubectl命令的常见格式是:kubectl action resource [parameter]

  • kubectl:二进制执行文件。
  • action:操作选项。
  • resource:资源类型。
  • parameter(可选):参数。

​ 这会对指定的资源(类似node或deployment)执行指定的操作(类似create、describe或delete)。您可以再子命令后面使用 --help获取可能参数相关的更多信息。kubectl get nodes –help

​ 示例:创建一个deployment类型的资源,创建的资源名称为deployment-nginx,所引用的镜像为nginx,查询刚创建名为deployment-nginx的deployment资源类型,当前启动了0个pod

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
[root@k8s-master-01 ~]# kubectl create deployment deployment-nginx --image nginx 
deployment.apps/deployment-nginx created
# 创建资源成功,但是READY启动了0个pod
[root@k8s-master-01 ~]# kubectl get deployments.apps deployment-nginx
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-nginx 0/1 1 0 2m
# 稍等一会在查,READY已经1/1,那是因为在这过程中他回去先拉取镜像,是需要等一会的
[root@k8s-master-01 ~]# kubectl get deployments.apps deployment-nginx
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-nginx 1/1 1 1 8m48s
# 想要查看资源创建详情可通过describe选项
[root@k8s-master-01 ~]# kubectl describe deployments.apps deployment-nginx
Name: deployment-nginx
Namespace: default
CreationTimestamp: Mon, 14 Jul 2025 16:44:03 +0800
Labels: app=deployment-nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=deployment-nginx
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=deployment-nginx
Containers:
nginx:
Image: nginx
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: deployment-nginx-f9986cddf (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set deployment-nginx-f9986cddf from 0 to 1
# 删除刚创建的deployment
[root@k8s-master-01 ~]# kubectl delete deployments.apps deployment-nginx
deployment.apps "deployment-nginx" deleted

yaml语法

​ kubectl命令是正常是可以创建出服务,但是在企业实践中这是利用kubectl创建的服务通常仅用来测试或者临时的服务,因为一个完整的业务他是需要具备着很多参数,使用kubectl来创建显然不是很方便阅读,并且命令敲了是一次性的,当我要更新这个服务时,只能删除后重新进行执行,因为对于k8s来说它是没有更新的概念的,所有的更新都是删除后重新部署的。

​ 但是我们使用yaml文件的方式进行部署版本迭代,那就可以很轻松的解决,唯一的缺点就是yaml的学习成本较高,对于初学者来说是较为困难的事情。下图为官网给出的一个最简单的创建资源的yaml。

  • 文件内容格式要求严格。
  • 大小写敏感。
  • 使用缩进表达上下级关系,上下级需保持两位空格缩进。
  • 缩进时不允许使用tab,只能使用空格进行缩进。
  • #号为注释,不作为允许时的代码。
  • 键值对(key:value)用冒号分割,value不允许紧挨着冒号,需要空一个书写value。
  • 列表类型的value需要回车用-(减号)加一个空格来表示,多个列表使用同级缩进进行表示为一组列表。
  • 文件已yaml和yml后缀作为文件名。

image-20250714172355789

​ 虽然有些复杂,但是我们可以通过帮助explain选项帮助我们查询它所具备的参数及用法。

​ 例如:kubectl explain pod

​ 查询pod资源下存在如图标记出的key选项。

image-20250714173015446

kubectl explain pod.spec下有具备如下图众多选项,命令中的上下级使用.(点)来表示,yaml文件中的上下级通过换行缩进两格进行表示。

image-20250714173220277

​ 如果您对kubectl很熟悉,也可以通过kubectl来主动帮您生成yaml,仅需在写好的kubectl后加上--dry-run=client -o yaml参数即可,添加后您的这条语句不会正真执行操作,而是将它转化为yaml进行输出,具体示例参考下方代码。

​ kubectl创建一个名为deployment-nginx的deployment类型资源,镜像使用nginx,--replicas 3生成3个副本(Pod),--dry-run=client -o yaml模拟运行到客户端,已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
[root@k8s-master-01 ~]# kubectl create deployment deployment-nginx --image nginx --replicas 3 --dry-run=client -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: deployment-nginx
name: deployment-nginx
spec:
replicas: 3
selector:
matchLabels:
app: deployment-nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: deployment-nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
[root@k8s-master-01 ~]#

注:Kind代表你要操作的资源类型,apiVersion代表这个资源的版本,metadata下的内容代表着这个资源的具体操作内容,apiVersion并不都是v1,下表中介绍版本中各不同的表示。

Alpha Beta Stable
1、版本名称包含了Alpha。 1、版本名称包含了Beta。 1、版本名称是vX,其中X是整数。
2、可能是由缺陷的。启用该功能可能会带来问题,默认是关闭的。 2、代码进行测试过。启动该功能认为是安全的,默认是启用。 2、功能和稳定版本将出现在许多后续版本的发行软件中。
3、支持的功能可能在没有通知的情况下随时删除。 3、所有以支持的功能不会被删除,细节可能发生变化。 3、有时候也会被称为GA或者毕业等词汇。
4、API的更改可能会带来兼容性问题,但是在后续的软件发布中不会有任何通知。 4、对象的模式和语义可能会在后续的Beta测试版或稳定版中以不兼容的方式进行更改。
5、由于BUG风险的增加和缺乏长期的支持,推荐在短暂的集群测试中使用。 5、建议仅用于非业务关键型用途,因为后续版本中可能存在不兼容的更改。如果您有多个可以独立升级的集群,则可以放款此限制。

API and RESOURCES

​ 我们前面简单以pod、deployment资源进行了演示,那么我们这个k8s到底还存在着哪些API功能呢?

​ 可以通过:kubectl api-resources命令进行查看。

  • NAME:资源名称,通常用于kubectl中表示资源类型的名称。
  • SHORTNAMES:资源名称缩写,通常用于kubectl中表示资源类型的名称缩写。
  • APIVERSION:API版本,通常用于表示这每个资源的稳定情况及预示后续版本可能会带来的某些变化。
  • NAMESPACED:代表着这个资源的命名空间作用域范围。
    • True表示只作用于所创建隶属于哪个命名空间的范围。
    • False表示该资源创建后作用域整个集群。
  • KIND:资源类型,通常用于Yaml中表示要操作的资源类型。

image-20250714174333125

注:NAMESPACED其实主要的作用就是在您写Yaml时,如果是True那您就需要在metadata下写明该资源要创建到哪个命名空间中,作用域这个小范围,如果是False则无需写明,因为他的作用域是集群的全局,写不写意义不大。

Kubernetes与docker的关系

​ 在之前我们介绍过,当您使用了K8s那我们就从一个打螺丝的一线员工晋升为领导了,我们所有操作都是通过master节点中的kubelet下发指令然后通过kube-api向node节点中的kubelet发送指令,翻译成docker的语言,让docker干活,node节点中的kubelet就处于一个监工的角色。以下用一个示例来演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 这里我们通过master节点创建了一个资源,让docker去生成一个httpd的容器。
# 这里k8s告诉我资源已经创建成功,但是容器是否有创建成功我们不知道。
[root@k8s-master-01 namespace]# kubectl create deployment httpd-01 --image httpd
deployment.apps/httpd-01 created
# 可以通过如下命令看到READY1/1说明运行了一个容器,一个容器正在运行中
[root@k8s-master-01 namespace]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
httpd-01 1/1 1 1 8m9s
# 我们在master上并未发现有httpd镜像
[root@k8s-master-01 namespace]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 9592f5595f2b 3 weeks ago 192MB
reg.liweihu.cn/calico/typha v3.30.2 b3baa600c7ff 4 weeks ago 85.2MB
calico/typha v3.30.2 b3baa600c7ff 4 weeks ago 85.2MB
# master上并未发现有httpd容器在运行
[root@k8s-master-01 namespace]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba8132dd4b57 1cf5f116067c "/coredns -conf /etc…" 6 hours ago Up 6 hours k8s_coredns_coredns-dc6b59956-bfgfb_kube-system_962eb48f-da7c-40b4-be9d-2a4420322173_8
7f4c39926348 1cf5f116067c "/coredns -conf /etc…" 6 hours ago Up 6 hours k8s_coredns_coredns-dc6b59956-72kvq_kube-system_de1ba00e-bac3-4d96-8e5c-90d523cdac40_8

​ 我们说过,master是管理节点是一个领导的角色,领导是不会在一线打螺丝的,所以我们所创建的容器肯定是在node节点上去运行的。

1
2
3
4
5
6
7
8
9
# 在node1节点上我们发现了httpd被拉下来的镜像
[root@k8s-node-01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 22bd15417453 6 days ago 192MB
httpd latest 90f191b9781e 10 days ago 148MB
# 并且我们所创建的httpd的容器也是在node1上运行的
[root@k8s-node-01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa97240d5022 httpd "httpd-foreground" 5 minutes ago Up 5 minutes k8s_httpd_httpd-01-6797c85b9f-csrjb_book-k8s_3ac3ff31-78de-45b3-8ca0-c40edd15c2e1_0

命名空间

​ 在Kubernetes中,命名空间(Namespace)提供了一种机制,将同一集群中的资源划分为相互隔离的组。同一命名空间的内的资源名称要唯一,但跨命名空间时没这个要求。命名空间作用域仅针对带有命名空间的对象,(例如Deployment、Service等),这种作用域对集群范围的对象(例如StorageClass、Node)PersistentVolume 等)不适用,这一点也就是上段文章内容中介绍的kubectl api-resources命令查看到的Namespace字段,True表示适用命名空间,False表示不适用。

何时使用多个命名空间

​ 命名空间适用于存在很多个团队或项目的用户场景,对于只有几个到十几个用户的群体,可以不需要考虑命名空间。如果业务和团队合作时确实需要,请开始使用它们。

​ 命名空间为命名提供了一个范围。资源的名称需要在命名空间内是唯一的,但不能跨命名空间。命名空间不能相互嵌套,每个Kubernetes资源只能在一个命名空间中。

​ 命名空间是在多个用户质检划分集群资源的一种方式(通过资源配额)。

​ 不必使用多个命名空间来分割仅仅轻微不同的资源,例如同一软件的不同版本:应该使用标签来区分同一命名空间中的不同资源。

​ 在Kubernetes集群中会分别会自动创建四个命令空间,我们可以使用以下命令进行查看当前集群中存在哪些命名空间。

  • default:Kubernetes包含这个命名空间,以便于您无需创建新的命名空间即可开始使用新集群,同时当您在创建资源为指定命名空间时,默认会创建在改命名空间下。
  • kube-node-lease:该名字空间包含用于与各个节点关联的 Lease(租约)对象。 节点租约允许 kubelet 发送心跳, 由此控制面能够检测到节点故障。该命名空间下主要包含的资源是leases。
  • kube-public:所有的客户端(包括未经身份验证的客户端)都可以读取该名字空间。 该名字空间主要预留为集群使用,以便某些资源需要在整个集群中可见可读。 该名字空间的公共属性只是一种约定而非要求。
  • kube-system:该名字空间用于 Kubernetes 系统集群类资源创建的对象。
1
2
3
4
5
6
7
[root@k8s-master-01 ~]# kubectl get namespaces
NAME STATUS AGE
default Active 12d
kube-node-lease Active 12d
kube-public Active 12d
kube-system Active 12d
tigera-operator Active 10d

注意:tigera-operator并非集群初始化的命名空间,而是Calico官方操作Kubernetes所创建的命名空间,用于创建管理Calico网络策略和配置资源的。

重要:对于生产环境,请考虑不要使用default命名空间,而是创建其他具有项目意义的名字来使用。

创建一个具有项目意义的命名空间

​ 以下我们将要创建一个属于我们项目独有、具有识别意义的命名空间,之后我们的大部分资源创建操作都将在该命名空间中。

  • 创建一个名为:book-k8s的命名空间。
  • 查看命名空间,检查名为book-k8s的命名空间是否存在。
1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master-01 ~]# kubectl create namespace book-k8s
namespace/book-k8s created
[root@k8s-master-01 ~]#
[root@k8s-master-01 ~]# kubectl get namespaces
NAME STATUS AGE
book-k8s Active 6s
default Active 12d
kube-node-lease Active 12d
kube-public Active 12d
kube-system Active 12d
tigera-operator Active 10d

Yaml的方式

1
2
3
4
5
6
7
8
9
10
#创建yaml文件
[root@k8s-master-01 namespace]# cat >> create-names.yaml << EOF
kind: Namespace
apiVersion: v1
metadata:
name: book-k8s
EOF
# 执行yaml文件
[root@k8s-master-01 namespace]# kubectl create -f create-names.yaml
namespace/book-k8s created

为创建资源设置命名空间

​ 目前我们已经创建了一个名为book-k8s的命名空间,接下来我们需要在该命名空间中创建第一个项目资源Pod。

  • ​ 使用yaml或kubectl的方式创建一个Pod并指定该资源运行在book-k8s命名空间中。
  • 查看资源是否正常运行中。

kubectl的方式:

1
2
3
4
5
# 创建一个名为nginx的Pod,使用Nginx镜像,该资源在book-k8s命名空间下运行。
[root@k8s-master-01 ~]# kubectl run nginx --image nginx --namespace book-k8s
pod/nginx created
[root@k8s-master-01 ~]# kubectl get pods
No resources found in default namespace.

Yaml语法:可以使用–dry-run=client -o yaml快速生成,但在学习阶段不建议使用该方式,能使用explain进行编写是最好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@k8s-master-01 ~]# kubectl run nginx --image nginx --namespace book-k8s --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx
name: nginx
namespace: book-k8s
spec:
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

​ 我们创建了一个Pod,在book-k8s命名空间下,但是我们使用kubectl get pods命令查看Pod是否在正常运行时提示了,在default(默认命名空间)中未发现任何资源。

​ 这就是之前说的,default是默认的命名空间,当你不管是创建还是查询资源时未指定命名空间,默认是使用的default命名空间。所以本示例中我们在需要指定一下命名空间,或者使用-A选项,显示所有命名空间下的该类型资源。

1
2
3
4
5
6
7
8
9
10
11
12
# 显示所有命名空间下的Pods资源类型
[root@k8s-master-01 ~]# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
book-k8s nginx 1/1 Running 0 11m
kube-system calico-kube-controllers-7f59498f59-kf5nn 1/1 Running 7 (40m ago) 10d
kube-system calico-node-7ndvs 1/1 Running 7 10d
....忽略....
# 显示book-k8s命名空间下的pods资源
# -n为--namespace的缩写
[root@k8s-master-01 ~]# kubectl get pods -n book-k8s
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 12m

设置命名空间偏好(修改默认命名空间)

​ 如果您仅有这一个命名空间,认为每次查询或创建时都需要指定命名空间较为麻烦,您可以使用以下命令,将默认命名空间修改为您所指定的命名空间,但是这样也会伴随着一些失误,导致您之后操作集群时误操作风险。

1
2
3
4
5
6
7
8
9
10
# config为k8s的配置项,修改k8s的配置上下文。
[root@k8s-master-01 ~]# kubectl config set-context --current --namespace=book-k8s
Context "kubernetes-admin@kubernetes" modified.
# 验证
[root@k8s-master-01 ~]# kubectl config view --minify | grep namespace:
namespace: book-k8s
# 再度不加命名空间,发现他默认就是查询的book-k8s下的资源
[root@k8s-master-01 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 21m

删除命令空间

​ 当您需要删除命名空间时,可使用delete选项进行删除,如果改命名空间下存在资源,则会连通资源一并进行删除。

1
2
[root@k8s-master-01 namespace]# kubectl delete namespaces book-k8s 
namespace "book-k8s" deleted

​ 如果您是使用yaml创建的资源,也可以使用创建资源时所使用的yaml文件进行删除。

1
2
[root@k8s-master-01 namespace]# kubectl delete -f create-names.yaml
namespace "book-k8s" deleted

关于Pod

​ Pod是可以再Kubernetes中创建和管理的最小单元、最小的可部署的计算单位。

​ Pod(就像豌豆荚)是一组(一个或多个)容器;这些容器恭喜昂存储、网络、以及怎样运行这些容器的规约。Pod中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。

image-20250721180834032

​ 之前我们说微服务他是解耦合(松散耦合),这里又提到Pod是精密耦合,这是不冲突的,对于项目的拆解是属于解耦合,但是他们实际在运行中跟豌豆荚中的豆一样,他们的关系是紧密相连的。同时你的一个项目不可能拆分的特别细,不可能细到一个把报表一个容器,只是拆分的相对精细。

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod:每个 Pod 一个容器模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
  • 运行多个协同工作的容器的 Pod: Pod 可以封装由紧密耦合且需要共享资源的多个并置容器组成的应用。 这些位于同一位置的容器构成一个内聚单元。

​ 将多个并置、同管的容器组织到一个 Pod 中是一种相对高级的使用场景。 只有在一些场景中,容器之间紧密关联时你才应该使用这种模式。

使用Pod

​ 以下是一个Pod的示例,它由一个运行镜像nginx:latest的容器组成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat > pod-01.yaml << EOF
kind: Pod
apiVersion: v1
metadata:
name: nginx-01
namespace: book-k8s
spec:
containers:
- name: nginx-01
image: nginx:latest
ports:
- name: nginx-01-ports
containerPort: 80
protocol: TCP
EOF

​ 要创建上面显示的Pod,请允许以下命令:

1
[root@k8s-master-01 pod]# kubectl create -f pod-01.yaml

​ Pod通常不用于直接创建,而是使用工作负载资源进项创建。

Pod的生命周期

​ 本页讲述 Pod 的生命周期。 Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段。

​ 和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID), 并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。 如果一个节点死掉了,调度到该节点的 Pod 也被计划在给定超时期限结束后删除。

​ 在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作。

​ Pod 在其生命周期中只会被调度一次。 将 Pod 分配到特定节点的过程称为绑定,而选择使用哪个节点的过程称为调度。 一旦 Pod 被调度并绑定到某个节点,Kubernetes 会尝试在该节点上运行 Pod。 Pod 会在该节点上运行,直到 Pod 停止或者被终止; 如果 Kubernetes 无法在选定的节点上启动 Pod(例如,如果节点在 Pod 启动前崩溃), 那么特定的 Pod 将永远不会启动。

​ 以下我们使用一个示例来演示:

​ 注:imagePullPolicy为镜像拉取模式:

  • 当value为IfNotPresent时,当运行的本地节点存在镜像时,则无需额外拉取,直接使用本地镜像。
  • 当value为Always时,无论节点本地是否存在镜像,都从docker配置的仓库中进行额外拉取。
  • 当value为Never时,无论节点本地是否存在镜像,都从本地节点进行拉取,如果本地节点不存在该镜像,则会导致容器创建失败。
1
2
3
4
5
6
7
8
9
10
11
12
cat > pod-02.yaml << EOF
kind: Pod
apiVersion: v1
metadata:
name: nginx-02
namespace: book-k8s
spec:
containers:
- name: nginx-02
image: nginx:latest
imagePullPolicy: IfNotPresent
EOF

​ 运行yaml及查询资源状态使用如下命令:

1
2
3
4
[root@k8s-master-01 pod]# kubectl create -f pod-02.yaml
[root@k8s-master-01 pod]# kubectl get -f pod-02.yaml
NAME READY STATUS RESTARTS AGE
nginx-02 1/1 Running 0 9s

​ 最开始Pod的状态是Pending(等待执行),期间会去拉取镜像、运行镜像,当容器处于运行中时,状态则会变成Running,如果容器已失败运行结束,则会变成Failed,反之成功则会边成Succeeded(完成)。

根容器

​ 当我们创建了一个Pod,该Pod里拥有2个容器,那您可能会认为这个Pod里仅有两个容器,实则不然,其实该Pod拥有三个容器,其中一个容器叫做根容器(Pause)。

image-20250722160242947

​ 之前我们介绍过,pod是由一个或多个容器组成的,他们共享网络、存储。并且生命周期是一起启动一起停止等等,该根容器就是负责这个Pod中的多个Pod网络、存储共享、生命周期一起启动或停止等。

​ 下图中我们可以看到,其中一个node节点中,分别由K8s创建出来的三个Pod,这三个Pod分别都对应着一个容器,同样三个Pod也会有三个根容器(Pause)。

image-20250722160604659

创建多容器Pod

​ 上面我们采用的都是单容器对应一个pod进行创建,另外一个Pod可以对应多个容器,以下示例进行演示:

​ 对于一个Pod包含多个容器,只需要在containers下在写一个容器列表描述。

​ 其中pod.spec下的restartPolicy参数,表示pod重启的策略模式。

  • OnFailure: 只有在容器错误退出(退出状态非零时)才会重启。
  • Never: 从不会重启,即使失败或是完成终止都不会重启。
  • Always: 只要容器终止就自动重启容器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat > pods-01.yaml << EOF
kind: Pod
apiVersion: v1
metadata:
name: pods-01
namespace: book-k8s
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
- name: ubuntu
image: ubuntu:latest
command: ['sh','-c','echo "hello lwh" && sleep 3600']
imagePullPolicy: IfNotPresent
restartPolicy: OnFailure
EOF

​ 以下命名可以运行yaml文件:

1
2
[root@k8s-master-01 pod]# kubectl create -f pods-01.yaml 
pod/pods-01 created

​ 以下命令可以查询资源运行情况:

1
2
3
4
5
6
7
8
# 当前状态就是处于Pending中的一环,正在创建容器,也就是正在拉取容器,如果您本地没有镜像,这拉取需要等待一段时间。
[root@k8s-master-01 pod]# kubectl get -f pods-01.yaml
NAME READY STATUS RESTARTS AGE
pods-01 0/2 ContainerCreating 0 9s
# 过一段时间以后即可处于Running
[root@k8s-master-01 pod]# kubectl get -f pods-01.yaml
NAME READY STATUS RESTARTS AGE
pods-01 2/2 Running 0 2m23s

注意:Pod实际上是不支持重启的,Pod只支持创建、删除,所以这里说的重启并非真正意义上的重启,而是删除后重新创建达到的一个重启效果。

修改Pod

​ 原则上Pod是不能修改的,但是官方并没有说Pod不能修改,而是可修改的内容及其有限,几乎达到了不能修改的级别。

​ 修改etcd数据,可以使用以下命令,之后会为您打开一个vim编辑器,正常通过编辑文本的方式进行修改:

1
[root@k8s-master-01 pod]# kubectl edit -f pods-01.yaml

进入容器的方法

​ 如果要通过pod进入容器,与docker类似,使用以下命令:

  • exec:执行容器命令的选项。
  • -it:交互式访问容器。
  • pods/pods-01: 指定进入哪个Pod
  • -c nginx:如该pod存在多个容器,则需指定pod中的哪个容器名。
  • – :k8s中的容器命令特殊连接符号。
  • /bin/bash:在容器中执行的bash命令。
1
2
3
[root@k8s-master-01 pod]# kubectl exec -it pods/pods-01 -c nginx  -- /bin/bash
# 退出容器
root@pods-01:/# exit

删除Pod

​ 如果要删除Pod可通过以下命令进行删除:

利用创建Pod时所使用的yaml进行删除

1
2
[root@k8s-master-01 pod]# kubectl delete -f pods-01.yaml 
pod "pods-01" deleted

利用kubectl指定Pod进行删除

1
2
[root@k8s-master-01 pod]# kubectl delete pod pods-01 
pod "pods-01" deleted

Init类型容器

​ Init容器是一种特殊的容器,在Pod内的应用容器启动之前运行。Init容器可以包含一些应用镜像中不存在的实用工具和安装脚本。

​ 您可以在Pod的规约中与用来描述应用容器的containers数组平行的位置指定Init容器。Init容器使用pod.spec.initContainers来进行描述。

Init容器特点

  • 在主容器启动前执行。
  • 具有临时性,执行完成即终止。
  • kubectl get无法查看到pod。

使用Init容器

​ 以下生成了一个Yaml文件,该yaml较之前的复杂很多,以下会对yaml做些内容解析,该部分仅用理解initContainers参数,其余的volumeMounts目前稍作了解即可:

  • metadata.labels:为该Pod打上一个标签,对服务是无任何意义的,主要是便于后续资源查找筛选使用。
  • metadata.containers.volumeMounts:为该容器挂载一个持久卷,向宿主机的/work-dir目录创建文件可映射到容器内的/usr/share/nginx/html目录。
  • metadata.spec.volumes:创建一个空的持久卷,持久卷名字为:workdir
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
[root@k8s-master-01 pod]# cat > init-pods.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: my-web
namespace: book-k8s
labels:
app: my-web
spec:
containers:
- name: my-web
image: nginx:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
initContainers:
- name: my-service
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://info.cern.ch
volumeMounts:
- name: workdir
mountPath: "/work-dir"
volumes:
- name: workdir
emptyDir: {}
EOF

​ 执行yaml文件使用如下指令

1
2
[root@k8s-master-01 pod]# kubectl create -f init-pods.yaml 
pod/my-web created

​ yaml整个执行阶段的变化

1
2
3
4
5
6
7
8
9
10
11
12
# init容器正在创建
[root@k8s-master-01 pod]# kubectl get -f init-pods.yaml
NAME READY STATUS RESTARTS AGE
my-web 0/1 Init:0/1 0 6s
# init容器进行初始化任务中
[root@k8s-master-01 pod]# kubectl get -f init-pods.yaml
NAME READY STATUS RESTARTS AGE
my-web 0/1 PodInitializing 0 9s
# init容器初始化完成,应用容器运行中
[root@k8s-master-01 pod]# kubectl get -f init-pods.yaml
NAME READY STATUS RESTARTS AGE
my-web 1/1 Running 0 11s

Init容器的具体行为

以上yaml整个运行流程梳理:

  1. initContainers的初始化容器会先去执行wget下载一个index.html的文件到容器的/work-dir/index.html目录下,同时该init容器的/work-dir/目录挂载了名为workdir的持久卷,也相当于把文件下载到了这个持久卷中,执行完成后init容器会以completed状态结束。
  2. containers运行的应用容器是一个nginx页面服务,该容器将持久卷workdir挂载到服务首页配置目录中,持久卷内具有一个从init容器帮我们提前完成下载的index.html的文件,最终完成整个服务的部署启动。

总结:init通常用于应用服务运行前的环境检查,及先决条件配置,当先决条件满足后才会正式运行我们真正用到的容器服务。

Sidecar类型容器

​ Sidecar容器也称为边车容器,他与主应用容器是在同一个Pod中运行的辅助性容器。Sidecar容器通过额外的辅助性服务或功能(如日志记录、监控、安全性或数据同步)来增强或扩展主应用容器的功能,而无需直接修改主应用代码。

Sidecar容器特点

​ Sidecar具有以下特点:

  • Sidecar并非特定类型的容器,而是一个辅助容器的概念。
  • Sidecar生命周期具有持久性。
  • Sidecar容器可被kubectl get获取到(取决于用法)
  • Pod终止时主容器会先行终止,Sidecar等待主容器终止后随之终止。

以init容器启动Sidecar

​ 以下Ymal将产生具有Sidecar概念的pod,细心的可以看出,这怎么跟之前创建的Init容器一样,都具有一个containers(主容器)和initContainers(初始化容器),唯一不同的是initContainers容器里增加了一个重启策略,策略模式为Always,只要容器终止就会自动重启,这里我们先来解析以下他分别做了些什么事。

  • ​ 创建了一个containers容器,使用了alpine镜像,command中每秒向容器内的/opt/logs.txt文件中写入”logging”内容,并挂载了一个名为data的临时卷。
  • 创建了一个initContainers容器,使用了alpine镜像,并且restartPolicy(重启策略)为Always,容器停止则自动重启,command中实时查看/opt/logs.txt文件,并同样挂载了一个名为data的临时卷。
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
[root@k8s-master-01 pod]# cat > init-Sidecar.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: alpine:latest
command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
volumeMounts:
- name: data
mountPath: /opt
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always
command: ['sh', '-c', 'tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
volumes:
- name: data
emptyDir: {}

​ 以下命令可运行yaml文件:

1
[root@k8s-master-01 ~]# kubectl create -f init-Sidecar.yaml

​ 查看效果,需要查看资源日志可使用kubectl logs [资源名] [一个pod包含多个容器则需要指定容器]:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 由于init容器具有重启策略的加持,会一直进行重启,所以READY的时候会发现这个pod具有两个容器
[root@k8s-master-01 ~]# kubectl get pods myapp-55d976bcf9-m4mw8
NAME READY STATUS RESTARTS AGE
myapp-55d976bcf9-m4mw8 2/2 Running 0 35m
# 正常情况下我们无法通过kubectl查看到主容器的日志文件情况
[root@k8s-master-01 ~]# kubectl logs pods/myapp-55d976bcf9-m4mw8 myapp
# 但是当我们指定查看辅助容器,则可以快速查看和定位到主容器服务写入的日志
[root@k8s-master-01 ~]# kubectl logs pods/myapp-55d976bcf9-m4mw8 logshipper
logging
logging
logging
# 删除资源
[root@k8s-master-01 ~]# kubectl delete -f init-Sidecar.yaml

以普通容器启动Sidecar

​ 以下Yaml与上面init启动的Sidecar是一样的,区别就是在于Sidecar辅助容器现在用普通的containers进行创建,并且restartPolicy: Always与containers同级,作用域是containers下的所有容器,但是这个与Sidecar没有关系,这里只是为了让该资源创建时更为健壮,不会因为停止而停止。

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
[root@k8s-master-01 pod]# cat > pod-Sidecar.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: alpine:latest
command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
volumeMounts:
- name: data
mountPath: /opt
- name: logshipper
image: alpine:latest
command: ['sh', '-c', 'tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
restartPolicy: Always
volumes:
- name: data
emptyDir: {}
EOF

​ 使用以下命令进行yaml资源创建

1
2
[root@k8s-master-01 ~]# kubectl create -f pod-Sidecar.yaml 
deployment.apps/myapp created

​ 查看效果,需要查看资源日志可使用kubectl logs [资源名] [一个pod包含多个容器则需要指定容器]:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 与init生成的Sidecar概念区别在于containers生成的pods可被直观的看到,这里外面发现READY容器数量是2
[root@k8s-master-01 ~]# kubectl get pods myapp-75c678fb68-r7fxm
NAME READY STATUS RESTARTS AGE
myapp-75c678fb68-r7fxm 2/2 Running 0 3m38s
# 正常情况下我们无法通过kubectl查看到主容器的日志文件情况
[root@k8s-master-01 ~]# kubectl logs pods/myapp-75c678fb68-r7fxm myapp
# 但是当我们指定查看辅助容器,则可以快速查看和定位到主容器服务写入的日志
[root@k8s-master-01 ~]# kubectl logs pods/myapp-75c678fb68-r7fxm logshipper
logging
logging
logging
# 删除资源
[root@k8s-master-01 ~]# kubectl delete -f pod-Sidecar.yaml

Sidecar与init和普通容器的区别

从以上实验我们可以看出Sidecar与init的区别在于:

  • 一个是可持续性运行的容器。那是因为我们加的restartPolicy: Always重启策略使init不会因为一次执行完成后而终止。
  • 一个是为主容器做完先决运行条件后终止的容器临时在主容器启动前完成运行的容器。

从以上实验我们可以看出Sidecar与普通containers的就没有区别,他就是一个普通的容器。

​ 所以我们在开头就说Sidecar容器他只是一个概念,取决于你的用途,你的init可以用于为主容器完成先决运行条件配置、检查,也可以使用init辅助主容器持续的完成日志转发等扩展功能,而无需去修改主容器的代码。普通的containers容器也相同,你可以使用containers作为主容器,也可以使用containers辅助你另外一个主容器达到功能扩展。

​ 就类似在一个公司会有高级程序员和程序员助理,大家都是打螺丝的员工,没有区别,而助理是为高级程序员做辅助性工作的,只是做的事情不一样而已。

重要:Pod中存在多个容器的话,并且用到了Sidecar概念时,你如果使用containers来运行这类辅助性工作的容器,里面的容器他是一起启动的,如果您需要Sidecar辅助性容器要有些延迟,在应用容器先行启动的话,建议使用initcontainers来进行创建。

Sidecar可以做什么?

​ 一般边车容器可用来处理以下几个事件:

  • 日志代理/转发,例如fluentd;
  • Service Mesh,比如Istio,Linkerd;
  • 代理,比如Docker Ambassador;
  • 探活:检查某些组件是不是正常工作;
  • 其他辅助性工作,比如拷贝文件,下载文件等;

静态pod

正常资源创建流程

在此我们可以回忆一下,我们前面介绍的k8s创建一个Pod的流程,kubectl将指令发送给API,API接收到请求后,询问kube-scheduler(调度器)这个Pod适合放在哪个节点上运行,发送给API,API将资源信息存放到etcd数据库,并发送给选中节点中的kubelet,节点中的kubelet把指令翻译成docker看得懂的语言进行创建,并将创建的结果及状态反馈给API,API再将状态信息等数据存入ETCD数据库。所有的资源创建都由API进行监管

而静态 Pod 在指定的节点上由 kubelet 守护进程直接管理,不需要 API 服务器监管。 与由控制面管理的 Pod(例如,Deployment) 不同;kubelet 监视每个静态 Pod(在它失败之后重新启动)。

​ 静态 Pod 始终都会绑定到特定节点的 Kubelet 上。

​ 既然静态Pod不能API所监管,那么我们为什么可以在kubectl get node的时候看见这些静态Pod呢?

​ kubelet 会尝试通过 Kubernetes API 服务器为每个静态 Pod 自动创建一个镜像 mirror Pod。 这意味着节点上运行的静态 Pod 对 API 服务来说是可见的,但是不能通过 API 服务器来控制。 Pod 名称将把以连字符开头的节点主机名作为后缀。

静态Pod如何创建?

​ 其实静态Pod里我们很近,其实k8s中的API、controller-manager、kube-scheduler就是使用静态Pod进行部署的。我们可以发现这几个Pod他的命名格式跟静态Pod一摸一样,都是组件名+节点主机名进行命名。

1
2
3
4
[root@k8s-master-01 ~]# kubectl get pods -A
kube-system kube-apiserver-k8s-master-01 1/1 Running 17 (24m ago) 17d
kube-system kube-controller-manager-k8s-master-01 1/1 Running 15 (24m ago) 17d
kube-system kube-scheduler-k8s-master-01 1/1 Running 15 (24m ago) 17d

​ 既然静态Pod是节点中的kubelet进行创建管理的,那么我们可以通过kubelet的守护进程找到静态Pod的配置文件10-kubeadm.conf

1
2
3
4
5
6
7
# 
[root@k8s-master-01 ~]# systemctl status kubelet.service
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
....忽略....

​ 找到配置文件后,查看他的配置文件,找到他的config.yaml文件所在目录。

1
2
3
4
5
[root@k8s-master-01 ~]# cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf | grep -i Environment
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
EnvironmentFile=-/etc/sysconfig/kubelet

​ 通过它的yaml文件找到它静态Pod的yaml文件存在路径。

1
2
[root@k8s-master-01 manifests]# cat /var/lib/kubelet/config.yaml | grep -i staticPodPath
staticPodPath: /etc/kubernetes/manifests

​ 进入到静态Pod的yaml文件存在路径,发现我们的API这些静态Pod的yaml文件全都存放在这里。

1
2
3
4
5
6
7
[root@k8s-master-01 ~]# cd /etc/kubernetes/manifests
[root@k8s-master-01 manifests]# ll
总用量 16
-rw-------. 1 root root 2572 7月 8 16:02 etcd.yaml
-rw-------. 1 root root 3614 7月 8 16:02 kube-apiserver.yaml
-rw-------. 1 root root 3120 7月 8 16:02 kube-controller-manager.yaml
-rw-------. 1 root root 1673 7月 8 16:02 kube-scheduler.yaml

​ 这个staticPodPath的路径就非常有意义,所有你在该目录下创建的yaml都会直接为您创建出一个静态Pod,无需您单独去执行任何命令,以下我们就在该目录创建一个简单的Yaml来演示一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在staticPodPath路径下创建一个yaml
[root@k8s-master-01 manifests]#cat > staticPod.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: staticpod
namespace: book-k8s
spec:
containers:
- name: staticpod
image: nginx
imagePullPolicy: IfNotPresent
EOF

​ 稍等一会,因为如果您当前节点的本地没有镜像它需要先拉镜像,以及kubelet会定期扫描目录中的变化。在此查询即可发现我们创建的静态资源就出现了。

​ 这里我们发现静态Pod是以资源名-节点主机名称的方式来命名的,并且我们可以自由选择将它部署在哪个命名空间下,与我们普通Pod类似,只是创建方式,以及运行流程监管对象不同。

1
2
3
4
5
6
7
[root@k8s-master-01 manifests]# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
book-k8s staticpod-k8s-master-01 1/1 Running 0 2m34s
kube-system calico-kube-controllers-7f59498f59-kf5nn 1/1 Running 13 (54m ago) 15d
kube-system calico-node-7ndvs 1/1 Running 13 (54m ago) 15d
kube-system calico-node-l4rfm 1/1 Running 13 (54m ago) 15d
kube-system calico-node-ls56h 1/1 Running 13 (54m ago) 15d

静态Pod的用途

​ 您可以试想一下,您正常通过API创建的资源,万一哪一天API组件坏了,那么您创建的那个资源也会随着API一起全部宕机掉,但是你当前想要有一个API这个重要的组件即使坏了,也不要影响我这个Pod,那么这个时候您就可以考虑使用静态Pod进行发布。

​ 例如:您有一个监控系统负责监控K8s集群中的各个组件以及节点的资源使用情况,那么您的这个监控系统就可以使用静态Pod进行发布,避免因为集群API损坏导致您的监控系统一同失效。

删除静态Pod

​ 由于静态Pod是由kubelet通过扫描静态目录,直接进行创建管理,删除也是非常简单,只需将需要删除的yaml从目录中删除即可。

1
[root@k8s-master-01 manifests]# rm -rf staticPod.yaml

注意:静态Pod是无法通过kubectl delete [资源名]进行删除,因为它并非由API进行创建的,所有您无法通过该命令进行删除和管理操作,一切的操作只存在于kubelet配置的静态目录中。