<!-- 《基于 Kubernetes 的云原生 DevOps》第7章 强大的 Kubernetes 工具 --> <!-- cloud-native-devops-with-kubernetes-ch-07 --> --- > My mechanic told me, "I couldn't repair your brakes, so I made your horn louder." > > -- Steven Wright --- [TOC] ## 7.1 掌握 Kubectl **Shell 别名** 关于 PowerShell 如果设置别名可以参考[这篇博客](https://segmentfault.com/a/1190000015928399 "PowerShell设置命令别名Alias") 。 ```powershell PS C:\k8s> $profile C:\Users\jiajia\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 ``` 在 *Microsoft.PowerShell_profile.ps1* 文件中添加设置别名的脚本,之后每次启动 *PowerShell* 就可以直接使用别名了。 *$profile* 示例: ```powershell Set-Alias k kubectl function kubectlGet {param([string] $kind) kubectl get $kind} Set-Alias kg kubectlGet function kubectlGetPods {kubectl get pods} Set-Alias kgp kubectlGetPods ``` 如果出现 *在此系统上禁止运行脚本* 的错误,参考[MSDN](https://docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.2 "about_Execution_Policies"),执行如下命令修改 PowerShell 执行策略(默认为 *Restricted*,修改为 *RemoteSigned* 就可以运行脚本了)。 ```powershell Set-ExecutionPolicy -ExecutionPolicy RemoteSigned ``` 使用示例: ```powershell PS C:\k8s> k get pods NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-m8flw 1/1 Running 1 (2d18h ago) 2d21h demo-5bf7bc95c7-qzbw5 1/1 Running 1 (2d18h ago) 2d20h PS C:\k8s> kg po NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-m8flw 1/1 Running 1 (2d18h ago) 2d21h demo-5bf7bc95c7-qzbw5 1/1 Running 1 (2d18h ago) 2d20h PS C:\k8s> kgp NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-m8flw 1/1 Running 1 (2d18h ago) 2d21h demo-5bf7bc95c7-qzbw5 1/1 Running 1 (2d18h ago) 2d20h ``` 更多的博客可以参考[Ahmet的博客](https://ahmet.im/blog/kubectl-aliases/index.html "Fun with kubectl aliases") Linux 下没试过,应该是在 *.bash_profile* 文件中设置别名: ```bash alias k=kubectl ``` **使用缩写的标志** *kubectl* 的许多标志和开关都支持缩写形式。 如 *--namespace* 可以缩写为 *-n* 。 ```powershell PS C:\k8s> kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-78fcd69978-2s4jv 1/1 Running 8 (4d2h ago) 155d etcd-minikube 1/1 Running 8 (4d2h ago) 155d kube-apiserver-minikube 1/1 Running 8 (4d2h ago) 155d kube-controller-manager-minikube 1/1 Running 8 (4d2h ago) 155d kube-proxy-zwsz8 1/1 Running 8 (4d2h ago) 155d kube-scheduler-minikube 1/1 Running 8 (4d2h ago) 155d storage-provisioner 1/1 Running 17 (4d2h ago) 155d ``` *--selector* 标志指定 kubectl 操作的一组与标签匹配的资源,可以缩写为 *-l* (代表 labels)。 ```powershell PS C:\k8s> kubectl get pods -l app=demo NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-2vd66 1/1 Running 0 30h demo-5bf7bc95c7-c872k 1/1 Running 0 30h ``` **缩写资源的类型** 为了加快输入, *kubectl* 支持以下资源类型的缩写形式 - `kubectl get po` - `kubectl get deploy` - `kubectl get svc` - `kubectl get ns` ```powershell PS C:\k8s> kubectl get po NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-2vd66 1/1 Running 0 30h demo-5bf7bc95c7-c872k 1/1 Running 0 30h ``` ```powershell PS C:\k8s> kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE demo 2/2 2 2 30h ``` ```powershell PS C:\k8s> kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE demo-service ClusterIP 10.109.26.249 <none> 8888/TCP 30h kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 155d ``` ```powershell PS C:\k8s> kubectl get ns NAME STATUS AGE default Active 155d kube-node-lease Active 155d kube-public Active 155d kube-system Active 155d kubernetes-dashboard Active 155d ``` 还有一些缩写: - *no* 代表 *nodes* - *cm* 代表 *configmaps* - *sa* 代表 *serviceaccounts* - *ds* 代表 *daemonsets* - *pv* 代表 *persistentvolumes* **自动补全 *kubectl* 命令** ```powershell PS C:\k8s> kubectl completion -h Output shell completion code for the specified shell (bash or zsh). The shell code must be evaluated to provide interactive completion of kubectl commands. This can be done by sourcing it from the .bash_profile. Detailed instructions on how to do this are available here: for macOS: https://kubernetes.io/docs/tasks/tools/install-kubectl-macos/#enable-shell-autocompletion for linux: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#enable-shell-autocompletion for windows: https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/#enable-shell-autocompletion Note for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2. Examples: # Installing bash completion on macOS using homebrew ## If running Bash 3.2 included with macOS brew install bash-completion ## or, if running Bash 4.1+ brew install bash-completion@2 ## If kubectl is installed via homebrew, this should start working immediately ## If you've installed via other means, you may need add the completion to your completion directory kubectl completion bash > $(brew --prefix)/etc/bash_completion.d/kubectl # Installing bash completion on Linux ## If bash-completion is not installed on Linux, install the 'bash-completion' package ## via your distribution's package manager. ## Load the kubectl completion code for bash into the current shell source <(kubectl completion bash) ## Write bash completion code to a file and source it from .bash_profile kubectl completion bash > ~/.kube/completion.bash.inc printf " # Kubectl shell completion source '$HOME/.kube/completion.bash.inc' " >> $HOME/.bash_profile source $HOME/.bash_profile # Load the kubectl completion code for zsh[1] into the current shell source <(kubectl completion zsh) # Set the kubectl completion code for zsh[1] to autoload on startup kubectl completion zsh > "${fpath[1]}/_kubectl" Usage: kubectl completion SHELL [options] Use "kubectl options" for a list of global command-line options (applies to all commands). ``` > **JiaJia:** > > Windows 环境运行上面[官方文档](https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/#enable-shell-autocompletion "Enable shell autocompletion ")中的命令时报错了,不知道是哪里出了问题。 > > ```powershell > PS C:\k8s> kubectl completion powershell > error: Unsupported shell type "powershell". > See 'kubectl completion -h' for help and examples > ``` > > `kubectl completion bash` 这个倒是有,不确定是不是 *cmd* 命令用的。 > > 总的来说,自动补全这个功能没有操作成功。 **获取帮助** ```powershell kubectl -h ``` **获取有关 Kubernetes 资源的帮助** `kubectl explain 资源` 可以获取指定类型资源的文档,`kubectl explain 资源.字段` 可以获取有关资源特定字段的更多信息。 ```powershell kubectl explain deployment kubectl explain deployment.kind kubectl explain deployment.metadata.annotations ``` 递归获取资源所有字段: ```powershell kubectl explain deployment --recursive ``` **显示更详细的输出** 添加 `-o wide` 标志可以看到更多信息: ```powershell PS C:\k8s> kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-5bf7bc95c7-m8flw 1/1 Running 1 (2d19h ago) 2d21h 172.17.0.2 minikube <none> <none> demo-5bf7bc95c7-qzbw5 1/1 Running 1 (2d19h ago) 2d21h 172.17.0.5 minikube <none> <none> ``` **使用 JSON 数据和 jq** `kubectl get` 默认输出格式是纯文本的,可以通过 `-o json` 标志输出 JSON 格式的信息: ```powershell kubectl get pods -o json ``` *jq* 是一个轻量且灵活的命令行 JSON 处理器。 *macOs* 运行 `brew install jq` ; *Debian*、*Ubuntu* 运行 `apt install jq` 来安装 *jq* 工具。 > **JiaJia:** > > Windows 上安装 [jq](https://community.chocolatey.org/packages/jq#psdsc) 可以参考[这篇博客](https://blog.csdn.net/doulihang/article/details/106108965) > 1. 安装 *Chocolatey* > ```bash > @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" > ``` > 2. 安装 *jq* > ```bash > chocolatey install jq > ``` > > Windows 下执行效果如下: > > ```powershell > PS C:\k8s> kubectl get po -n kube-system -o json | jq '.items[].metadata.name' > "coredns-78fcd69978-2s4jv" > "etcd-minikube" > "kube-apiserver-minikube" > "kube-controller-manager-minikube" > "kube-proxy-zwsz8" > "kube-scheduler-minikube" > "storage-provisioner" > ``` **监视对象** 持续监视某个对象可以通过 *kubectl* 提供的 `--watch` 标志(缩写为 `-w`)。 ```powershell PS C:\k8s> kubectl get pods --watch NAME READY STATUS RESTARTS AGE demo-5bf7bc95c7-m8flw 1/1 Running 1 (2d19h ago) 2d21h demo-5bf7bc95c7-qzbw5 1/1 Running 1 (2d19h ago) 2d21h ``` 每当状态改变时,终端就会更新。 **描述对象** 使用 `kubectl describe` 可以获得对象的详细信息。 对容器进行故障排查时, *Events* 部分的信息非常有帮助,因为它记录了容器生命周期的各个阶段以及发生的错误。 ```powershell PS C:\k8s> kubectl describe po demo-5bf7bc95c7-2vd66 Name: demo-5bf7bc95c7-2vd66 Namespace: default Priority: 0 Node: minikube/192.168.49.2 Start Time: Mon, 09 May 2022 11:35:44 +0800 Labels: app=demo environment=development pod-template-hash=5bf7bc95c7 Annotations: <none> Status: Running IP: 172.17.0.5 IPs: IP: 172.17.0.5 Controlled By: ReplicaSet/demo-5bf7bc95c7 Containers: demo: Container ID: docker://442d2f150901c764ece88f9160a540c96b77b3e6d633a39aec9d31e8af681097 Image: cloudnatived/demo:hello Image ID: docker-pullable://cloudnatived/demo@sha256:bd04206ca8ab7025c465dc2b9d3282c2e0da216c71011d26d66ef51f5a5d3e34 Port: 8888/TCP Host Port: 0/TCP State: Running Started: Thu, 12 May 2022 14:12:08 +0800 Last State: Terminated Reason: Error Exit Code: 255 Started: Mon, 09 May 2022 11:35:45 +0800 Finished: Thu, 12 May 2022 14:11:38 +0800 Ready: True Restart Count: 1 Environment: environment: development Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7cn5k (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: kube-api-access-7cn5k: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SandboxChanged 6m3s kubelet Pod sandbox changed, it will be killed and re-created. Normal Pulled 6m1s kubelet Container image "cloudnatived/demo:hello" already present on machine Normal Created 6m kubelet Created container demo Normal Started 6m kubelet Started container demo ``` ## 7.2 处理资源 **命令式的 kubectl 命令** 创建、删除、修改命名空间: ```powershell PS C:\k8s> kubectl create namespace my-new-namespace namespace/my-new-namespace created PS C:\k8s> kubectl delete namespace my-new-namespace namespace "my-new-namespace" deleted PS C:\k8s> kubectl edit deployments demo deployment.apps/demo edited ``` `kubectl edit` 命令会用默认的编辑器打开代表指定资源的 YAML 清单文件,修改并保存后会自动应用所作改动。 **何时不应该使用命令式的命令** 在本书中,我们一直强调使用声明式基础设施即代码的重要性。因此,我们不建议你使用声明式的 *kubectl* 命令。 使用命令式命令的主要问题在于,这样做会导致你没有唯一的正确标准。 下次有人应用 YAML 清单后,之前做出的命令式修改都会被覆盖或丢失。 在重新应用清单文件之前,应该使用 `kubectl diff` 检查此次修改会引发哪些变化。 避免此类问题的最佳方法是,坚持使用版本控制来编辑和应用资源文件。 > **最佳实践** > 不要在生成环境中运行命令式的 *kubectl* 命令,例如 *create* 或 *edit* 等。 > 在管理资源时,请坚持使用版本控制的 YAML 清单,并通过 `kubectl apply` (或 `Helm chart`)来应用清单。 **生成资源清单** 可以使用 *kubectl* 生成一个 YAML 清单。这样可以省却在一个空文件中输入大量样板代码: ```powershell kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml ``` `--dry-run=client` 表示不会实际创建资源,只输出需要创建的资源。 `-o yaml` 表示输出 YAML 格式的资源清单。 ```powershell PS C:\k8s> kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: myhello name: myhello spec: replicas: 1 selector: matchLabels: app: myhello strategy: {} template: metadata: creationTimestamp: null labels: app: myhello spec: containers: - image: jiajiablog/myhello name: myhello resources: {} status: {} ``` 将资源清单直接保存到文件: ```powershell kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml > deployment.yaml ``` 应用保存的资源清单: ```powershell kubectl apply -f .\deployment.yaml ``` **导出资源** 只需在 `kubectl get` 的后面加上 `-o` 标志,就可以导出已有资源的清单文件: ```powershell kubectl get deployments myhello -o yaml > myhello.yaml ``` ```powershell PS C:\k8s> kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml > deployment.yaml PS C:\k8s> cat .\deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: myhello name: myhello spec: replicas: 1 selector: matchLabels: app: myhello strategy: {} template: metadata: creationTimestamp: null labels: app: myhello spec: containers: - image: jiajiablog/myhello name: myhello resources: {} status: {} PS C:\k8s> kubectl apply -f .\deployment.yaml deployment.apps/myhello created PS C:\k8s> kubectl get deployments myhello -o yaml > myhello.yaml PS C:\k8s> cat .\myhello.yaml apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"creationTimestamp":null,"labels":{"app":"myhello"},"name":"myhello","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"myhello"}},"strategy":{},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"myhello"}},"spec":{"containers":[{"image":"jiajiablog/myhello","name":"myhello","resources":{}}]}}},"status":{}} creationTimestamp: "2021-12-13T06:30:57Z" generation: 1 labels: app: myhello name: myhello namespace: default resourceVersion: "431030" uid: d2f41a65-8312-4bf0-b796-e4cb79abff20 spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: myhello strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: myhello spec: containers: - image: jiajiablog/myhello imagePullPolicy: Always name: myhello resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: availableReplicas: 1 conditions: - lastTransitionTime: "2021-12-13T06:31:02Z" lastUpdateTime: "2021-12-13T06:31:02Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available - lastTransitionTime: "2021-12-13T06:30:57Z" lastUpdateTime: "2021-12-13T06:31:02Z" message: ReplicaSet "myhello-7b7468bb7f" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 1 replicas: 1 updatedReplicas: 1 ``` 这个输出包含了一些额外的信息,比如 *status* 小结等,这些信息需要事先移除,才能与其它清单一起保存、更新,并通过 `kubectl apply -f` 应用。 **对比资源的差异** 在使用 `kubectl apply` 应用清单之前,最好弄清楚集群上即将发生的变化。使用 `kubectl diff` 命令可以完成该操作。 ```powershell kubectl diff -f .\deployment.yaml ``` > **JiaJia:** > > 初次运行时报了 *error: failed to run "diff": executable file not found in %PATH%* 错误。 > > ```powershell > PS C:\k8s> kubectl diff -f .\myhello.yaml > error: failed to run "diff": executable file not found in %PATH% > ``` > > 参考 [StackOverflow](https://stackoverflow.com/questions/58390269/kubectl-diff-on-windows-returns-an-error-executable-file-not-found-in-path/ "kubectl diff on windows returns an error: executable file not found in PATH") 上的回复,下载并安装 [GnuWin32](http://gnuwin32.sourceforge.net/packages/diffutils.htm) 之后,里面就自带了 *DiffUtils for Windows* 工具。 > > 安装完成后将安装目录下的 *bin* 目录(默认为 *C:\Program Files (x86)\GnuWin32\bin* )加入 *PATH* 环境变量,之后重新启动 *PowerShell* 就可以正常运行 `kubectl diff` 了(如不行,请重启电脑后再试下)。 > > 实际执行结果如下: > > ```powershell > PS C:\k8s> kubectl diff -f .\myhello.yaml > diff -u -N C:\Users\jiajia\AppData\Local\Temp\LIVE-2814301283/apps.v1.Deployment.default.myhello C:\Users\jiajia\AppData\Local\Temp\MERGED-3848057086/apps.v1.Deployment.default.myhello > --- C:\Users\jiajia\AppData\Local\Temp\LIVE-2814301283/apps.v1.Deployment.default.myhello 2022-05-12 15:00:52.067340800 +0800 > +++ C:\Users\jiajia\AppData\Local\Temp\MERGED-3848057086/apps.v1.Deployment.default.myhello 2022-05-12 15:00:52.067860300 +0800 > @@ -6,7 +6,7 @@ > kubectl.kubernetes.io/last-applied-configuration: | > {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app":"myhello"},"name":"myhello","namespace":"default"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"myhello"}},"template":{"metadata":{"labels":{"app":"myhello"}},"spec":{"containers":[{"image":"jiajiablog/myhello","name":"demo","ports":[{"containerPort":8888}]}]}}}} > creationTimestamp: "2022-05-12T06:35:41Z" > - generation: 1 > + generation: 2 > labels: > app: myhello > managedFields: > @@ -100,7 +100,7 @@ > uid: 524268a2-f01f-4545-8c21-9ef1831a4033 > spec: > progressDeadlineSeconds: 600 > - replicas: 2 > + replicas: 1 > revisionHistoryLimit: 10 > selector: > matchLabels: > ``` > 可以看到 *generation* 从 1 变成了 2 , *replicas* 从 2 变成了 1 。 --- > **最佳实践** > 在将任何更新应用到生产集群之前,请使用 *kubectl diff* 检查即将发生的变化。 ## 7.3 处理容器 **查看容器日志** 在 Kubernetes 中,日志包含容器写入到标准输出流和标准错误流的所有内容。 可以使用 `kubectl logs [Pod 名]` 来获取日志: ```powershell PS C:\k8s> kubectl logs -n kube-system --tail=20 coredns-78fcd69978-2s4jv [WARNING] plugin/kubernetes: starting server with unsynced Kubernetes API .:53 [INFO] plugin/reload: Running configuration MD5 = c23ed519c17e71ee396ed052e6209e94 CoreDNS-1.8.4 linux/amd64, go1.16.4, 053c4d5 [INFO] plugin/ready: Still waiting on: "kubernetes" [INFO] plugin/ready: Still waiting on: "kubernetes" ``` 使用 `--tail` 标志限制只输出最新的几行。 使用 `--follow` (缩写 `-f`) 可以持续看到容器日志: ```powershell kubectl logs -n kube-system --tail=2 --follow etcd-minikube ``` 如果 Pod 中有多个容器,可以使用标志 `--container` (缩写为 `-c`)指定查看哪个容器的日志。 ```powershell kubectl logs -n kube-system metrics-server -c metrics-server-nanny ``` **附着到容器** 附着到容器,可以直接查看容器的输出: ```powershell kubectl attach myhello ``` **利用 kubespy 监视 Kubernetes 资源** *kubespy* 可以监视集群内部的单个资源,并向你展示一段时间内的情况。 **转发容器端口** 使用 `kubectl port-forward` 将 Kubernetes 服务转发到本地计算机的端口上。 如果你想直接连接到特定 Pod,也可以使用这个命令转发容器端口。 ```powershell kubectl port-forward myhello-7b7468bb7f-5wcmr 9999:8888 ``` ```powershell PS C:\k8s> kubectl port-forward myhello-7b7468bb7f-5wcmr 9999:8888 Forwarding from 127.0.0.1:9999 -> 8888 Forwarding from [::1]:9999 -> 8888 Handling connection for 9999 Handling connection for 9999 ``` **在容器上执行命令** 在容器内运行一个 *shell* : ```powershell kubectl exec -it alpine -- /bin/sh ``` ```powershell PS C:\k8s> kubectl run alpine --image alpine --command -- sleep 999 pod/alpine created PS C:\k8s> kubectl get pods NAME READY STATUS RESTARTS AGE alpine 1/1 Running 0 29s PS C:\k8s> kubectl exec -it alpine -- /bin/sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / # ps PID USER TIME COMMAND 1 root 0:00 sleep 999 7 root 0:00 /bin/sh 14 root 0:00 ps / # ``` 如果 Pod 中有多个容器,默认将在第一个容器中运行命令。可以使用 `-c` 指定容器。 **容器的故障排除** 下面的示例展示了如何通过一次性的容器命令进行调试。 启动演示用实例: ```powershell kubectl run demo --image cloudnatived/demo:hello --expose --port 8888 ``` 容器内运行 *nslookup* 命令: ```powershell PS C:\k8s> kubectl run nslookup --image=busybox:1.28 --rm -it --restart=Never --command -- nslookup demo Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: demo Address 1: 10.99.227.156 demo.default.svc.cluster.local pod "nslookup" deleted ``` 从终端日志可以看出 DNS 是有效的。 通过 *wget* 命令发送 HTTP 请求: ```powershell PS C:\k8s> kubectl run wget --image=busybox:1.28 --rm -it --restart=Never --command -- wget -qO- http://demo:8888 Hello, 世界 pod "wget" deleted ``` 上面几个命令中用到的标志的含义: `--rm`:删除该命令为被附着的容器创建的资源 `-it`:以交互的方式(*i*)通过终端(*t*)运行容器 `--restart=Never`:在容器退出时,不要像常见容器那样重新启动 `--command --`:指定要运行的命令,用于取代容器的默认入口。`--` 之后的所有内容都将作为命令行的参数传递给容器。 **BusyBox 命令** *busybox* 非常方便,它包含许多最常用的 unix 命令。 完整的 *busybox* 命令请参考[官方网站](https://busybox.net/downloads/BusyBox.html)。 ```powershell kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never /bin/sh ``` 创建 Busybox Shell 的别名: ```bash alias bb=kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never --command -- ``` > **JiaJia:** > > 在 Windows 的 PowerShell 中设置别名比较麻烦,而且貌似不支持不定长的参数数组,必须要提前定义好函数的参数个数。 > > 这里先定义了支持最多3个参数的函数 `busyboxCommand` 并设置了别名 *bb* 。 > > ```powershell > function busyboxCommand([string] $arg1, [string] $arg2, [string] $arg3) {kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never --command -- $arg1 $arg2 $arg3} > Set-Alias bb busyboxCommand > ``` > > 尝试了书中的三个调用,其中第 3 个 *wget* 命令的 `-qO-` 参数没有被正确接收(猜测是因为前面有个负号,被识别成了数值型),需要添加双引号,改成 `"-qO-"` 的形式才可以正常执行。 > > 1. `bb nslookup demo` > 1. `bb sh` > 1. `bb wget -qO- http://demo:8888` > 1. `bb wget "-qO-" http://demo:8888` > > 实际的执行效果如下: > > ```powershell > PS C:\k8s> function busyboxCommand([string] $arg1, [string] $arg2, [string] $arg3) {kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never --command -- $arg1 $arg2 $arg3} > PS C:\k8s> Set-Alias bb busyboxCommand > ``` > > ```powershell > PS C:\k8s> bb nslookup demo > Server: 10.96.0.10 > Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local > > Name: demo > Address 1: 10.102.139.230 demo.default.svc.cluster.local > pod "busybox" deleted > ``` > > ```powershell > PS C:\k8s> bb sh > If you don't see a command prompt, try pressing enter. > / # exit > pod "busybox" deleted > ``` > > 这里 *wget* 命令没有接收到正确的参数,报错了。 > > ```powershell > PS C:\k8s> bb wget -qO- http://demo:8888 > BusyBox v1.28.4 (2018-05-22 17:00:17 UTC) multi-call binary. > > Usage: wget [-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE] > [--header 'header: value'] [-Y|--proxy on/off] [-P DIR] > [-S|--server-response] [-U|--user-agent AGENT] [-T SEC] URL... > > Retrieve files via HTTP or FTP > > --spider Only check URL existence: $? is 0 if exists > -c Continue retrieval of aborted transfer > -q Quiet > -P DIR Save to DIR (default .) > -S Show server response > -T SEC Network read timeout is SEC seconds > -O FILE Save to FILE ('-' for stdout) > -U STR Use STR for User-Agent header > -Y on/off Use proxy > pod "busybox" deleted > pod default/busybox terminated (Error) > ``` > > 参数加上双引号就可以正确运行了。 > > ```powershell > PS C:\k8s> bb wget "-qO-" http://demo:8888 > Hello, 世界 > pod "busybox" deleted > ``` **将 BusyBox 添加到容器** 如果你的容器内已有一个 shell ,则可以通过运行以下命令来访问容器: ```powershell kubectl exec -it Pod名 /bin.sh ``` 如果容器中没有 */bin/sh* 时,可以使用 *dcokerfile* 的 `COPY --from` 命令,将文件从之前构建的容器赋值到新容器中。 该命令可以从任何公开的镜像复制文件。 在之前的 demo 项目的 *Dockerfile* 中添加 `COPY --from=busybox:1.28 /bin/busybox /bin/busybox` 。 ```dockerfile FROM golang:1.17-alpine AS build WORKDIR /src/ COPY main.go go.* /src/ RUN CGO_ENABLED=0 go build -o /bin/demo FROM scratch COPY --from=build /bin/demo /bin/demo COPY --from=busybox:1.28 /bin/busybox /bin/busybox ENTRYPOINT ["/bin/demo"] ``` 构建镜像时通过 `-t myhello:busybox` 标志指定标签。 ```powershell docker image build -t myhello:busybox . ``` 通过 `docker images` 命令查看镜像大小,相比之前仅多了 *1.05MB* 。 ```powershell PS C:\projects\github\cloudnativedevops\demo\hello> docker images REPOSITORY TAG IMAGE ID CREATED SIZE myhello busybox 34ee40473cc9 2 minutes ago 7.13MB jiajiablog/myhello latest 1ddc99cfc6c7 4 days ago 6.07MB myhello latest 1ddc99cfc6c7 4 days ago 6.07MB ``` 通过如下命令启动一个 Shell (书中没加 `--command` 执行的效果有点区别): ```powershell kubectl run myhello-busybox --image=jiajiablog/myhello:busybox --rm -it --restart=Never --command /bin/busybox sh ``` **在容器上安装程序** 可以在运行镜像后安装任何你需要的程序: ```powershell PS C:\k8s> kubectl run alpine --image alpine --rm -it --restart=Never /bin/sh If you don't see a command prompt, try pressing enter. / # apk --update add emacs ``` **通过 *kubesquash* 实时调试** 项目已更名为 [Squash](https://github.com/solo-io/squash) 。 从 https://github.com/solo-io/squash/releases 下载的 *v0.5.18* 版,根据 [Quick Start](https://squash.solo.io/overview/) 安装 VS Code *Squash* 插件,但最终尝试 debug 时报错。 > creating base DebugAttachment resource client: failed to register crd: the server could not find the requested resource > time="2021-12-14T11:25:03+08:00" level=info msg="soloio/example-service2-java:v0.2.2" > Error: creating base DebugAttachment resource client: failed to register crd: the server could not find the requested resource 查看了,Pod *example-service2-java* 中也报错了,应该是服务启动就失败了。 > SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". > SLF4J: Defaulting to no-operation (NOP) logger implementation > SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. > **Failed to load class org.slf4j.impl.StaticLoggerBinder** > > This warning message is reported when the org.slf4j.impl.StaticLoggerBinder class could not be loaded into memory. This happens when no appropriate SLF4J binding could be found on the class path. Placing one (and only one) of slf4j-nop.jar slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar on the class path should solve the problem. > > Note that slf4j-api versions 2.0.x and later use the ServiceLoader mechanism. Backends such as logback 1.3 and later which target slf4j-api 2.x, do not ship with org.slf4j.impl.StaticLoggerBinder. If you place a logging backend which targets slf4j-api 2.0.x, you need slf4j-api-2.x.jar on the classpath. See also relevant faq entry. > > SINCE 1.6.0 As of SLF4J version 1.6, in the absence of a binding, SLF4J will default to a no-operation (NOP) logger implementation. > > If you are responsible for packaging an application and do not care about logging, then placing slf4j-nop.jar on the class path of your application will get rid of this warning message. Note that embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose. 这个项目貌似2年未更新了,空了再继续尝试下吧。 ## 7.4 上下文和命名空间 集群、用户以及命名空间组合在一起构成了上下文。 `kubectl` 命令总是在当前上下文中执行。 **查看所有上下文** ```powershell kubectl config get-contexts ``` ```powershell PS C:\k8s> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop * minikube minikube minikube default ``` **切换上下文** ```powershell kubectl config use-context docker-desktop ``` ```powershell PS C:\k8s> kubectl config use-context docker-desktop Switched to context "docker-desktop". PS C:\k8s> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * docker-desktop docker-desktop docker-desktop minikube minikube minikube default ``` **查看集群信息** ```powershell kubectl cluster-info ``` ```powershell PS C:\k8s> kubectl cluster-info Kubernetes control plane is running at https://127.0.0.1:5609 CoreDNS is running at https://127.0.0.1:5609/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ``` ```HTTP GET https://127.0.0.1:5609/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "services \"kube-dns:dns\" is forbidden: User \"system:anonymous\" cannot get resource \"services/proxy\" in API group \"\" in the namespace \"kube-system\"", "reason": "Forbidden", "details": { "name": "kube-dns:dns", "kind": "services" }, "code": 403 } ``` 可以把上下文视为书签:帮助你快速切换到特定的集群和命名空间。 **创建新的上下文** ```powershell kubectl config set-context myapp --cluster=minikube --namespace=demo ``` ```powershell PS C:\k8s> kubectl config set-context myapp --cluster=minikube --namespace=demo Context "myapp" created. PS C:\k8s> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop * minikube minikube minikube default myapp minikube demo PS C:\k8s> kubectl config use-context myapp Switched to context "myapp". PS C:\k8s> kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop minikube minikube minikube default * myapp minikube demo ``` **获取当前上下文** ```powershell kubectl config current-context ``` ```powershell PS C:\k8s> kubectl config current-context myapp ``` ***kubectx* 和 *kubens*** 这个工具主要用来简化命令的输入,不过没看到 *Windows* 下安装脚本,就没有实际运行。 详细用户见官方仓库:[GitHub - ahmetb_kubectx_ Faster way to switch between clusters and namespaces in kubectl](https://github.com/ahmetb/kubectx) ***kube-ps1*** 将当前上下文添加到命令行提示符。 貌似也只支持 *Linux* 。 官方仓库:[GitHub - jonmosco_kube-ps1_ Kubernetes prompt info for bash and zsh](https://github.com/jonmosco/kube-ps1) ## 7.5 Kubernetes shell 与工具 1. *kube-shell* 输入命令的时候会弹出候选列表。 1. *Click* 提供了更复杂的K8S终端体验。 1. *Kubed-sh* 拉取并运行必要的程序,以方便在当前集群上执行 JavaScript、Ruby 或 Python 程序。 1. *Stern* 更高级的日志输出工具。 ## 7.6 构建自己的 Kubernetes 工具 通过 *kubectl* 搭建 *jq* 等查询工具以及标准的 UNIX 实用工具集(*cut*、*grep*、*xargs* 和 *friends*),就可以编写出操作 Kubernetes 资源的高级脚本。 如果你想编写真正的系统程序,自动化生产工作流程,作者强烈建议使用 Go 语言。 *client-go* 库可以完整的访问所有 Kubernetes API。 ## 7.7 小结 Kubernetes 的工具层出不穷,令人眼花缭乱。 事实上,大多数工具都不是必需的。 Kubernetes 本身可以通过 *kubectl* 完成大多数的工作,而其余的工具只是为了让工作更有趣、更方便。 没有人无所不知,但是每个人都有自己的积累。 - *kubectl* 本身包含完整详尽的文档,你可以通过 `kubectl -h` 查看文档,还可以使用 `kubectl explain` 查询每个 Kubernetes 资源、字段或功能的文档。。如果你想针对 *kubectl* 的输出进行复杂的过滤和转换,例如在脚本中,请使用 `-o json` 选择 JSON 格式。在拿到 JSON 数据后,可以使用 *jq* 等强大的工具进行查询。 - 同时使用 *kubectl* 的选项 `--dry-run=client` 以及 `-o YAML` 就可以获得 YAML 格式的输出,你可以通过这个命令式的命令生成 Kubernetes 清单。在为新应用程序创建清单文件时,这种方式可以节省大量时间。 - 你也可以将现有资源转换为 YAML 清单,只需在 `kubectl get` 中加入 `-o` 标志。 - `kubectl diff` 会告诉你,如果应用清单会发生哪些改变,但该命令本身不会更改任何内容。 - 你可以使用 `kubectl logs` 查看容器的输出和错误消息,使用 `--follow` 标志可以连续传输日志输出流,还可以使用 *Stern* 查看多个 Pod 的日志。 - 为了针对有问题的容器进行故障排除,你可以通过 `kubectl attach` 附着到容器上,或者通过 `exec -it … /bin/sh` 在容器上启动一个 shell 。 - 你可以使用 `kubectl run` 来运行任何公共容器镜像,包括用途广泛的 *BusyBox* 工具(BusyBox 中包含所有常用的 Unix 命令)。 - Kubernetes 的上下文就像书签一样,标记你在特定集群和命名空间中的位置。你可以使用 *kubectx* 和 *kubens* 工具切换上下文和命名空间。 - *Click* 是一款强大的 Kubernetes shell ,不仅可以提供 *kubectl* 的所有功能,而且还可以保持状态,也就是说它可以将当前选定的对象带到下一个命令因此你不必每次都指定操作对象。 - Kubernetes 旨在通过代码实现自动化和控制。当你需要某个 *kubectl* 没有提供的功能时,你可以通过 Kubernetes *client-go* 库,用 Go 代码全权控制集群的各个方面。 Loading... 版权声明:本文为博主「佳佳」的原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://www.liujiajia.me/2022/5/14/cloud-native-devops-with-kubernetes-ch-07 提交