Code For Colorful Life
关于浮点数的运算,彻底弄懂为何 101.4 - 80.0 != 21.4
关于浮点数运算精度问题网上已有很多资料解释,但笔者还是想再造下“轮子”,加深理解。
先看一段简单的代码:
package main
func main() {
var a float32 = 101.4
var b float32 = 80.0
var c float32 = 21.4
var d float32 = 21.4
if a-b == c {
println("a-b = c")
}
if c == d {
println("c = d")
}
}
上述代码的运行结果为:
c = d
为何 a-b != c
? 如果我们直接在纸上用笔算,或者直接脑算都能得出 101.4 - 80.0 = 21.4。那么为何计算机算错了呢?
一句话说明原因:计算机在存储浮点数时存在精度误差。
Read more...
Kubernetes 网络中数据包的流转
本文基于 kubernetes 1.17.4 + calico IPIP 模式 + kube-proxy IPtables 模式,观测 pod 间数据包的流动。
同宿主上 Pod 之间的流量
在 busybox-7d4f45df67-w2mvj 中,访问 nginx-7944498f44-7cllz。
首先查看 Pod 的路由表:
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
busybox-7d4f45df67-w2mvj 发送给 nginx-7944498f44-7cllz 的数据包会通过 eth0 发送给网关 169.254.1.1。
但网关 169.254.1.1 并不是实际存在的,calico 通过在宿主机上的 Veth Pair 上设置 proxy_arp,代理了 169.254.1.1 的 arp 请求,这样容器发送出去的所有数据包都会送到宿主机上的 Veth Pair。
calico 对于 169.254.1.1 的相关解释:
- Why does my container have a route to 169.254.1.1?
- Why can’t I see the 169.254.1.1 address mentioned above on my host?
查看 busybox-7d4f45df67-w2mvj 在宿主机上的 Veth Pair:
➜ ~ calicoctl get workloadendpoint yangxikun-k8s-busybox--7d4f45df67--w2mvj-eth0 -o yaml
apiVersion: projectcalico.org/v3
kind: WorkloadEndpoint
metadata:
creationTimestamp: 2020-06-21T09:05:55Z
generateName: busybox-7d4f45df67-
labels:
app: busybox
pod-template-hash: 7d4f45df67
projectcalico.org/namespace: default
projectcalico.org/orchestrator: k8s
projectcalico.org/serviceaccount: default
name: yangxikun-k8s-busybox--7d4f45df67--w2mvj-eth0
namespace: default
resourceVersion: "1966670"
uid: e56e7d6f-cab2-4b2a-96a5-1c8f908e567b
spec:
endpoint: eth0
interfaceName: cali84b7d149337
ipNetworks:
- 10.200.77.220/32
node: yangxikun
orchestrator: k8s
pod: busybox-7d4f45df67-w2mvj
profiles:
- kns.default
- ksa.default.default
从以上信息中可以知道 busybox-7d4f45df67-w2mvj 在宿主机上的 Veth Pair 为 cali84b7d149337,查看其 proxy_arp 的设置:
➜ ~ cat /proc/sys/net/ipv4/conf/cali84b7d149337/proxy_arp
1
现在数据包出现在了宿主机上,在宿主机上观察请求数据包和响应数据包的流动。
Read more...
iptables 学习总结
参考文章:朱双印 iptables
防火墙概念
逻辑分类:
- 主机防火墙:对单个主机进行防护
- 网络防火墙:通常处于网络的入口/出口,服务于其背后的局域网
物理分类:
- 硬件防火墙:在硬件级别实现部分防火墙功能,另一部分功能基于软件实现,性能高,成本高
- 软件防火墙:应用软件处理逻辑运行于通用硬件平台之上的防火墙,性能低,成本低
iptables 概念
iptables 是一个客户端程序,与内核空间的 netfilter 交互。
netfilter 是集成到 linux 内核协议栈中的一套防火墙系统,用户可通过运行在用户空间的 iptables 来把相关配置下发给 netfilter。
netfilter 分为多个模块,各个模块的用户空间配置工具为:
- 链路层:ebtables
- 网络层ipv4:iptables
- 网络层 ipv6:ip6tables
- 专门用于 ARP 协议:arptables
wikipedia 关于 netfilter 中数据包的流图:
网络层部分的流图:
Read more...
Kubernetes Scheduler
schedulerCache:Pod 与 Node 的缓存
type schedulerCache struct {
stop <-chan struct{}
ttl time.Duration
period time.Duration
// This mutex guards all fields within this cache struct.
mu sync.RWMutex
// a set of assumed pod keys.
// The key could further be used to get an entry in podStates.
assumedPods map[string]bool
// a map from pod key to podState.
podStates map[string]*podState
nodes map[string]*nodeInfoListItem
// headNode points to the most recently updated NodeInfo in "nodes". It is the
// head of the linked list.
headNode *nodeInfoListItem
nodeTree *nodeTree
// A map from image name to its imageState.
imageStates map[string]*imageState
}
- nodes:维护节点名称到节点信息的映射
- headNode:按照更新时间由大到小排序节点信息
- nodeTree:维护 zone 和 node 关系
- 一个 node 只属于一个 zone
- 一个 zone 可以包含多个 node
- imageStates:维护镜像名称到节点的关系
- podStates:
- pod:Pod 的最新状态
- deadline:在结束绑定之后,等待多久没有从 apiserver 接收到绑定完成的事件,就会由 cache.cleanupExpiredAssumedPods 从缓存中删除
- bindingFinished:是否已经完成绑定
- assumedPods:值为 true 说明调度器为 Pod 分配了一个 Node
Pod 的调度状态变化:UnScheduled Pod -> (assume) -> Assumed Pod -> (bind) -> Scheduled Pod。
Read more...
Kubernetes API 资源对象的删除和 GarbageCollector Controller
参考文档:
- termination-of-pods
- Garbage Collection
- 两篇设计文档,不过感觉已经有点过时了:garbage-collection 和 synchronous-garbage-collection
Kubernetes API 资源对象的删除方式
Foreground cascading deletion
显示级联删除,根对象首先进入 deletion in progress 状态。在 deletion in progress 状态会有如下的情况:
- 对象仍然可以通过 REST API 可见。
- 会设置对象的 ObjectMeta.DeletionTimestamp 字段。
- 对象的 metadata.finalizers 字段包含了值 foregroundDeletion。
一旦对象被设置为 deletion in progress 状态,垃圾收集器在删除了所有 Blocking 状态的 dependents(ownerReference.blockOwnerDeletion=true)之后,对象才会被删除。
Background cascading deletion
隐式级联删除,kubernetes-apiserver 会立即删除对象,然后垃圾收集器会在后台删除 dependents。
Orphan
非级联删除,根对象首先进入 deletion in progress 状态。在 deletion in progress 状态会有如下的情况:
- 对象仍然可以通过 REST API 可见。
- 会设置对象的 deletionTimestamp 字段。
- 对象的 metadata.finalizers 字段包含了值 orphan。
一旦对象被设置为 deletion in progress 状态,垃圾收集器在解除所有 dependents 的关联之后,对象才会被删除。
Gracefully terminate
针对 Pod 特有的删除方式,允许优雅地终止容器。先发送 TERM 信号,过了宽限期还未终止,则发送 KILL 信号。
kube-apiserver 先设置 ObjectMeta.DeletionGracePeriodSeconds,默认为 30s,再由 kubelet 发送删除请求,请求参数中 DeleteOptions.GracePeriodSeconds = 0,kube-apiserver 判断到 lastGraceful = *options.GracePeriodSeconds = 0,就直接删除对象了。
Read more...