基于 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 如果设置别名可以参考这篇博客 。
PS C:\k8s> $profile
C:\Users\jiajia\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
在 Microsoft.PowerShell_profile.ps1 文件中添加设置别名的脚本,之后每次启动 PowerShell 就可以直接使用别名了。
$profile 示例:
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 就可以运行脚本了)。
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
使用示例:
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 文件中设置别名:
alias k=kubectl
使用缩写的标志
kubectl 的许多标志和开关都支持缩写形式。
如 --namespace 可以缩写为 -n 。
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)。
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
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
PS C:\k8s> kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
demo 2/2 2 2 30h
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
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 命令
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 环境运行上面官方文档中的命令时报错了,不知道是哪里出了问题。
powershellPS C:\k8s> kubectl completion powershell error: Unsupported shell type "powershell". See 'kubectl completion -h' for help and examples
kubectl completion bash
这个倒是有,不确定是不是 cmd 命令用的。总的来说,自动补全这个功能没有操作成功。
获取帮助
kubectl -h
获取有关 Kubernetes 资源的帮助
kubectl explain 资源
可以获取指定类型资源的文档,kubectl explain 资源.字段
可以获取有关资源特定字段的更多信息。
kubectl explain deployment
kubectl explain deployment.kind
kubectl explain deployment.metadata.annotations
递归获取资源所有字段:
kubectl explain deployment --recursive
显示更详细的输出
添加 -o wide
标志可以看到更多信息:
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 格式的信息:
kubectl get pods -o json
jq 是一个轻量且灵活的命令行 JSON 处理器。
macOs 运行 brew install jq
; Debian、Ubuntu 运行 apt install jq
来安装 jq 工具。
JiaJia:
- 安装 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"
- 安装 jq
bashchocolatey install jq
Windows 下执行效果如下:
powershellPS 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
)。
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 部分的信息非常有帮助,因为它记录了容器生命周期的各个阶段以及发生的错误。
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 命令
创建、删除、修改命名空间:
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 清单。这样可以省却在一个空文件中输入大量样板代码:
kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml
--dry-run=client
表示不会实际创建资源,只输出需要创建的资源。-o yaml
表示输出 YAML 格式的资源清单。
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: {}
将资源清单直接保存到文件:
kubectl create deployment myhello --image=jiajiablog/myhello --dry-run=client -o yaml > deployment.yaml
应用保存的资源清单:
kubectl apply -f .\deployment.yaml
导出资源
只需在 kubectl get
的后面加上 -o
标志,就可以导出已有资源的清单文件:
kubectl get deployments myhello -o yaml > myhello.yaml
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
命令可以完成该操作。
kubectl diff -f .\deployment.yaml
JiaJia:
初次运行时报了 error: failed to run "diff": executable file not found in %PATH% 错误。
powershellPS 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
了(如不行,请重启电脑后再试下)。实际执行结果如下:
powershellPS 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 名]
来获取日志:
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
)可以持续看到容器日志:
kubectl logs -n kube-system --tail=2 --follow etcd-minikube
如果 Pod 中有多个容器,可以使用标志 --container
(缩写为 -c
)指定查看哪个容器的日志。
kubectl logs -n kube-system metrics-server -c metrics-server-nanny
附着到容器
附着到容器,可以直接查看容器的输出:
kubectl attach myhello
利用 kubespy 监视 Kubernetes 资源
kubespy 可以监视集群内部的单个资源,并向你展示一段时间内的情况。
转发容器端口
使用 kubectl port-forward
将 Kubernetes 服务转发到本地计算机的端口上。
如果你想直接连接到特定 Pod,也可以使用这个命令转发容器端口。
kubectl port-forward myhello-7b7468bb7f-5wcmr 9999:8888
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 :
kubectl exec -it alpine -- /bin/sh
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
指定容器。
容器的故障排除
下面的示例展示了如何通过一次性的容器命令进行调试。
启动演示用实例:
kubectl run demo --image cloudnatived/demo:hello --expose --port 8888
容器内运行 nslookup 命令:
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 请求:
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 命令请参考官方网站。
kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never /bin/sh
创建 Busybox Shell 的别名:
alias bb=kubectl run busybox --image=busybox:1.28 --rm -it --restart=Never --command --
JiaJia:
在 Windows 的 PowerShell 中设置别名比较麻烦,而且貌似不支持不定长的参数数组,必须要提前定义好函数的参数个数。
这里先定义了支持最多 3 个参数的函数
busyboxCommand
并设置了别名 bb 。powershellfunction 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-"
的形式才可以正常执行。
bb nslookup demo
bb sh
bb wget -qO- http://demo:8888
bb wget "-qO-" http://demo:8888
实际的执行效果如下:
powershellPS 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
powershellPS 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
powershellPS C:\k8s> bb sh If you don't see a command prompt, try pressing enter. / # exit pod "busybox" deleted
这里 wget 命令没有接收到正确的参数,报错了。
powershellPS 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)
参数加上双引号就可以正确运行了。
powershellPS C:\k8s> bb wget "-qO-" http://demo:8888 Hello, 世界 pod "busybox" deleted
将 BusyBox 添加到容器
如果你的容器内已有一个 shell,则可以通过运行以下命令来访问容器:
kubectl exec -it Pod名 /bin.sh
如果容器中没有 /bin/sh 时,可以使用 dcokerfile 的 COPY --from
命令,将文件从之前构建的容器赋值到新容器中。
该命令可以从任何公开的镜像复制文件。
在之前的 demo 项目的 Dockerfile 中添加 COPY --from=busybox:1.28 /bin/busybox /bin/busybox
。
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
标志指定标签。
docker image build -t myhello:busybox .
通过 docker images
命令查看镜像大小,相比之前仅多了 1.05MB 。
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
执行的效果有点区别):
kubectl run myhello-busybox --image=jiajiablog/myhello:busybox --rm -it --restart=Never --command /bin/busybox sh
在容器上安装程序
可以在运行镜像后安装任何你需要的程序:
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
命令总是在当前上下文中执行。
查看所有上下文
kubectl config get-contexts
PS C:\k8s> kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
docker-desktop docker-desktop docker-desktop
* minikube minikube minikube default
切换上下文
kubectl config use-context docker-desktop
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
查看集群信息
kubectl cluster-info
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'.
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
}
可以把上下文视为书签:帮助你快速切换到特定的集群和命名空间。
创建新的上下文
kubectl config set-context myapp --cluster=minikube --namespace=demo
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
获取当前上下文
kubectl config current-context
PS C:\k8s> kubectl config current-context
myapp
kubectx 和 kubens
这个工具主要用来简化命令的输入,不过没看到 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 与工具
- kube-shell
输入命令的时候会弹出候选列表。 - Click
提供了更复杂的 K8S 终端体验。 - Kubed-sh
拉取并运行必要的程序,以方便在当前集群上执行 JavaScript、Ruby 或 Python 程序。 - 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 代码全权控制集群的各个方面。