Skip to content

基于 Kubernetes 的云原生 DevOps 第 7 章 强大的 Kubernetes 工具

🏷️ Kubernetes 《基于 Kubernetes 的云原生 DevOps》


My mechanic told me, "I couldn't repair your brakes, so I made your horn louder."

-- Steven Wright


7.1 掌握 Kubectl

Shell 别名

关于 PowerShell 如果设置别名可以参考这篇博客

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,执行如下命令修改 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 的博客

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 环境运行上面官方文档中的命令时报错了,不知道是哪里出了问题。

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 ; DebianUbuntu 运行 apt install jq 来安装 jq 工具。

JiaJia:

Windows 上安装 jq 可以参考这篇博客

  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 命令,例如 createedit 等。
在管理资源时,请坚持使用版本控制的 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 上的回复,下载并安装 GnuWin32 之后,里面就自带了 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 命令请参考官方网站

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
  2. bb sh
  3. bb wget -qO- http://demo:8888
  4. 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 时,可以使用 dcokerfileCOPY --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/releases 下载的 v0.5.18 版,根据 Quick Start 安装 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

kubectxkubens

这个工具主要用来简化命令的输入,不过没看到 Windows 下安装脚本,就没有实际运行。
详细用户见官方仓库:GitHub - ahmetb_kubectx_ Faster way to switch between clusters and namespaces in kubectl

kube-ps1

将当前上下文添加到命令行提示符。
貌似也只支持 Linux
官方仓库:GitHub - jonmosco_kube-ps1_ Kubernetes prompt info for bash and zsh

7.5 Kubernetes shell 与工具

  1. kube-shell
    输入命令的时候会弹出候选列表。
  2. Click
    提供了更复杂的 K8S 终端体验。
  3. Kubed-sh
    拉取并运行必要的程序,以方便在当前集群上执行 JavaScript、Ruby 或 Python 程序。
  4. Stern
    更高级的日志输出工具。

7.6 构建自己的 Kubernetes 工具

通过 kubectl 搭建 jq 等查询工具以及标准的 UNIX 实用工具集(cutgrepxargsfriends),就可以编写出操作 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 的上下文就像书签一样,标记你在特定集群和命名空间中的位置。你可以使用 kubectxkubens 工具切换上下文和命名空间。
  • Click 是一款强大的 Kubernetes shell,不仅可以提供 kubectl 的所有功能,而且还可以保持状态,也就是说它可以将当前选定的对象带到下一个命令因此你不必每次都指定操作对象。
  • Kubernetes 旨在通过代码实现自动化和控制。当你需要某个 kubectl 没有提供的功能时,你可以通过 Kubernetes client-go 库,用 Go 代码全权控制集群的各个方面。