一个计算机技术爱好者与学习者

0%

好好学K8S:kubectl命令——资源对象增删查改篇

1. K8S资源对象是啥?

在 Kubernetes 系统中,Kubernetes 对象 是持久化的实体。 Kubernetes 使用这些实体去表示整个集群的状态,具体包括pod、replicaset、deployment、service、configmap、secret等等。

参考文档:

2. 资源对象管理方式

资源对象的管理有三种方式:指令式命令、指令式对象配置和声明式对象配置。
其中,指令式对象配置和声明式对象配置都要依赖资源对象的yaml/json定义文件。

2.1. 指令式命令

使用指令式命令时,用户可以在集群中的活动对象上进行操作。用户将操作传给 kubectl 命令作为参数或标志。
这是开始或者在集群中运行一次性任务的推荐方法。因为这种方式直接在活跃对象上操作,所以它不提供以前配置的历史记录。
例如,创建一个nginx deployment:

1
kubectl create deployment nginx --image nginx

2.2. 指令式对象配置

在指令式对象配置中,kubectl 命令指定操作(创建、更新和删除),可选标志和至少一个文件名。指定的文件必须包含 YAML 或 JSON 格式的对象的完整定义。
例如,创建配置文件中定义的对象(前提是写好了nginx.yaml):

1
kubectl create -f nginx.yaml

通过覆盖更新配置文件中定义的对象:

1
kubectl replace -f nginx.yaml

删除两个配置文件中定义的对象:

1
kubectl delete -f nginx.yaml -f redis.yaml

2.3. 声明式对象配置

使用声明式对象配置时,用户对本地存储的对象配置文件进行操作,但是用户未定义要对该文件执行的操作。 kubectl 会自动检测每个文件的创建、更新和删除操作。这使得配置可以在目录上工作,根据目录中配置文件对不同的对象执行不同的操作。
例如,处理 configs 目录中的所有对象配置文件,创建并更新活跃对象。
可以首先使用 diff 子命令查看将要进行的更改,然后再进行应用:

1
2
kubectl diff -f configs/
kubectl apply -f configs/

与指令式对象配置相比的优点:

  • 对活动对象所做的更改即使未合并到配置文件中,也会被保留下来。
  • 声明性对象配置更好地支持对目录进行操作并自动检测每个文件的操作类型(创建,更新,删除)。

与指令式对象配置相比的缺点:

  • 声明式对象配置难于调试并且出现异常时结果难以理解。
  • 使用 diff 产生的部分更新会创建复杂的合并和补丁操作。

3. 资源对象的yaml/json文件详解

3.1. yaml/json文件构成

k8s资源对象的yaml文件分成四部分,apiVersion、kind、metadata和spec。

  • apiVersion和kind是关联的,参考kubectl api-resources
  • metadata必填name、namespace、labels。
  • pod.spec主要填containers的name和image;deployment.spec主要填replicas、template和selector;service.spec主要填selector、ports和type。

3.2. yaml/json文件编写

编写k8s资源对象的yaml/json文件,有三种方法:

  • 纯手工编写(难度最高)
  • 使用--dry-run生成yaml/json文件,然后修改
  • 从线上导出yaml/json文件,然后修改

3.3. 生成文件模板

生成deployment的yaml/json文件模板(推荐):

1
2
kubectl create deployment vk-deploy --image=nginx --dry-run -o yaml > deploy-name.yaml
kubectl create deployment vk-deploy --image=nginx --dry-run -o json > deploy-name.json

更多内容,参考Kubernetes kubectl create deployment 命令详解

注意,我们并不需要在deployment中指定容器对外暴露的ports,因为该字段只是一个提示作用。

List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default “0.0.0.0” address inside a container will be accessible from the network. Cannot be updated.

生成deployment的yaml文件模板(即将废弃):

1
kubectl run vk-deploy --image=nginx --dry-run -o yaml

会出现提示:
kubectl 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.
因为官方不推荐使用 run-pod/v1 以外的其他生成器,其他生成器不久后就会弃用。更多内容参考kubectl run

3.4. 导出文件模板

从K8S集群中导出已经存在的资源对象的yaml文件(已经废弃):

1
kubectl get deploy/deployment-name -o yaml --export > deploy-name.yaml

出现提示:
Flag –export has been deprecated, This flag is deprecated and will be removed in future.
该flag 1.14版本弃用,1.18版本移除,目前已经不可用。

替代方案:

1
2
kubectl krew install neat
kubectl get deploy/deployment-name -o yaml | kubectl neat

3.5. -h帮助

在生成yaml文件的过程中,如果忘记了参数,可以使用kubectl xxx -h命令来获取帮助。

1
2
3
kubectl -h
kubectl create -h
kubectl create deployment -h

-h除了可以查看生成yaml文件的命令帮助,还可以用来查看所有kubectl子命令的帮助,非常实用。

3.6. explain帮助

编写yaml文件的过程中,如果忘记了某些结构和字段,可以使用kubectl explain命令来获取帮助。

1、查看资源包含哪些字段
以查看deployment的yaml包含哪些字段为例:

1
2
3
kubectl explain deployment
kubectl explain deployment --api-version=apps/v1
kubectl explain deployment --api-version=apps/v1 --recursive=true

2、查看子字段
以查看节点亲和性字段为例:

1
2
3
4
kubectl explain deployment.spec.template.spec.affinity
kubectl explain deployment.spec.template.spec.affinity.nodeAffinity
...
kubectl explain deployment.spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions

必须说明的是,explain不止可以查看k8s内置资源结构,还可以查看crd资源结构,例如:

1
2
3
4
kubectl explain milvus --api-version=milvus.io/v1beta1
kubectl explain milvus.spec --api-version=milvus.io/v1beta1
kubectl explain milvus.spec.components --api-version=milvus.io/v1beta1
kubectl explain milvus.spec.dependencies --api-version=milvus.io/v1beta1

milvus安装配置方法,参考《K8S中安装配置Milvus》

3.7. yaml/json文件验证

1
kubectl create --validate -f deploy-name.yaml --dry-run=client

需要注意的是,--dry-run=client参数要带着,否则验证成功后,这个文件直接就提交给k8s了。

4. pod yaml

生成pod的yaml文件模板比较常用,这里单独做一下记录。

1
2
3
4
5
6
kubectl run vkpod --image=busybox --restart=Never --dry-run=client -oyaml

kubectl run vk-pod --image=busybox --dry-run=client -o yaml --command -- sleep 1000

kubectl run vk-pod --image=busybox -l 'name=vk-pod,env=dev' --dry-run=client -o yaml
kubectl run vk-pod --image=busybox --labels='name=vk-pod,env=dev' --dry-run=client -o yaml

更多内容,参考Kubernetes kubectl run 命令详解kubectl 的用法约定

5. 查看资源对象

5.1. 查看可用api版本

1
kubectl api-versions

5.2. 查看资源缩写

1
2
kubectl describe
kubectl api-resources

建议记住常用资源的SHORTNAMES,可以提升输入效率。
此外,记住常用资源的APIGROUP,可以提高编写yaml文件时的效率。

5.3. 查看所有资源对象

1
2
kubectl get all
kubectl get all -o wide

5.4. 查看指定的资源对象

以deployment资源对象为例,其他资源对象操作方法相同。

查看所有空间的所有deployment,deployment可以缩写为deploy

1
kubectl get deployment --all-namespaces

查看指定空间下的所有deployment,默认空间default

1
2
3
kubectl get deploy
kubectl get deploy -n voidking
kubectl get deploy -n voidking -o wide

查看deployment,显示label

1
kubectl get deploy --show-labels

根据label筛选deployment

1
2
3
kubectl get deploy -l 'env=dev'
kubectl get deploy --selector='env=dev'
kubectl get deploy --selector="env=dev,type=frontend"

查看指定的deployment

1
2
3
kubectl get deploy/deployment-name
kubectl get deploy/deployment-name -o wide
kubectl get deploy/deployment-name -o yaml

查看deployment详细信息

1
kubectl describe deploy/deployment-name

查看deployment实时变化

1
kubectl get deploy/deployment-name --watch

5.5. 根据label筛选资源对象

筛选所有label包含 env=dev 的资源对象

1
2
3
kubectl get all -l 'env=dev'
# or
kubectl get all --selector 'env=dev'

5.6. 根据field筛选资源对象

对于Pod资源来说,以下是一些可用于--field-selector的字段:

  • metadata.name
  • metadata.namespace
  • status.phase(例如,Running,Pending,Succeeded,Failed,Unknown)
  • status.podIP
  • spec.nodeName(节点名)

这是一个不完全的列表,支持的字段可能会随着Kubernetes版本的更新而变化。

筛选所有Running状态的Pod

1
kubectl get pod -A --field-selector status.phase==Running

5.7. 根据jsonpath筛选资源对象

筛选所有Ready状态的Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}' > pods.txt

while read line;do
namespace=$(echo "$line" | awk '{print $1}')
name=$(echo "$line" | awk '{print $2}')
# ready 取值 True/False
ready=$(kubectl get pods $name -n $namespace -o jsonpath="{.status.conditions[?(@.type=='Ready')].status}")
if [[ $ready == "True" ]];then
echo "${namespace}/${name} is ready!"
else
echo "${namespace}/${name} is not ready!"
fi
done < pods.txt

更多jsonpath的内容,参考文档《JSONPath入门篇》

6. 创建资源对象

以deployment资源对象为例,其他资源对象操作方法相同。

6.1. 指令式命令

1
kubectl create deployment vk-deploy --image=nginx

6.2. 指令式对象配置

指令式对象配置,需要依赖定义好的资源对象yaml文件。

1
kubectl create -f deploy.yaml

6.3. 声明式对象配置

和指令式对象配置唯一不同的是,kubectl create 改为 kubectl apply

7. 更新资源对象

以deployment资源对象为例,其他资源对象操作方法相同。

7.1. 基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 编辑集群中的资源
kubectl edit deployment deployment-name

# 比较manifest与集群中当前资源的不同
kubectl diff -f deploy.yaml

# 应用最新定义
kubectl replace -f deploy.yaml
kubectl apply -f deploy.yaml

# 添加label
kubectl label deployment deployment-name new-label=awesome

# 添加annotation
kubectl annotate deployment deployment-name icon-url=http://goo.gl/XXBTWq

7.2. patch操作

7.2.1. patch简介

kubectl patch: Update field(s) of a resource using strategic merge patch.

用法:

1
kubectl patch (-f FILENAME | TYPE NAME) -p PATCH

JSON and YAML formats are accepted.

--type有三个选项:

  • strategic:策略更新,也是默认的选项。根据k8s crd 资源对象的字段定义(patchStrategy)决定如何该如何更新,不指定patchStrategy时,默认是replace,当前大多资源对象在代码中已经指定patchStrategy为merge。
  • merge:合并更新,有相同的字段就替换,没有相同的字段就合并。和代码中指定patchStrategy为merge效果相同。
  • json:json更新,要求--patch参数是一个json列表 [{"op":"","path":"","value":""}]

merge之坑:

  • 如果一个字段的值为数组,无论你有没有指定 --type=merge,新的元素都将覆盖掉原先所有的列表元素。
  • merge 想要删除一个 key,只能通过将 key 设置为 null,但有些 key 对应的 value 是不能为 null 的。

--patch 参数是 json 格式时,path 里的斜杠就会与 key 冲突,此时可以将 波浪线和斜杠 替换成如下转义字符。

  • ~(波浪线)对应的是 ~0
  • /(斜杠)对应的是 ~1

这个规则和kustomize中的patchesJson6902类似。

参考文档:

7.2.2. patch添加节点亲和性

1、准备亲和性配置,例如 data.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spec:
template:
spec:
# affinity:
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: nodetype
# operator: In
# values:
# - infra
nodeSelector:
nodetype: infra
tolerations:
- key: "nodetype"
operator: "Equal"
value: "infra"
effect: "NoSchedule"

或者json格式的配置文件,也是支持的。

2、添加节点亲和性

1
2
3
kubectl patch deployment deployment-name --type=merge -p "$(cat data.yaml)"
# or
kubectl patch deployment deployment-name --type=merge --patch-file data.yaml

3、批量添加节点亲和性

1
2
kubectl get deployment -n $namesapce -o=jsonpath='{.items[*].metadata.name}' | xargs kubectl patch deployment --type=merge --patch-file data.yaml -n $namesapce
kubectl get statefulset -n $namesapce -o=jsonpath='{.items[*].metadata.name}' | xargs kubectl patch statefulset --type=merge --patch-file data.yaml -n $namesapce

7.2.3. patch删除存活探针

1
2
kubectl patch deployment deployment-name --type json \
-p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'

8. 删除资源对象

以deployment资源对象为例,其他资源对象操作方法相同。

删除单个deployment:

1
kubectl delete deployment deployment-name

批量删除deployment:

1
2
kubectl get deployment -n <your-namespace> -oname | \
xargs kubectl delete -n <your-namespace>

9. 扩缩容

扩缩容针对pod对象,需要操作deployment对象。

方法一:扩缩容命令。

1
kubectl scale --replicas=2 deployment deployment-name

方法二:更新yaml文件。

10. 重启pod

k8s中,没有pod重启命令,只有pod重建命理。
而我们配置的pod重启策略,本质上也是重建pod,只不过pod名称相同,保留了event记录。

验证方法:
创建一个100秒重启的pod,启动后在其中创建一个文件。
当pod重启后,文件消失,pod在宿主机上对应的容器id也全部改变了。

11. 重建pod

参考文档Using Kubectl to Restart a Kubernetes Pod

方法一:删除pod并重建

1
kubectl get pod <pod_name> -n <namespace> -o yaml | kubectl replace --force -f -

方法二:删除pod利用保活重建(前提是有replicaset)

1
kubectl delete pod <pod_name> -n <namespace>

方法三:通过扩缩实现重建pod

1
2
kubectl scale deployment <deployment_name> --replicas=0 -n <namespace>
kubectl scale deployment <deployment_name> --replicas=2 -n <namespace>

方法四:通过rollout实现重建pod

1
kubectl rollout restart deployment <deployment_name> -n <namespace>

方法五:通过docker停止容器实现重建pod
前提是保证pod的重启策略是Always。
登录到pod所在宿主机,通过docker命令停止pod的pause容器。

1
2
docker ps | grep xxx
docker stop yyy

pause容器被停止后,kubectl get pods xxx看到的是pod重启。
kubectl describe pod xxx会看到:
Pod xxx changed, it will be killed and re-created.
是的,实际上pod的所有容器都会被重建。

12. 创建service/暴露服务

12.1. 命令式指令

为deployment创建clusterip,暴露clusterip的80端口,对应pod的80端口

1
kubectl expose deployment deployment-name --port=80 --name svc-name

为deployment创建clusterip,暴露clusterip的6789端口,对应pod的80端口

1
2
kubectl expose deployment deployment-name --target-port=80 --port=6789
kubectl expose -f vk-deploy.yaml --target-port=80 --port=6789

创建nodeport,暴露clusterip的80端口,对应pod的80端口,暴露node的随机端口

1
kubectl expose deployment deployment-name --port=80 --type=NodePort --name svc-name

创建clusterip,暴露clusterip的80端口,对应pod的80端口

1
kubectl create service clusterip svc-name --tcp=80:80

创建nodeport,暴露clusterip的80端口,对应pod的pod端口,暴露node的30080端口

1
kubectl create service nodeport svc-name --tcp=80:80 --node-port=30080

12.2. 命令式配置文件

生成service的yaml文件模板(推荐方法):

1
kubectl create service clusterip vk-svc --tcp="5678:80" --dry-run -o yaml > service.yaml

创建service

1
kubectl create -f service.yaml

更多内容,参考Kubernetes kubectl create service 命令详解Service

12.3. 声明式配置文件

创建service

1
kubectl apply -f service.yaml

13. kubectl port-forward

对外暴露服务,我们会使用nodeport或者loadbalance类型的service。
如果是临时测试,还可以使用kubectl port-forward

kubectl port-forward 通过端口转发映射本地端口到指定的应用端口,从而访问集群中的应用程序。

1
2
3
4
5
6
7
# 本地端口映射pod端口
kubectl port-forward pod/$pod_name -n $namespace $node_port:$pod_port
kubectl port-forward pod/$pod_name -n $namespace --address 0.0.0.0 $node_port:$pod_port

# 本地端口映射service端口
kubectl port-forward service/$service_name -n $namespace $node_port:$service_port
kubectl port-forward service/$service_name -n $namespace --address 0.0.0.0 $node_port:$service_port

注意:使用该转发功能依赖socat,需要提前安装
否则会报错:unable to do port forwarding: socat not found

1
yum install -y socat

14. 版本回退

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看发布历史,看到的版本号按照递增顺序分配,越大的版本号表示越新的版本
kubectl rollout history deployment deployment-name

# 查看发布历史详情
kubectl rollout history deployment deployment-name --revision=1

# 查看发布状态
kubectl rollout status deployment deployment-name

# 回退到上一个版本
kubectl rollout undo deployment deployment-name

# 回退到指定版本
kubectl rollout undo deployment deployment-name --to-revision=1

rollout表示roll out,这里翻译为发布。

回退到指定replicaset对应的版本:

1
2
3
4
5
# 查看想要回退到的replicaset详情
kubectl describe replicaset deployment-name-xxx

# 找到 Annotations 中的 deployment.kubernetes.io/revision ,例如值为2,那么回退命令为
kubectl rollout undo deployment deployment-name --to-revision=1

15. configmap和secret

1、创建configmap

1
2
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>

2、创建secret

1
2
3
4
5
6
7
8
9
10
# 在命令中指定key和value
kubectl create secret generic db-user-pass --from-literal=username=voidking --from-literal=password='vkpassword'
kubectl get secret db-user-pass -o yaml

# 在文件中指定value
echo -n 'voidking' > ./username.txt
echo -n 'vkpassword' > ./password.txt
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
kubectl create secret generic db-user-pass --from-file=username=./username.txt --from-file=password=./password.txt
kubectl get secret db-user-pass -o yaml

在yaml文件中看到的username和password,都是经过base64加密的字符串。

1
2
3
4
# 加密
echo -n 'voidking' | base64
# 解密
echo 'dm9pZGtpbmc=' | base64 --decode

16. 创建多个资源

如果要创建ns,然后在ns中创建configmap,最后创建deployment(依赖configmap),该怎么操作?
方法一:挨个apply

1
2
3
kubectl apply -f ns.yaml
kubectl apply -f cm.yaml
kubectl apply -f deploy.yaml

方法二:按顺序合并,然后apply

1
2
cat ns.yaml <(echo "---") cm.yaml <(echo "---") deploy.yaml > ns-cm-deploy.yaml
kubecl apply -f ns-cm-deploy.yaml

方法三:多次apply

1
2
kubectl apply -f .
kubectl apply -f .

方法四:添加编号

1
2
3
4
mv ns.yaml 00-ns.yaml
mv cm.yaml 01-cm.yaml
mv deploy.yaml 02-deploy.yaml
kubectl apply -f .

17. 强制删除namspace

17.1. 问题描述

有时,通过kubectl删除了一个namespace之后,namespace并不会消失,而是一直处于Terminating状态。

17.2. 解决办法

方法一:先删除namespace中的资源

1
2
3
4
5
6
kubectl get ns <your-namespace> -oyaml

kubectl api-resources --verbs=list --namespaced -o name | \
xargs -n 1 kubectl get --show-kind --ignore-not-found -n <your-namespace>

kubectl delete <resource-type> <resource-name> --namespace=<your-namespace>

方法二:强制删除

1
kubectl delete ns <your-namespace> --force --grace-period=0

方法三:强制删除plus

1
kubectl patch namespace <your-namespace> -p '{"metadata":{"finalizers": []}}' --type=merge

方法四:方法三的API调用版

1、获取namepace配置

1
kubectl get ns <your-namespace> -o json > namespace.json

2、编辑namespace配置
编辑namespace.json,从 finalizers 字段中删除 kubernetes。

3、提交namespace配置

1
2
3
kubectl proxy --port=6880 &
curl -k -H "Content-Type: application/json" -X PUT --data-binary @namespace.json http://127.0.0.1:6880/api/v1/namespaces/${NAMESPACE}/finalize
kubectl get ns
  • 本文作者: 好好学习的郝
  • 原文链接: https://www.voidking.com/dev-kubectl-curd/
  • 版权声明: 本文采用 BY-NC-SA 许可协议,转载请注明出处!源站会即时更新知识点并修正错误,欢迎访问~
  • 微信公众号同步更新,欢迎关注~