一、kubectl 命令补全
安装bash自动补全工具
yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
bash 终端
source <(kubectl completion bash) # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completion 包。
echo "source <(kubectl completion bash)" >> ~/.bashrc # 在您的 bash shell 中永久的添加自动补全
zsh 终端
source <(kubectl completion zsh) # setup autocomplete in zsh into the current shell
echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc # add autocomplete permanently to your zsh shell
设置别名,减短命令
vim ~/.bashrc
# 添加下面两行
alias k=kubectl
complete -F __start_kubectl k
二、更新镜像
Kubernetes中,默认的镜像抓取策略是 IfNotPresent
,使用此策略,kubelet在发现本机有镜像的情况下,不会向镜像仓库抓取镜像。如果您期望每次启动 Pod 时,都强制从镜像仓库抓取镜像,可以尝试如下方式:
- 设置 container 中的
imagePullPolicy
为Always
- 省略
imagePullPolicy
字段,并使用:latest
tag 的镜像 - 省略
imagePullPolicy
字段和镜像的 tag - 激活
AlwaysPullImages
管理控制器
imagePullPolicy
字段和 image tag
的可能取值将影响到 kubelet 如何抓取镜像:
imagePullPolicy:
IfNotPresent 仅在节点上没有该镜像时,从镜像仓库抓取imagePullPolicy:
Always 每次启动 Pod 时,从镜像仓库抓取imagePullPolicy
未填写,镜像 tag 为:latest
或者未填写,则同Always
每次启动 Pod 时,从镜像仓库抓取imagePullPolicy
未填写,镜像 tag 已填写但不是:latest
,则同IfNotPresent
仅在节点上没有该镜像时,从镜像仓库抓取imagePullPolicy:
Never,Kubernetes 假设本地存在该镜像,并且不会尝试从镜像仓库抓取镜像
重要
在生产环境部署时,您应该避免使用 :latest tag,如果这样做,您将无法追踪当前正在使用的镜像版本,也无法正确地执行回滚动作 |
---|
如果要 100% 确保所有的容器都使用了同样的镜像版本,可以尝试使用镜像的 digest,例如 sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2。 Digest 唯一地标识了容器镜像的版本,并且永远不会改变。 |
容器引擎的镜像缓存机制使得 imagePullPolicy: Always 仍然是高效的。在 Docker 中,如果镜像已经存在,抓取尝试非常快速,先检查镜像所有的 layer 是否有更新,如果该镜像在镜像仓库中所有 layer 的 digest 与本地所有 layer 的 digest 相同,则不会再下载镜像。 |
三、管理容器的计算资源
您可以为 Pod 中的每一个容器指定其所需要的内存(RAM)大小和 CPU 数量。如果这些信息被指定了,Kubernetes 调度器可以更好的决定将 Pod 调度到哪一个节点。对于容器来说,其所需要的资源也将依据其指定的数值得到保证
1、CPU 的计量
在 Kubernetes 中,1 个 CPU 代表:
- 1 AWS vCPU
- 1 GCP Core
- 1 Azure vCore
- 1 IBM vCPU
- 物理机上 Intel 超线程 CPU 的 1 个超线程(Hyperthread)
Kubernetes 中,0.5 代表请求半个 CPU 资源。表达式 0.1 等价于 表达式 100m,在 API Server 中,表达式 0.1 将被转换成 100m,精度低于 1m 的请求是不受支持的。 CPU 的计量代表的是绝对值,而非相对值,例如,您请求了 0.1 个 CPU,无论您的节点是 单核、双核、48核,您得到的 CPU 资源都是 0.1 核。
2、内存的计量
内存的计量单位是 byte 字节。您可以使用一个整数来表达内存的大小,也可以使用后缀来表示(E、P、T、G、M、K)。您也可以使用 2 的幂数来表示内存大小,其后缀为(Ei、Pi、Ti、Gi、Mi、Ki)。例如,下面的几个表达方式所表示的内存大小大致相等:
128974848, 129e6, 129M, 123Mi
Kubernetes 中,可以为容器指定计算资源的请求数量 request
和限制数量 limit
。尽管资源的请求/限制数量只能在容器上指定,我们仍然经常讨论容器组的资源请求/限制数量。容器组对某一个类型的资源请求/限制数量是该容器组中所有工作容器对该资源请求/限制数量的求和。
3、带有资源请求的容器组是如何调度的
调度程序将确保:对于每一种资源类型,已调度的 Pod 对该资源的请求之和小于该节点最大可供使用资源数量。
如果资源请求之和大于Node节点资源,则调度程序不会将该 Pod 分配到该节点。Kubernetes 这样做可以避免在日常的流量高峰时段,节点上出现资源短缺的情况。
4、带有资源限制的容器组是如何运行的
Kubelet 启动容器组的容器时,将 CPU、内存的最大使用限制作为参数传递给容器引擎。
以 Docker 容器引擎为例:
- 容器的 cpu 请求将转换成 docker 要求的格式,并以
--cpu-shares
标志传递到docker run
命令 - 容器的 cpu 限制将也将转换成 millicore 表达式并乘以 100。结果数字是每 100ms 的周期内,该容器可以使用的 CPU 份额
- 容器的内存限制将转换成一个整数,并使用
--memory
标志传递到docker run
命令
如下情况可能会发生:
- 如果某个容器超出了其内存限制,它可能将被终止。如果 restartPolicy 为 Always 或 OnFailure,kubelet 将重启该容器
- 如果某个容器超出了其内存申请(仍低于其内存限制),当节点超出内存使用时,该容器仍然存在从节点驱逐的可能性
- 短时间内容器有可能能够超出其 CPU 使用限制运行。kubernetes 并不会终止这些超出 CPU 使用限制的容器
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
排查问题
容器可能因为资源不足而被终止。要检查容器是否由于达到资源限制而被杀死,请在有问题的Pod上调用kubectl describe pod PodName
kubectl describe pod simmemleak-hra99
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
...
Containers:
simmemleak:
Image: saadali/simmemleak
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2015 12:54:41 -0700
Last Termination State: Terminated
Exit Code: 1
Started: Fri, 07 Jul 2015 12:54:30 -0700
Finished: Fri, 07 Jul 2015 12:54:33 -0700
Ready: False
Restart Count: 5
...
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
主要观察
Last Termination State: Terminated
Restart Count: 5
可以通过 kubectl get pod
加上 -o go-template=...
选项来以取先前pod终止的状态
kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-hra99
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
你可以看到 reason:OOM Killed
, 因为超过内存限制所以被 OOM
四、将pod调度到指定node节点
您可以限定 Pod 只能在特定的节点上运行,或者优先选择在特定的节点上运行。
- 确保某些 Pod 被分配到具有固态硬盘的节点
- 将相互通信频繁的两个 Pod 分配到同一个高可用区的节点
Kubernetes 一共提供了四种方法,可以将 Pod 调度到指定的节点上,这些方法从简便到复杂的顺序如下:
- 指定节点 nodeName
- 节点选择器 nodeSelector Kubernetes 推荐用法
- Node isolation/restriction
- Affinity and anti-affinity
1、指定节点 nodeName
nodeName 是四种方法中最简单的一个,但是因为它的局限性,也是使用最少的。nodeName 是 Pod Spec 当中的一个字段。如果该字段非空,调度程序直接将其指派到 nodeName 对应的节点上运行。
通过 nodeName 限定 Pod 所运行的节点有如下局限性:
- 如果 nodeName 对应的节点不存在,Pod 将不能运行
- 如果 nodeName 对应的节点没有足够的资源,Pod 将运行失败,可能的原因有:OutOfmemory /OutOfcpu
- 集群中的 nodeName 通常是变化的(新的集群中可能没有该 nodeName 的节点,指定的 nodeName 的节点可能从集群中移除)
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 1
template:
metadata:
labels:
app: tomcat-app
spec:
nodeName: k8s.node1 # 指定调度节点为k8s.node1
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
2、节点选择器 nodeSelector
nodeSelector 是 PodSpec 中的一个字段。指定了一组名值对。节点的 labels 中必须包含 Pod 的 nodeSelector 中所有的名值对,该节点才可以运行此 Pod。最普遍的用法中, nodeSelector 只包含一个键值对。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 1
template:
metadata:
labels:
app: tomcat-app
spec:
nodeSelector:
cloudnil.com/role: dev #指定调度节点为带有label标记为:cloudnil.com/role=dev的node节点
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
3、Node isolation/restriction (限制/隔离)
向节点对象添加标签后,可以将 Pod 指定到特定(一个或一组)的节点,以便确保某些 Pod 只在具备某些隔离性、安全性或符合管理规定的节点上运行
如果将标签用于这个目的,推荐选择那些不会被 kubelet 修改的标签。这样做可以避免节点非法使用其 kubelet credential 来设置节点自己的标签,进一步影响到调度器将工作负载调度到该节点上。
NodeRestriction
管理插件可以阻止 kubelet 设置或者修改节点上以 node-restriction.kubernetes.io/
开头的标签。如需要使用该标签前缀作为节点隔离的目的,需要:
-
确保 kubenetes 已经启用了 Node authorizer 和 NodeRestriction admission plugin
-
添加带
node-restriction.kubernetes.io/
前缀的标签到节点对象,并将这些标签作为 Pod 中的节点选择器。
例如:
example.com.node-restriction.kubernetes.io/fips=true
或者example.com.node-restriction.kubernetes.io/pci-dss=true
4、Affinity and anti-affinity (亲和性和反亲和性)
Node affinity概念上与nodeSelector相似,通过选择标签的方式,可以限制pod被调度到特定的节点上。
主要有以下几个优点:
- 语法更具表现力(不仅仅支持“与(AND)"完全匹配)
- 可以指明规则是“soft/preference”而不是强制要求,所以如果不满足调度条件,pods依然可以被调度。
- 可以将规则限制在运行在一个节点上的pods(或其他拓扑域),而不仅仅是节点本身,这将允许pods是否可以调度到同一个节点。
目前支持两种类型的node affinity,
requiredDuringSchedulingIgnoredDuringExecution (强制)
preferredDuringSchedulingIgnoredDuringExecution (非强制)
某种意义上,前者指定了要将pod调度到节点上必须满足的规则(像nodeSelector,但使用了更具表现力的语法),而后者试图调度到特定的节点但不能保证一定会调度到该节点。
其中,“IgnoredDuringExecution”表示如果在pod运行时节点的标签发生改变导致无法满足pods创建时使用的调度规则,pod会继续在该节点上运行,这点与nodeSelector相似。