Niujie 2020-09-29T19:35:46+08:00 neujie@126.com 使用amWiki搭建自己的博客和生活记录 2020-09-26T00:00:00+08:00 Niujie https://www.neujie.cn//2020/09/build-wiki-and-life-with-amwiki 博客停更了很久,源自两点:

  1. 自己电脑送给小朋友了;
  2. 没有时间用自己的电脑。

为了防止自己懒惰下来,特使用amWiki系统搭建新的记录“遇见”系列。

  1. 特申请cq2050.com用以思考2050年的自己;
  2. 想象百年中华后的自己、家人、家乡、祖国的样子;

博客记录:

]]>
配置K8S集群中的DNS 2019-03-16T00:00:00+08:00 Niujie https://www.neujie.cn//2019/03/configuring-k8s-dns FWD: https://jimmysong.io/posts/configuring-kubernetes-kube-dns/

kube-dns 介绍

从 Kubernetes v1.3 版本开始,使用 [cluster add-on 插件管理器回自动启动内置的 DNS。

Kubernetes DNS pod 中包括 3 个容器:

  • kubedns:kubedns 进程监视 Kubernetes master 中的 Service 和 Endpoint 的变化,并维护内存查找结构来服务DNS请求。
  • dnsmasq:dnsmasq 容器添加 DNS 缓存以提高性能。
  • sidecar:sidecar 容器在执行双重健康检查(针对 dnsmasq 和 kubedns)时提供单个健康检查端点(监听在10054端口)。

DNS pod 具有静态 IP 并作为 Kubernetes 服务暴露出来。该静态 IP 分配后,kubelet 会将使用 –cluster-dns = 标志配置的 DNS 传递给每个容器。

DNS 名称也需要域名。本地域可以使用标志 –cluster-domain = 在 kubelet 中配置。

Kubernetes集群DNS服务器基于 SkyDNS 库。它支持正向查找(A 记录),服务查找(SRV 记录)和反向 IP 地址查找(PTR 记录)

kube-dns 支持的 DNS 格式

kube-dns 将分别为 service 和 pod 生成不同格式的 DNS 记录。

Service

  • A记录:生成my-svc.my-namespace.svc.cluster.local域名,解析成 IP 地址,分为两种情况:
    • 普通 Service:解析成 ClusterIP
    • Headless Service:解析为指定 Pod 的 IP 列表
  • SRV记录:为命名的端口(普通 Service 或 Headless Service)生成 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local 的域名

Pod

  • A记录:生成域名 pod-ip.my-namespace.pod.cluster.local

kube-dns 存根域名

可以在 Pod 中指定 hostname 和 subdomain:hostname.custom-subdomain.default.svc.cluster.local,例如:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: busybox-subdomain
  containers:
  name: busybox
  - image: busybox
    command:
    - sleep
    - "3600"

该 Pod 的域名是 busybox-1.busybox-subdomain.default.svc.cluster.local。

继承节点的 DNS

运行 Pod 时,kubelet 将预先配置集群 DNS 服务器到 Pod 中,并搜索节点自己的 DNS 设置路径。如果节点能够解析特定于较大环境的 DNS 名称,那么 Pod 应该也能够解析。请参阅下面的已知问题以了解警告。

如果您不想要这个,或者您想要为 Pod 设置不同的 DNS 配置,您可以给 kubelet 指定 –resolv-conf 标志。将该值设置为 “” 意味着 Pod 不继承 DNS。将其设置为有效的文件路径意味着 kubelet 将使用此文件而不是 /etc/resolv.conf 用于 DNS 继承。

配置存根域和上游 DNS 服务器

通过为 kube-dns (kube-system:kube-dns)提供一个 ConfigMap,集群管理员能够指定自定义存根域和上游 nameserver。

例如,下面的 ConfigMap 建立了一个 DNS 配置,它具有一个单独的存根域和两个上游 nameserver:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {“acme.local”: [“1.2.3.4”]}
  upstreamNameservers: |
    [“8.8.8.8”, “8.8.4.4”]

如上面指定的那样,带有“.acme.local”后缀的 DNS 请求被转发到 1.2.3.4 处监听的 DNS。Google Public DNS 为上游查询提供服务。

下表描述了如何将具有特定域名的查询映射到其目标DNS服务器:

域名 响应查询的服务器
kubernetes.default.svc.cluster.local kube-dns
foo.acme.local 自定义 DNS (1.2.3.4)
widget.com 上游 DNS (8.8.8.8 或 8.8.4.4)

查看 ConfigMap 选项 获取更多关于配置选项格式的详细信息。

对 Pod 的影响

自定义的上游名称服务器和存根域不会影响那些将自己的 dnsPolicy 设置为 Default 或者 None 的 Pod。

如果 Pod 的 dnsPolicy 设置为 “ClusterFirst”,则其名称解析将按其他方式处理,具体取决于存根域和上游 DNS 服务器的配置。

  • 未进行自定义配置:没有匹配上配置的集群域名后缀的任何请求,例如 “www.kubernetes.io”,将会被转发到继承自节点的上游 nameserver。

  • 进行自定义配置:如果配置了存根域和上游 DNS 服务器(和在 前面例子 配置的一样),DNS 查询将根据下面的流程进行路由:

    • 查询首先被发送到 kube-dns 中的 DNS 缓存层。
    • 从缓存层,检查请求的后缀,并转发到合适的 DNS 上,基于如下的示例:
      • 有集群后缀的名字 (例如 “.cluster.local”):请求被发送到 kube-dns。
      • 具有存根域后缀的名字 (例如 “.acme.local”):请求被发送到配置的自定义 DNS 解析器(例如:监听在 1.2.3.4)。
      • 不具有能匹配上后缀的名字 (例如 “widget.com”):请求被转发到上游 DNS(例如:Google 公共 DNS 服务器,8.8.8.8 和 8.8.4.4)。

ConfigMap 选项

kube-dns kube-system:kube-dns ConfigMap 的选项如下所示:

stubDomains(可选) 使用 DNS 后缀 key 的 JSON map(例如 “acme.local”),以及 DNS IP 的 JSON 数组作为 value。 目标 nameserver 可能是一个 Kubernetes Service。例如,可以运行自己的 dnsmasq 副本,将 DNS 名字暴露到 ClusterDNS namespace 中。
upstreamNameservers(可选) DNS IP 的 JSON 数组。 注意:如果指定,则指定的值会替换掉被默认从节点的 /etc/resolv.conf 中获取到的 nameserver。限制:最多可以指定三个上游 nameserver。

示例

存根域

在这个例子中,用户有一个 Consul DNS 服务发现系统,他们希望能够与 kube-dns 集成起来。 Consul 域名服务器地址为 10.150.0.1,所有的 Consul 名字具有后缀 “.consul.local”。 要配置 Kubernetes,集群管理员只需要简单地创建一个 ConfigMap 对象,如下所示:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {“consul.local”: [“10.150.0.1”]}

注意: 集群管理员不希望覆盖节点的上游 nameserver,所以他们不会指定可选的 upstreamNameservers 字段。

示例:上游 nameserver

在这个示例中,集群管理员不希望显式地强制所有非集群 DNS 查询进入到他们自己的 nameserver 172.16.0.1。 而且这很容易实现:他们只需要创建一个 ConfigMap,upstreamNameservers 字段指定期望的 nameserver 即可。

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  upstreamNameservers: |
    [“172.16.0.1”]

调试 DNS 解析

创建一个简单的 Pod 用作测试环境

创建一个名为 busybox.yaml 的文件,其中包括以下内容:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

使用该文件创建 Pod 并验证其状态:

$ kubectl create -f busybox.yaml
pod "busybox" created

$ kubectl get pods busybox
NAME      READY     STATUS    RESTARTS   AGE
busybox   1/1       Running   0          <some-time>

该 Pod 运行后,您可以在它的环境中执行 nslookup。如果您看到类似如下的输出,表示 DNS 正在正确工作。

$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      kubernetes.default
Address 1: 10.0.0.1

如果 nslookup 命令失败,检查如下内容:

首先检查本地 DNS 配置

查看下 resolv.conf 文件。(参考集成节点的 DNS和 下面的已知问题获取更多信息)

$ kubectl exec busybox cat /etc/resolv.conf

验证搜索路径和名称服务器设置如下(请注意,搜索路径可能因不同的云提供商而异):

search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5

如果看到如下错误表明错误来自 kube-dns 或相关服务:

$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

nslookup: can't resolve 'kubernetes.default'

或者

$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes.default'

检查 DNS pod 是否在运行

使用 kubectl get pods 命令验证 DNS pod 是否正在运行。

$ kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
NAME                    READY     STATUS    RESTARTS   AGE
...
kube-dns-v19-ezo1y      3/3       Running   0           1h
...

如果您看到没有 Pod 运行或者 Pod 处于 失败/完成 状态,DNS 插件可能没有部署到您的当前环境中,您需要手动部署。

检查 DNS pod 中的错误

使用 kubectl logs 命令查看 DNS 守护进程的日志。

$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c sidecar

看看有没有可疑的日志。以字母“W”“E”“F”开头的代表警告、错误和失败。请搜索具有这些日志级别的条目,并使用 kubernetes issues来报告意外错误。

DNS 服务启动了吗?

使用 kubectl get service 命令验证 DNS 服务是否启动。

$ kubectl get svc --namespace=kube-system
NAME          CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
...
kube-dns      10.0.0.10      <none>        53/UDP,53/TCP        1h
...

如果您已经创建了该服务或它本应该默认创建但没有出现,参考调试服务获取更多信息。

DNS 端点暴露出来了吗?

您可以使用kubectl get endpoints命令验证 DNS 端点是否被暴露。

$ kubectl get ep kube-dns --namespace=kube-system
NAME       ENDPOINTS                       AGE
kube-dns   10.180.3.17:53,10.180.3.17:53    1h

如果您没有看到端点,查看调试服务文档中的端点部分。

获取更多的 Kubernetes DNS 示例,请参考 Kubernetes GitHub 仓库中的cluster-dns示例。

已知问题

Kubernetes安装时不会将节点的 resolv.conf 文件配置为默认使用集群 DNS,因为该过程本身是特定于发行版的。这一步应该放到最后实现。

Linux 的 libc 不可思议的卡住(查看该2005年起暴出来的bug)限制只能有 3 个 DNS nameserver 记录和 6 个 DNS search 记录。Kubernetes 需要消耗 1 个 nameserver 记录和 3 个 search 记录。这意味着如果本地安装已经使用 3 个 nameserver 或使用 3 个以上的 search 记录,那么其中一些设置将会丢失。有个部分解决该问题的方法,就是节点可以运行 dnsmasq,它将提供更多的 nameserver 条目,但不会有更多的 search 条目。您也可以使用 kubelet 的 –resolv-conf 标志。

如果您使用的是 Alpine 3.3 或更低版本作为基础映像,由于已知的 Alpine 问题,DNS 可能无法正常工作。点击这里查看更多信息。

]]>
应用如何设置DSCP 2019-03-14T00:00:00+08:00 Niujie https://www.neujie.cn//2019/03/how-to-set-dscp-with-application DSCP是什么

DSCP:差分服务代码点(Differentiated Services Code Point),IETF于1998年12月发布了Diff-Serv(Differentiated Service)的QoS分类标准。 它在每个数据包IP头部的服务类别TOS标识字节中,利用已使用的6比特和未使用的2比特,通过编码值来区分优先级。DSCP 使用6个bit,DSCP的值得范围为0~63。 换言之它为QOS提供了比TOS标记更多的优先级范围。

DSCP优先级

RFC 791中 OS位的IP Precedence划分成了8个优先级,可以应用于流分类,数值越大表示优先级越高。

   0     1     2     3     4     5     6     7  
+-----+-----+-----+-----+-----+-----+-----+-----+
|   PRECEDENCE    |  t3 | t2  |  t1 | t0 |m
-----+-----+-----+-----+-----+-----+-----+-----+
            111 - Network Control
            110 - Internetwork Control
            101 - CRITIC/ECP
            100 - Flash Override
            011 - Flash
            010 - Immediate
            001 - Priority
            000 – Routine

但是在网络中实际部署的时候这8个优先级是远远不够的,于是在RFC 2474中又对TOS进行了重新的定义。把前六位定义成DSCP,后两位保留。

 0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
|         DSCP          |  CU   |
+---+---+---+---+---+---+---+---+
DSCP: differentiated services codepoin
CU:   currently unused 

但是由于DSCP和IP PRECEDENCE是共存的于是存在了一些兼容性的问题,DSCP的可读性比较差,比如DSCP 43我们并不知道对应着IP PRECEDENCE的什么取值, 于是就把DSCP进行了进一步的分类。DSCP总共分成了4类。

                 Class Selector(CS)           aaa 000
                 Expedited Forwarding(EF)     101 110
                 Assured Forwarding(AF)       aaa bb0
                 Default(BE)                  000 000

1,默认的DSCP为000 000
2,CS的DSCP后三位为0,也就是说CS仍然沿用了IP PRECEDENCE只不过CS定义的DSCP=IP PRECEDENCE8,比如CS6=68=48,CS7=7*8=56
3,EF含义为加速转发,也可以看作为IP PRECEDENCE为5,是一个比较高的优先级,取值为101110(46),但是RFC并没有定义为什么EF的取值为46。
4,AF分为两部分,a部分和b部分,a部分为3 bit仍然可以和IP PRECEDENCE对应,b部分为2 bit表示丢弃性,可以表示3个丢弃优先级,可以应用于RED或者WRED。 目前a部分由于有三个bit最大取值为8,但是目前只用到了1~4。为了迅速 的和10进制转换,可以用如下方法,先把10进制数值除8得到的整数就是AF值, 余数换算成二进制看前两位就是丢弃优先级,比如34/8=4余数为2,2 换算成二进制为010,那么换算以后可以知道34代表AF4丢弃优先级为middle的数据报。

如果把CS EF AF和BE做一个排列可以发现一个有趣的现象,如下表。这个表也就是我们在现实当中应用最多的队列。根据IP PRECEDENCE的优先级,CS7最高依次排列BE最低。
一般情况下这些队列的用途看这个表的Usage字段

对应的服务 IPv4优先级/EXP/802.1P    DSCP(二进制) DSCP[dec][Hex] TOS(十六进制)       应用  丢包率  

BE         0                        0            0        0                Internet  
AF1        Green 1       001 010      10[0x0a]      40[0x28]      Leased Line  L  
AF1        Green 1       001 100      12[0x0c]      48[0x30]      Leased Line   M
AF1        Green 1       001 110      14[0x0e]      56[0x38]      Leased Line   H
AF2        Green 2                  010 010      18[0x12]      72[0x48]       IPTV VOD   L
AF2        Green 2                  010 100      20[0x14]      80[0x50]          IPTV VOD   M
AF2        Green 2                  010 110      22[0x16]      88[0x58]       IPTV VOD   H
AF3        Green 3                  011 010      26[0x1a]      104[0x68]       IPTV Broadcast  L
AF3        Green 3                  011 100      28[0x1c]      112[0x70]      IPTV Broadcast  M
AF3        Green 3                  011 110      30[0x1e]      120[0x78]       IPTV Broadcast  H
AF4        Green 4                  100 010      34[0x22]      136[0x88]       NGN/3G Singaling  L
AF4        Green 4                  100 100      36[0x24]      144[0x90]      NGN/3G Singaling M 
AF4        Green 4                  100 110      38[0x26]      152[0x98]       NGN/3G Singaling H
EF         5                        101 110      46[0x2E]      184[0xB8]      NGN/3G voice 
CS6(INC)   6                        110 000      48[0x30]      192[0xC0]      Protocol 
CS7(NC)    7                        111 000      56[0x38]      224[0xE0]      Protocol 

1,CS6和CS7默认用于协议报文,比如说OSPF报文,BGP报文等应该优先保障,因为如果这些报文无法接收的话会引起协议中断。而且是大多数厂商硬件队列里最高优先级的报文。
2,EF用于承载语音的流量,因为语音要求低延迟,低抖动,低丢包率,是仅次于协议报文的最重要的报文。
3,AF4用来承载语音的信令流量,这里大家可能会有疑问为什么这里语音要优先于信令呢?其实是这样的,这里的信令是电话的呼叫控制,你是可以忍受在接通的时候等待几秒钟的,但是绝对不能允许在通话的时候的中断。所以语音要优先于信令。
4,AF3可以用来承载IPTV的直播流量,直播的时时性很强需要连续性和大吞吐量的保证。
5,AF4可以用来承载VOD的流量,相对于直播VOD要求时时性不是很强,允许有延迟或者缓冲。
6,AF5可以承载不是很重要的专线业务,因为专线业务相对于IPTV和VOICE来讲,IPTV和VOICE是运营商最关键的业务,需要最优先来保证。当然面向银行之类需要钻石级保证的业务来讲,可以安排为AF4甚至为EF。
7,最不重要的业务是INTERNET业务,可以放在BE模型来传输。
而在硬件队列里是如何保证协议报文(CS6和CS7中的数据)优先传输呢?在制作路由器的时候一般都是把CS6和CS7中的数据做PQ也就是绝对优先处理,
无论下面是否有数据也是要优先来传递这两个队列中的数据。而其他EF到AF1的队列中是用WFQ来做的,保证所有队列都可以得到带宽来传输。

fwd: https://blog.csdn.net/wang_hufeng/article/details/40514989

]]>
深入解析 kubernetes 资源管理 2019-03-14T00:00:00+08:00 Niujie https://www.neujie.cn//2019/03/how-to-manage-resource-with-k8s FWD:https://www.jianshu.com/p/a5a7b3fb6806

资源,无论是计算资源、存储资源、网络资源,对于容器管理调度平台来说都是需要关注的一个核心问题。

  • 如何对资源进行抽象、定义?
  • 如何确认实际可以使用的资源量?
  • 如何为容器分配它所申请的资源?

这些问题都是平台开发者需要仔细思考的。当然, kubernetes 在这个方面也提出了很多精巧、实用的设计方案。所以这篇博文所关注的就是有关 kubernetes 资源管理的相关问题。

这篇博文会依次讨论以下几个问题,希望能够通过尽量平实的语言为读者解析 kubernetes 在资源管理上的大致思路。

  • 首先我们关注的是 kubernetes 对各种资源的抽象模型,也就是回答第一个问题:kubernetes 是如何对资源进行抽象和定义的呢?
  • 然后我们将关注,kubernetes 是如何获取它可以使用的资源量的信息的。
  • 在弄清楚 kubernetes 是如何定义资源,以及如何确认可用资源量后,我们将关注 kubernetes 是如何实际为 pod 分配资源的。

Kubernetes 资源模型

01 Kubernetes 是怎么定义资源的呢?

在 kubernetes 中,任何可以被申请、分配,最终被使用的对象,都是 kubernetes 中的资源,比如 CPU、内存。
而且针对每一种被 kubernetes 所管理的资源,都会被赋予一个【资源类型名】,这些名字都是符合 RFC 1123 规则的,比如 CPU,它对应的资源名全称为 kubernetes.io/cpu(在展示时一般直接简写为 cpu);GPU 资源对应的资源名为 alpha.kubernetes.io/nvidia-gpu。

除了名字以外,针对每一种资源还会对应有且仅有一种【基本单位】。这个基本单位一般是在 kubernetes 组件内部统一用来表示这种资源的数量的,比如 memory 的基本单位就是字节。

但是为了方便开发者使用,在开发者通过 yaml 文件或者 kubectl 同 kubernetes 进行交互时仍可以使用多种可读性更好的资源单位,比如内存的 Gi。而当这些信息进入 kubernetes 内部后,还是会被显式的转换为最基本单位。

所有的资源类型,又可以被划分为两大类:可压缩(compressible)和不可压缩(incompressible)的。其评判标准就在于:

如果系统限制或者缩小容器对可压缩资源的使用的话,只会影响服务对外的服务性能,比如 CPU 就是一种非常典型的可压缩资源。

对于不可压缩资源来说,资源的紧缺是有可能导致服务对外不可用的,比如内存就是一种非常典型的不可压缩资源。

02 Kubernetes 中有哪几类资源呢?

目前 kubernetes 默认带有两类基本资源

  • CPU
  • memory

其中 CPU,不管底层的机器是通过何种方式提供的(物理机 or 虚拟机),一个单位的 CPU 资源都会被标准化为一个标准的 “Kubernetes Compute Unit” ,大致和 x86 处理器的一个单个超线程核心是相同的。

CPU 资源的基本单位是 millicores,因为 CPU 资源其实准确来讲,指的是 CPU 时间。所以它的基本单位为 millicores,1 个核等于 1000 millicores。也代表了 kubernetes 可以将单位 CPU 时间细分为 1000 份,分配给某个容器。

memory 资源的基本单位比较好理解,就是字节。

另外,kubernetes 针对用户的自定制需求,还为用户提供了 device plugin 机制,让用户可以将资源类型进一步扩充,比如现在比较常用的 nvidia gpu 资源。这个特性可以使用户能够在 kubernetes 中管理自己业务中特有的资源,并且无需修改 kubernetes 自身源码。

而且 kubernetes 自身后续还会进一步支持更多非常通用的资源类型,比如网络带宽、存储空间、存储 iops 等等。

所以如上,我们就回答了 kubernetes 是如何定义资源的问题。

Kubernetes 计算节点资源管理

了解了 kubernetes 是如何对资源进行定义的,我们再来看

Kubernetes 如何确定可以使用的资源量呢?

kubernetes 所管理的集群中的每一台计算节点都包含一定的资源,kubernetes 是如何获知这台计算节点有多少资源的呢?这些资源中又有多少可以被用户容器所使用呢? 我们在使用 kubernetes 时会发现:每一个 Node 对象的信息中,有关资源的描述部分如下述所示 (通过 kubectl get node xxx -o yaml 命令可以得到)

allocatable:    
  cpu: "40"    
  memory: 263927444Ki    
  pods: "110"  
capacity:    
  cpu: "40"    
  memory: 264029844Ki    
  pods: "110"

其中 【capacity】 就是这台 Node 的【资源真实量】,比如这台机器是 8核 32G 内存,那么在 capacity 这一栏中就会显示 CPU 资源有 8 核,内存资源有 32G(内存可能是通过 Ki 单位展示的)。

而 【allocatable】 指的则是这台机器【可以被容器所使用的资源量】。在任何情况下,allocatable 是一定小于等于 capacity 的。

比如刚刚提到的 8 核机器的,它的 CPU capacity 是 8 核,但是它的 cpu allocatable 量可以被调整为 6 核,也就是说调度到这台机器上面的容器一共最多可以使用 6 核 CPU,另外 2 核 CPU 可以被机器用来给其他非容器进程使用。

Capacity 和 allocatable 信息都是如何确定的呢?

首先看 【capacity】 ,由于 capacity 反映的是这台机器的资源真实数量,所以确认这个信息的任务理所应当交给运行在每台机器上面的 kubelet 上。

kubelet 目前把 cadvisor 的大量代码直接作为 vendor 引入。其实就相当于在 kubelet 内部启动了一个小的 cadvisor。在 kubelet 启动后,这个内部的 cadvisor 子模块也会相应启动,并且获取这台机器上面的各种信息。其中就包括了有关这台机器的资源信息,而这个信息也自然作为这台机器的真实资源信息,通过 kubelet 再上报给 apiserver。

Allocatable 信息又是如何确认的呢?

如果要介绍 allocatable 信息如何确认,首先必须介绍 Node Allocatable Resource 特性 [6]。

Node Allocatable Resource 特性是由 kubernetes 1.6 版本引进的一个特性。主要解决的问题就是:为每台计算节点的【非容器进程】预留资源。

在 kubernetes 集群中的每一个节点上,除了用户容器还会运行很多其他的重要组件,他们并不是以容器的方式来运行的,这些组件的类型主要分为两个大类:

  • kubernetes daemon:kubernetes 相关的 daemon 程序,比如 kubelet,dockerd 等等。
  • system daemon:和 kubernetes 不相关的其他系统级 daemon 程序,比如 sshd 等等。

这两种进程对于整个物理机稳定的重要性是毋庸置疑的。所以针对这两种进程,kubernetes 分别提供了 Kube-Reserved 和 System-Reserved 特性,可以分别为这两组进程设定一个预留的计算资源量,比如预留 2 核 4G 的计算资源给系统进程用。

Kubernetes 是如何实现这一点的呢?

我们应该都有了解,kubernetes 底层是通过 cgroup 特性来实现资源的隔离与限制的,而这种资源的预留也是通过 cgroup 技术来实现的。

在默认情况下,针对每一种基本资源(CPU、memory),kubernetes 首先会创建一个根 cgroup 组,作为所有容器 cgroup 的根,名字叫做 kubepods。这个 cgroup 就是用来限制这台计算节点上所有 pod 所使用的资源的。默认情况下这个 kubepods cgroup 组所获取的资源就等同于该计算节点的全部资源。

但是,当开启 Kube-Reserved 和 System-Reserved 特性时,kubernetes 则会为 kubepods cgroup 再创建两个同级的兄弟 cgroup,分别叫做 kube-reserved 和 system-reserved,分别用来为 kubernetes daemon、system daemon 预留一定的资源并且与 kubepods cgroup 共同分配这个机器的资源。所以 kubepods 能够被分配到的资源势必就会小于机器的资源真实量了,这样从而就达到了为 kubernetes daemon,system daemon 预留资源的效果。

所以如果开启了 Kube-Reserved 和 System-Reserved 的特性的话,在计算 Node Allocatable 资源数量时必须把这两个 cgroup 占用的资源先减掉。

所以,假设当前机器 CPU 资源的 Capacity 是 32 核,然后我们分别设置 Kube-Reserved 为 2 核,System-Reserved 为 1 核,那么这台机器真正能够被容器所使用的 CPU 资源只有 29 核。

但是在计算 memory 资源的 allocatable 数量时,除了 Kube-Reserved,System-Reserved 之外,还要考虑另外一个因素。那就是 Eviction Threshold。

什么是 Eviction Threshold 呢?

Eviction Threshold 对应的是 kubernetes 的 eviction policy 特性。该特性也是 kubernetes 引入的用于保护物理节点稳定性的重要特性。当机器上面的【内存】以及【磁盘资源】这两种不可压缩资源严重不足时,很有可能导致物理机自身进入一种不稳定的状态,这个很显然是无法接受的。

所以 kubernetes 官方引入了 eviction policy 特性,该特性允许用户为每台机器针对【内存】、【磁盘】这两种不可压缩资源分别指定一个 eviction hard threshold, 即资源量的阈值。

比如我们可以设定内存的 eviction hard threshold 为 100M,那么当这台机器的内存可用资源不足 100M 时,kubelet 就会根据这台机器上面所有 pod 的 QoS 级别(Qos 级别下面会介绍),以及他们的内存使用情况,进行一个综合排名,把排名最靠前的 pod 进行迁移,从而释放出足够的内存资源。

所以针对内存资源,它的 allocatable 应该是 [capacity] - [kube-reserved] - [system-reserved] - [hard-eviction]

所以,如果仔细观察你会发现:如果你的集群中没有开启 kube-reserved,system-reserved 特性的话,通过 kubectl get node -o yaml 会发现这台机器的 CPU Capacity 是等于 CPU Allocatable 的,但是 Memory Capacity 却始终大于 Memory Allocatable。主要是因为 eviction 机制,在默认情况下,会设定一个 100M 的 memory eviction hard threshold,默认情况下,memory capacity 和 memory allocatable 之间相差的就是这 100M。

Kubernetes pod 资源管理与分配

通过上面我们了解了 kubernetes 如何定义并且确认在当前集群中有多少可以被利用起来的资源后,下面就来看一下 kubernetes 到底如何将这些资源分配给每一个 pod 的。

在介绍如何把资源分配给每一个 pod 之前,我们首先要看一下 pod 是如何申请资源的。这个对于大多数已经使用过 kubernetes 的童鞋来讲,并不是很陌生。

01 Kubernetes pod 资源申请方式

kubernetes 中 pod 对资源的申请是以容器为最小单位进行的,针对每个容器,它都可以通过如下两个信息指定它所希望的资源量:

  • request
  • limit

比如:

 resources:  
  requests:    
    cpu: 2.5   
    memory: "40Mi"  
  limits:     
    cpu: 4.0    
    memory: "99Mi"

那么 request,limit 分别又代表了什么含义呢?

request:

request 指的是针对这种资源,这个容器希望能够保证能够获取到的最少的量。

但是在实际情况下,CPU request 是可以通过 cpu.shares 特性能够实现的。

但是内存资源,由于它是不可压缩的,所以在某种场景中,是有可能因为其他 memory limit 设置比 request 高的容器对内存先进行了大量使用导致其他 pod 连 request 的内存量都有可能无法得到满足。

limit:

limit 对于 CPU,还有内存,指的都是容器对这个资源使用的上限。

但是这两种资源在针对容器使用量超过 limit 所表现出的行为也是不同的。

对 CPU 来说,容器使用 CPU 过多,内核调度器就会切换,使其使用的量不会超过 limit。

对内存来说,容器使用内存超过 limit,这个容器就会被 OOM kill 掉,从而发生容器的重启。

在容器没有指定 request 的时候,request 的值和 limit 默认相等。 而如果容器没有指定 limit 的时候,request 和 limit 会被设置成的值则根据不同的资源有不同的策略。

02 Kubernetes pod QoS 分类

kubernetes 支持用户容器通过 request、limit 两个字段指定自己的申请资源信息。那么根据容器指定资源的不同情况,Pod 也被划分为 3 种不同的 QoS 级别。分别为:

  • Guaranteed
  • Burstable
  • BestEffort

不同的 QoS 级别会在很多方面发挥作用,比如调度,eviction。

Guaranteed 级别的 pod 主要需要满足两点要求:

  • pod 中的每一个 container 都必须包含内存资源的 limit、request 信息,并且这两个值必须相等
  • pod 中的每一个 container 都必须包含 CPU 资源的 limit、request 信息,并且这两个信息的值必须相等

Burstable 级别的 pod 则需要满足两点要求:

  • 资源申请信息不满足 Guaranteed 级别的要求
  • pod 中至少有一个 container 指定了 cpu 或者 memory 的 request 信息

BestEffort 级别的 pod 需要满足:

  • pod 中任何一个 container 都不能指定 cpu 或者 memory 的 request,limit 信息

所以通过上面的描述也可以看出来,

  • Guaranteed level 的 Pod 是优先级最高的,系统管理员一般对这类 Pod 的资源占用量比较明确。
  • Burstable level 的 Pod 优先级其次,管理员一般知道这个 Pod 的资源需求的最小量,但是当机器资源充足的时候,还是希望他们能够使用更多的资源,所以一般 limit > request。
  • BestEffort level 的 Pod 优先级最低,一般不需要对这个 Pod 指定资源量。所以无论当前资源使用如何,这个 Pod 一定会被调度上去,并且它使用资源的逻辑也是见缝插针。当机器资源充足的时候,它可以充分使用,但是当机器资源被 Guaranteed、Burstable 的 Pod 所抢占的时候,它的资源也会被剥夺,被无限压缩。

03 Kubernetes pod 资源分配原理

我们在上面两个小节介绍了:

  • pod 申请资源的方式
  • pod 申请资源的方式对应的是什么 QoS 级别

最终,kubelet 就是基于 【pod 申请的资源】 + 【pod 的 QoS 级别】来最终为这个 pod 分配资源的。

而分配资源的根本方法就是基于 cgroup 的机制。

kubernetes 在拿到一个 pod 的资源申请信息后,针对每一种资源,他都会做如下几件事情:

  • 对 pod 中的每一个容器,都创建一个 container level cgroup(注:这一步真实情况是 kubernetes 向 docker daemon 发送命令完成的)。
  • 然后为这个 pod 创建一个 pod level cgroup ,它会成为这个 pod 下面包含的所有 container level cgroup 的父 cgroup。
  • 最终,这个 pod level cgroup 最终会根据这个 pod 的 QoS 级别,可能被划分到某一个 QoS level cgroup 中,成为这个 QoS level cgroup 的子 cgroup。
  • 整个 QoS level cgroup 还是所有容器的根 cgroup - kubepods 的子 cgroup。

未完待续…

作者:七牛云 链接:https://www.jianshu.com/p/a5a7b3fb6806 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

]]>
一步一步,步步坚实,最简单的部署K8S玩具方法 2019-03-13T00:00:00+08:00 Niujie https://www.neujie.cn//2019/03/deploy-the-simple-k8s 准备K8S、ETCD二进制

etcd etcdctl k8s.sh kube-apiserver kubeconfig kube-controller-manager kubectl kubelet kube-proxy kube-scheduler

kubeconfig文件

apiVersion: v1
kind: Config
clusters:
  - cluster:
      certificate-authority:
      server: http://10.177.243.27:8080
    name: local-up-cluster
users:
  - user:
    name: local-up-cluster
contexts:
  - context:
      cluster: local-up-cluster
      user: local-up-cluster
    name: service-to-apiserver
current-context: service-to-apiserver

K8S master及master节点部署

#!/bin/bash
#
unset http_proxy; unset https_proxy
ETCD="http://{VMIP}:4001"
MASTERIP="{VMIP}"
MASTERPORT="8080"
MASTERAPI="${MASTERIP}:${MASTERPORT}"
HOSTIP="{VMIP}"
DNSIP="10.10.10.10"
BINPATH=`pwd`
LOGPATH=$BINPATH/log/
mkdir -p $LOGPATH
kill -9 `ps -elf | grep kube | grep -v grep | awk '{print $4}'`
kill -9 `ps -elf | grep etcd | grep -v grep | awk '{print $4}'`
# Master
${BINPATH}/etcd --listen-client-urls=http://0.0.0.0:4001 --advertise-client-urls=${ETCD} > ${LOGPATH}/etcd.log 2>&1 &
sleep 8
${BINPATH}/kube-apiserver --insecure-bind-address=${MASTERIP} --etcd-servers=${ETCD} --service-cluster-ip-range=10.10.10.0/24 --insecure-port=${MASTERPORT} --secure-port=0 --service-node-port-range=2000-32767 --allow-privileged=true --v=3 > ${LOGPATH}/kube-apiserver.log 2>&1 &
${BINPATH}/kube-scheduler --address=${MASTERIP} --master=${MASTERAPI} --port=10251 --scheduler-name="default-scheduler" --stderrthreshold=2 --v=3 > ${LOGPATH}/kube-scheduler.log 2>&1 &
${BINPATH}/kube-controller-manager --master=${MASTERAPI} --v=3 > ${LOGPATH}/kube-controller-manager.log 2>&1 &
# Node
${BINPATH}/kubelet --cgroup-root=/ --cluster-dns=${DNSIP} --cluster-domain=cluster.local --hostname-override=${HOSTIP} --allow-privileged=true --v=3 --kubeconfig=${BINPATH}/kubeconfig --fail-swap-on=false > ${LOGPATH}/kubelet.log 2>&1 &
${BINPATH}/kube-proxy --master=${MASTERAPI} --hostname-override=${HOSTIP} --v=3 > ${LOGPATH}/kube-proxy.log 2>&1 &

已经部署成功了

root@HGH1000049692:~/sk8s# ./kubectl -s {masterip}:8080 get nodes  -ndefault -o wide
NAME                    STATUS    ROLES     AGE       VERSION   EXTERNAL-IP   OS-IMAGE            KERNEL-VERSION                             CONTAINER-RUNTIME
ubuntu-vm-ip           Ready     <none>    3d        v1.9.2    <none>        Ubuntu 16.04 LTS    4.4.0-104-generic                          docker://18.6.1
]]>
2018年,感恩、感谢;2019年,承担、挑战 2019-01-01T00:00:00+08:00 Niujie https://www.neujie.cn//2019/01/Happy-New-Year 2017年,随着冷清的夜晚慢慢而去,越来越淡而忘。

2018年,随着亮亮的月光漫漫浸来,又快速的离去。

2019年,陪着清新的冷风无声而来,惊喜无措迎接。

加油吧,中年!!!

为了家、为了她、为了他

2018年,我要感恩、感谢……

2019年,我要承担、挑战……

2019全家福

2018挥手送走,感恩、感谢;
2019开门大吉,挑战、担当。

贤二师傅说:不工作,不奉献,不付出,不创造价值,那生命还有什么意义呢?

愿2019年,大家:
都有工作,都有奉献,都有付出,并且创造惊人价值。
都被认可,都被关怀,都被保护,还要赋予高高薪水。

无病无灾,身体康健,工作顺利,天天好梦笑到天亮。
]]>
牛牛的第一张准考证 2018-11-17T00:00:00+08:00 Niujie https://www.neujie.cn//2018/11/the-first-admission-ticket-of-my-son 今天是儿子第一次参家考试。

我也作为家长,第一次体验了在外等候考生出来的感觉。

也没啥,就是玩吧。

牛牛和他的第一张准考证:

牛牛&准考证1

牛牛&准考证2

做更好的自己

做更好的自己

📢机器人运动等级考试信息

姓名:牛****
报考级别:2级
考场:沈阳市浑南二中(浑南区全运三路与白塔一街交叉口)
考试时间:2018-11-17 11:35-12:10

🔴注:
✅请家长提前二十分钟到达考场。
✅三级/四级考试考生需自带黑色水性笔(一二级不需要)。
✅准考证于考试当天发放以免考生或家长遗失。
✅考试时家长不得陪同,考生由工作人员统一带进考场。到达后请于与当班主任联系或联系miya校长13390248640,yoyo老师13390248641。

收到请回复[玫瑰]
]]>
我和老婆的铁婚纪念日 2018-11-11T00:00:00+08:00 Niujie https://www.neujie.cn//2018/11/my-6th-anniversary-of-marriage 今天日子比较重要。6年前的今天,2012年11月11日,我和老婆领了结婚证。

看看,俩单身,在这个超级光棍节结束了单身的日子,进入了二人世界。

6年是铁婚哦,真棒!!!

祝福我和老婆的铁婚快乐。

普及下概念:

1年一纸婚; 
2年一布婚; 
3年一皮婚; 
4年一丝婚; 
5年一木婚; 
6年一铁婚; 
7年一铜婚; 
8年一电婚; 
9年一陶婚; 
10年一锡婚; 
11年一钢婚; 
12年一亚麻婚; 
13年一花边婚; 
14年一象牙婚; 
15年一水晶婚; 
20年一瓷婚; 
25年一银婚; 
30年一珍珠婚; 
35年一玉婚; 
40年一红宝石婚; 
45年一蓝宝石婚; 
50年一金婚; 
60年一钻石婚。 
]]>
为我儿子5岁庆生,给其在github上建立一个博客账号 2018-11-10T00:00:00+08:00 Niujie https://www.neujie.cn//2018/11/happy-for-the-baby-five-years-old 还有一周就是牛牛5岁生日。为了能让其学会使用博客记录生活。

今天为其在github上建立一个账号(niuziru),并开通博客(niuziru.cn)。

儿子,爸爸希望你能快乐成长。等再大一点,爸爸会带着你学会记录生活中的点点滴滴。

今天儿子说了几句话,感动了我和老婆:

老婆:“儿子,你生日想要什么礼物?”

儿子:“机械臂,像凤凰机器人那里一样的(儿子学习机器人的培训机构)”

老牛:“妈妈过生日,都没有礼物的”

儿子:“你是不是不关心妈妈了?”

老牛:“明天我们给妈妈买个什么礼物呢?”

儿子:“买个你吧。”

我和老婆愣了……

儿子:“就是像你一样的玩偶。要是妈妈想你了,就可以抱着他了。”

……

……

……

快好了,我们马上就不会再漂泊了,我们一起努力去闯了。

愿生活快乐……

]]>
公司要你做什么 2018-10-07T00:00:00+08:00 Niujie https://www.neujie.cn//2018/10/how-can-you-doing-in-a-company 一、公司请你来做什么?
1、请你来是解决问题而不是制造问题
2、如果你不能发现问题或解决不了问题,你本人就是一个问题
3、你能解决多大的问题,你就坐多高的位子
4、你能解决多少问题,你就能拿多少薪水
5、让解决问题的人高升,让制造问题的人让位,让抱怨问题的人下课

二、问题就是你的机会

公司的问题:就是你改善的机会;
客户的问题:就是你提供服务的机会;
自己的问题:就是你成长的机会;
同事的问题:就是你提供支持建立合作机会;
领导的问题:就是你积极解决获得信任的机会
竞争对手的问题:就是你变强的机会。

三、不要轻易离开团队

1、不要老想着做不顺就放弃,哪个团队都有问题,哪个团队都有优点。
2、跟对领导很重要,愿意教你的,放手让你做的领导,绝对要珍惜。
3、团队的问题就是你脱颖而出的机会,抱怨和埋怨团队就是打自己耳光,说自己无能,更是在放弃机会!
4、心怀感恩之心,感谢系统给你平台,感谢伙伴给你配合。
5、创造利润是你存在的核心价值,创业不是做慈善。
6、遇到问题请先思考,只反映问题是初级水平,思考并解决问题才是高级水平。

四、谁能享受到胜利成果

第一:能始终跟着团队一起成长的人。
第二:对团队的前景始终看好的人。
第三:在团队不断的探索中能找到自己位置的人。
第四:为了团队新的目标不断学习新东西的人。
第五:抗压能力强且有耐性的人。
第六:与团队同心同德、同舟共济、同甘共苦的人
第七:不计较个人得失,顾全大局的人。
第八:雄心博大,德才兼备,有奉献的人! # 五、不为失败找借口
第一段
你的责任就是你的方向,
你的经历就是你的资本,
你的性格就是你的命运。

第二段
复杂的事情简单做,你就是专家;
简单的事情重复做,你就是行家;
重复的事情用心做,你就是赢家。

第三段
美好是属于自信者的,
机会是属于开拓者的,
奇迹是属于执著者的!
你若不想做,总会找到借口;
你若真想做,总会找到方法!

六、对领导而言

1对你有严格要求的领导,才是能真正帮助你成长的好领导,使我痛苦者,必使我强大!
2任何强大公司都不会给下属安全感,用最残忍方式激发每个人变得强大,自强不息!
3凡是想办法给下属安全感的公司都会毁灭的,因为再强大的人,在温顺的环境中都会失去狼性!
4凡是想方设法逼出员工能力,开发员工潜力的公司都会升腾不息,因为在这种环境下,要么变成狼,要么被狼吃掉!
5最不给员工安全感的公司,其实给了真正的安全感,因为逼出了他们的强大,逼出了他们的成长,也因此他们有了未来!
6如果真的爱你的下属,就考核他,要求他,高要求,高目标,高标准,逼迫他成长!
7如果你碍于情面,低目标,低要求,低标准养了一群小绵羊、老油条,小白兔。这是对下属最大的不负责任! 因为这只会助长他们的任性、嫉妒和懒惰。
让你的下属因为你而成长,拥有正确的人生观,价值观,并具备了完善的品行,让员工不断的成长,就是领导对下属最伟大的爱。
]]>