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 | kubectl diff -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 | kubectl create deployment vk-deploy --image=nginx --dry-run -o yaml > deploy-name.yaml |
更多内容,参考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 | kubectl krew install neat |
3.5. -h帮助
在生成yaml文件的过程中,如果忘记了参数,可以使用kubectl xxx -h
命令来获取帮助。
1 | kubectl -h |
-h
除了可以查看生成yaml文件的命令帮助,还可以用来查看所有kubectl
子命令的帮助,非常实用。
3.6. explain帮助
编写yaml文件的过程中,如果忘记了某些结构和字段,可以使用kubectl explain
命令来获取帮助。
1、查看资源包含哪些字段
以查看deployment的yaml包含哪些字段为例:
1 | kubectl explain deployment |
2、查看子字段
以查看节点亲和性字段为例:
1 | kubectl explain deployment.spec.template.spec.affinity |
必须说明的是,explain不止可以查看k8s内置资源结构,还可以查看crd资源结构,例如:
1 | kubectl explain milvus --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 | kubectl run vkpod --image=busybox --restart=Never --dry-run=client -oyaml |
更多内容,参考Kubernetes kubectl run 命令详解和kubectl 的用法约定。
5. 查看资源对象
5.1. 查看可用api版本
1 | kubectl api-versions |
5.2. 查看资源缩写
1 | kubectl describe |
建议记住常用资源的SHORTNAMES,可以提升输入效率。
此外,记住常用资源的APIGROUP,可以提高编写yaml文件时的效率。
5.3. 查看所有资源对象
1 | kubectl get all |
5.4. 查看指定的资源对象
以deployment资源对象为例,其他资源对象操作方法相同。
查看所有空间的所有deployment,deployment可以缩写为deploy
1 | kubectl get deployment --all-namespaces |
查看指定空间下的所有deployment,默认空间default
1 | kubectl get deploy |
查看deployment,显示label
1 | kubectl get deploy --show-labels |
根据label筛选deployment
1 | kubectl get deploy -l 'env=dev' |
查看指定的deployment
1 | kubectl get deploy/deployment-name |
查看deployment详细信息
1 | kubectl describe deploy/deployment-name |
查看deployment实时变化
1 | kubectl get deploy/deployment-name --watch |
5.5. 根据label筛选资源对象
筛选所有label包含 env=dev
的资源对象
1 | kubectl get all -l '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 |
|
更多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 | # 编辑集群中的资源 |
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 | spec: |
或者json格式的配置文件,也是支持的。
2、添加节点亲和性
1 | kubectl patch deployment deployment-name --type=merge -p "$(cat data.yaml)" |
3、批量添加节点亲和性
1 | kubectl get deployment -n $namesapce -o=jsonpath='{.items[*].metadata.name}' | xargs kubectl patch deployment --type=merge --patch-file data.yaml -n $namesapce |
7.2.3. patch删除存活探针
1 | kubectl patch deployment deployment-name --type json \ |
8. 删除资源对象
以deployment资源对象为例,其他资源对象操作方法相同。
删除单个deployment:
1 | kubectl delete deployment deployment-name |
批量删除deployment:
1 | kubectl get deployment -n <your-namespace> -oname | \ |
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 | kubectl scale deployment <deployment_name> --replicas=0 -n <namespace> |
方法四:通过rollout实现重建pod
1 | kubectl rollout restart deployment <deployment_name> -n <namespace> |
方法五:通过docker停止容器实现重建pod
前提是保证pod的重启策略是Always。
登录到pod所在宿主机,通过docker命令停止pod的pause容器。
1 | docker ps | grep xxx |
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 | kubectl expose deployment deployment-name --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 | # 本地端口映射pod端口 |
注意:使用该转发功能依赖socat,需要提前安装
否则会报错:unable to do port forwarding: socat not found
1 | yum install -y socat |
14. 版本回退
1 | # 查看发布历史,看到的版本号按照递增顺序分配,越大的版本号表示越新的版本 |
rollout表示roll out,这里翻译为发布。
回退到指定replicaset对应的版本:
1 | # 查看想要回退到的replicaset详情 |
15. configmap和secret
1、创建configmap
1 | kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm |
2、创建secret
1 | # 在命令中指定key和value |
在yaml文件中看到的username和password,都是经过base64加密的字符串。
1 | # 加密 |
16. 创建多个资源
如果要创建ns,然后在ns中创建configmap,最后创建deployment(依赖configmap),该怎么操作?
方法一:挨个apply
1 | kubectl apply -f ns.yaml |
方法二:按顺序合并,然后apply
1 | cat ns.yaml <(echo "---") cm.yaml <(echo "---") deploy.yaml > ns-cm-deploy.yaml |
方法三:多次apply
1 | kubectl apply -f . |
方法四:添加编号
1 | mv ns.yaml 00-ns.yaml |
17. 强制删除namspace
17.1. 问题描述
有时,通过kubectl删除了一个namespace之后,namespace并不会消失,而是一直处于Terminating状态。
17.2. 解决办法
方法一:先删除namespace中的资源
1 | kubectl get ns <your-namespace> -oyaml |
方法二:强制删除
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 | kubectl proxy --port=6880 & |