k8s常见管理


一、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 中的 imagePullPolicyAlways
  • 省略 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/ 开头的标签。如需要使用该标签前缀作为节点隔离的目的,需要:

例如: 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被调度到特定的节点上。

主要有以下几个优点:

  1. 语法更具表现力(不仅仅支持“与(AND)"完全匹配)
  2. 可以指明规则是“soft/preference”而不是强制要求,所以如果不满足调度条件,pods依然可以被调度。
  3. 可以将规则限制在运行在一个节点上的pods(或其他拓扑域),而不仅仅是节点本身,这将允许pods是否可以调度到同一个节点。

目前支持两种类型的node affinity,

requiredDuringSchedulingIgnoredDuringExecution (强制)
preferredDuringSchedulingIgnoredDuringExecution (非强制)

某种意义上,前者指定了要将pod调度到节点上必须满足的规则(像nodeSelector,但使用了更具表现力的语法),而后者试图调度到特定的节点但不能保证一定会调度到该节点。

其中,“IgnoredDuringExecution”表示如果在pod运行时节点的标签发生改变导致无法满足pods创建时使用的调度规则,pod会继续在该节点上运行,这点与nodeSelector相似。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM