k8s基础 (一) – k8s 运行机制

一、 master 运行机制

1.1 kube-apiserver

k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。

1.1.1 监听端口

  • apiserver 目前在master监听两个端口
# (1) 通过 --insecure-port int 监听一个非安全的127.0.0.1本地端口(默认为 8080):
    该端口用于接收 HTTP 请求;
    该端口默认值为 8080,可以通过 API Server 的启动参数 "--insecure-port" 的值来修改默认值;
    默认的IP地址为 "localhost" ,可以通过启动参数 "--insecure-bind-address" 的值来修改该IP地址;
    非认证或未授权的HTTP请求通过该端口访问 API Server(kube-controller-manager、kube-scheduler)。

# (2) 通过参数--bind-address=192.168.7.101 监听一个对外访问且安全(https)的端口(默认为6443):
    该端口默认值为 6443,可通过启动参数 "--secure-port" 的值来修改默认值;
    默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数 "--bind-address" 设置该值;
    该端口用于接收客户端、dashboard 等外部 HTTPS 请求;
    用于基于 Token 文件或客户端证书及 HTTP Base 的认证;
    用于基于策略的授权;

1.1.2 API Server 的功能与使用

# 提供了集群管理的 REST API 接口(包括认证授权、数据校验以及集群状态变更);
# 提供其他模块之间的数据交互和通信的枢纽(其他模块通过 API Server 查询或修改数据,只有 API Server 才直接操作 etcd );
# 是资源配额控制的入口;
# 拥有完备的集群安全机制.

curl 127.0.0.1:8080/apis # 分组api
curl 127.0.0.1:8080/api/v1 # 带具体版本号的api
curl 127.0.0.1:8080/ # 返回核心api列表
curl 127.0.0.1:8080/version # api 版本信息
curl 127.0.0.1:8080/healthz/etcd # 与etcd的心跳监测
curl 127.0.0.1:8080/apis/autoscaling/v1 # api的详细信息
curl 127.0.0.1:8080/metrics # 指标数据

1.1.3 启动脚本

参考:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-apiserver/

# cat /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/usr/bin/kube-apiserver \
  --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook \
  --bind-address=192.168.7.101 \ #外部监听端口
  --insecure-bind-address=127.0.0.1 \ #本机监听端口
  --authorization-mode=Node,RBAC \    # 授权策略,Node:是一种专用模式,用于对kubelet发出的请求进行访问控制,RBAC:Role-Based Access Control,基于角色的访问控制
  --kubelet-https=true \ # 为 kubelet 启用 https。 (默认值 true)
  --kubelet-client-certificate=/etc/kubernetes/ssl/admin.pem \ # 用于 TLS 的客户端证书文件路径
  --kubelet-client-key=/etc/kubernetes/ssl/admin-key.pem \
  --anonymous-auth=false \
  --basic-auth-file=/etc/kubernetes/ssl/basic-auth.csv \
  --service-cluster-ip-range=10.20.0.0/16 \ # CIDR 表示的 IP 范围,服务的 cluster ip 将从中分配
  --service-node-port-range=30000-60000 \ # 保留给具有 NodePort 可见性的服务的端口范围
  --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \
  --client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \
  --etcd-cafile=/etc/kubernetes/ssl/ca.pem \
  --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \
  --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \
  --etcd-servers=https://192.168.7.105:2379,https://192.168.7.106:2379,https://192.168.7.107:2379 \
  --enable-swagger-ui=true \
  --endpoint-reconciler-type=lease \
  --allow-privileged=true \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/lib/audit.log \
  --event-ttl=1h \
  --requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --requestheader-allowed-names= \
  --requestheader-extra-headers-prefix=X-Remote-Extra- \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --proxy-client-cert-file=/etc/kubernetes/ssl/aggregator-proxy.pem \
  --proxy-client-key-file=/etc/kubernetes/ssl/aggregator-proxy-key.pem \
  --enable-aggregator-routing=true \ # 打开到 endpoints IP 的 aggregator 路由请求,替换 cluster IP
  --runtime-config=batch/v2alpha1=true \
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

1.2 kube-controller-manager

Controller Manager 作为集群内部的管理控制中心,非安全默认端口10252,负责集群内的 Node、Pod 副本、服务端点(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理,当某个 Node 意外宕机时,Controller Manager 会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。

1.2.1 启动脚本:

参考:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-controller-manager/

# vim /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/bin/kube-controller-manager \
--address=127.0.0.1 \
--master=http://127.0.0.1:8080 \ #调用kube-api-server的本地端口进行通信
--allocate-node-cidrs=true \
--service-cluster-ip-range=10.20.0.0/16 \
--cluster-cidr=172.31.0.0/16 \
--cluster-name=kubernetes \
--cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \
--cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \
--service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \
--root-ca-file=/etc/kubernetes/ssl/ca.pem \
--horizontal-pod-autoscaler-use-rest-clients=true \
--leader-elect=true \
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

1.3 kube-scheduler

Scheduler 负责 Pod 调度,在整个系统中起”承上启下”作用,承上:负责接收 Controller Manager 创建的新的 Pod,为其选择一个合适的 Node;启下:Node 上的 kubelet 接管 Pod 的生命周期

1.3.1 启动脚本

参考:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-scheduler/

[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/bin/kube-scheduler \
--address=127.0.0.1 \
--master=http://127.0.0.1:8080 \ #调用kube-api-server的本地端口进行通信
--leader-elect=true \
--v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

通过调度算法为待调度 Pod 列表的每个 Pod 从可用 Node 列表中选择一个最适合的 Node,并将信息写入 etcd 中
node 节点上的 kubelet 通过 API Server 监听到 kubernetes Scheduler 产生的 Pod 绑定信息,然后获取对应的 Pod 清单,下载 Image,并启动容器。

# 优选策略
1.LeastRequestedPriority
优先从备选节点列表中选择资源消耗最小的节点(CPU+内存)。
2.CalculateNodeLabelPriority
优先选择含有指定Label的节点。
3.BalancedResourceAllocation
优先从备选节点列表中选择各项资源使用率最均衡的节点。

二、node 节点运行机制

2.1 kubelet

在 kubernetes 集群中,每个 Node 节点都会启动 kubelet 进程,用来处理 Master 节点下发到本节点的任务,管理 Pod 和其中的容器。kubelet 会在 API Server 上注册节点信息,定期向 Master 汇报节点资源使用情况,并通过 cAdvisor (顾问)监控容器和节点资源,可以把 kubelet 理解成 Server/Agent 架构中的 agent, kubelet 是 Node上 的 pod 管家。

2.1.1 启动脚本

参考:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kubelet/

root@k8s-node2:~# cat /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/bin/kubelet \
--address=192.168.7.111 \
--allow-privileged=true \
--anonymous-auth=false \
--authentication-token-webhook \
--authorization-mode=Webhook \
--client-ca-file=/etc/kubernetes/ssl/ca.pem \
--cluster-dns=10.20.254.254 \
--cluster-domain=linux36.local. \
--cni-bin-dir=/usr/bin \
--cni-conf-dir=/etc/cni/net.d \
--fail-swap-on=false \
--hairpin-mode hairpin-veth \
--hostname-override=192.168.7.111 \
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig \ #配置文件
--max-pods=110 \
--network-plugin=cni \
--pod-infra-container-image=harbor.magedu.net/baseimages/pause-amd64:3.1 \
--register-node=true \
--root-dir=/var/lib/kubelet \
--tls-cert-file=/etc/kubernetes/ssl/kubelet.pem \
--tls-private-key-file=/etc/kubernetes/ssl/kubelet-key.pem \
--v=2
#kubelet cAdvisor 默认在所有接口监听 4194 端口的请求, 以下iptables限制内网访问
ExecStartPost=/sbin/iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 172.16.0.0/12 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -p tcp --dport 4194 -j DROP
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

2.2 kube-proxy

  • kube-proxy 运行在每个节点上,监听 API Server 中服务对象的变化,再通过管理 IPtables 来实现网络的转发。
  • Kube-Proxy 不同的版本可支持三种工作模式
    https://kubernetes.io/zh/docs/concepts/services-networking/service/

    • UserSpace
      k8s v1.2 及以后就已经淘汰
    • IPtables
      目前默认方式,1.1开始支持,1.2开始为默认
    • IPVS
      1.9引入到1.11正式版本,需要安装ipvsadm、ipset 工具包和加载 ip_vs 内核模块

2.2.1 iptables

  • Kube-Proxy 监听 Kubernetes Master 增加和删除 Service 以及 Endpoint 的消息。对于每一个 Service,Kube Proxy 创建相应的 IPtables 规则,并将发送到 Service Cluster IP 的流量转发到 Service 后端提供服务的 Pod 的相应端口上。
  • 注意:
    • 虽然可以通过 Service 的 Cluster IP 和服务端口访问到后端 Pod 提供的服务,但该 Cluster IP 是 Ping 不通的。其原因是 Cluster IP 只是 IPtables 中的规则,并不对应到一个任何网络设备。
    • IPVS 模式的 Cluster IP 是可以 Ping 通的。

2.2.2 IPVS

  • kubernetes 从1.9开始测试支持 ipvs(Graduate kube-proxy IPVS mode to beta),
  • 从1.11版本正式支持 ipvs(IPVS-based in-cluster load balancing is now GA),
  • IPVS 相对 IPtables 效率会更高一些,使用 IPVS 模式需要在运行 Kube-Proxy 的节点上安装 ipvsadm、ipset 工具包和加载 ip_vs 内核模块,当 Kube-Proxy 以 IPVS 代理模式启动时,Kube-Proxy 将验证节点上是否安装了 IPVS模块,如果未安装,则 Kube-Proxy 将回退到 IPtables 代理模式。

  • 使用 IPVS 模式,Kube-Proxy 会监视 Kubernetes Service 对象和 Endpoints,调用宿主机内核 Netlink 接口以相应地创建 IPVS 规则并定期与 Kubernetes Service 对象 Endpoints 对象同步 IPVS 规则,以确保 IPVS 状态与期望一致,访问服务时,流量将被重定向到其中一个后端 Pod , IPVS 使用哈希表作为底层数据结构并在内核空间中工作,这意味着 IPVS 可以更快地重定向流量,并且在同步代理规则时具有更好的性能,此外,IPVS 为负载均衡算法提供了更多选项,例如:rr (轮询调度)、lc (最小连接数)、dh (目标哈希)、sh (源哈希)、sed (最短期望延迟)、nq(不排队调度)等。

2.2.3 启动脚本

参考:https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-proxy/

# cat /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/bin/kube-proxy \
  --bind-address=192.168.7.111 \
  --hostname-override=192.168.7.111 \
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \ #配置文件
  --logtostderr=true \
  --proxy-mode=iptables #配置转发模式
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

三、etcd 运行机制

  • etcd 是 CoreOS 团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值 (key-value) 数据库。etcd 内部采用 raft 协议作为一致性算法,etcd 基于 Go 语言实现。
  • github地址:https://github.com/etcd-io/etcd
  • 官方网站:https://etcd.io/
Etcd具有下面这些属性:
完全复制:集群中的每个节点都可以使用完整的存档
高可用性:Etcd 可用于避免硬件的单点故障或网络问题
一致性:每次读取都会返回跨多主机的最新写入
简单:包括一个定义良好、面向用户的 API(gRPC)
安全:实现了带有可选的客户端证书身份验证的自动化 TLS
快速:每秒10000次写入的基准速度
可靠:使用 Raft 算法实现了存储的合理分布 Etcd 的工作原理

3.1 启动脚本参数

参考:https://doczhcn.gitbook.io/etcd/index/index-1/configuration

# cat /etc/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/ # 数据保存目录
ExecStart=/usr/bin/etcd \ # 二进制文件路径
  --name=etcd1 \ # 当前node 名称
  --cert-file=/etc/etcd/ssl/etcd.pem \
  --key-file=/etc/etcd/ssl/etcd-key.pem \
  --peer-cert-file=/etc/etcd/ssl/etcd.pem \
  --peer-key-file=/etc/etcd/ssl/etcd-key.pem \
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \
  --initial-advertise-peer-urls=https://192.168.7.105:2380 \ # 通告自己的集群端口
  --listen-peer-urls=https://192.168.7.105:2380 \ # 集群之间通讯端口
  --listen-client-urls=https://192.168.7.105:2379,http://127.0.0.1:2379 \ # 客户端访问地址
  --advertise-client-urls=https://192.168.7.105:2379 \ # 通告自己的客户端端口
  --initial-cluster-token=etcd-cluster-0 \ # 创建集群使用的 token,一个集群内的节点保持一致
  --initial-cluster=etcd1=https://192.168.7.105:2380,etcd2=https://192.168.7.106:2380,etcd3=https://192.168.7.107:2380 \ # 集群所有的节点信息
  --initial-cluster-state=new \ # 新建集群的时候的值为new,如果是已经存在的集群为existing。
  --data-dir=/var/lib/etcd # 数据目录路径
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target

3.2 查看成员信息

etcd 有多个不同的 API 访问版本,v1版本已经废弃,etcd v2 和 v3 本质上是共享同一套 raft 协议代码的两个独立的应用,接口不一样,存储不一样,数据互相隔离。也就是说如果从 Etcd v2 升级到 Etcd v3,原来v2 的数据还是只能用 v2 的接口访问,v3 的接口创建的数据也只能访问通过 v3 的接口访问。

ETCDCTL_API=3 etcdctl --help
<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl member --help
NAME:
    member - Membership related commands

USAGE:
    etcdctl member <subcommand> [flags]

API VERSION:
    3.4

COMMANDS:
    add    Adds a member into the cluster
    list    Lists all members in the cluster
    promote    Promotes a non-voting member in the cluster
    remove    Removes a member from the cluster
    update    Updates a member in the cluster

OPTIONS:
  -h, --help[=false]    help for member

<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl member list
2df6611b3fa63449, started, etcd-192.168.7.102, https://192.168.7.102:2380, https://192.168.7.102:2379, false


<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl member list --endpoints=https://192.168.7.102:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
2df6611b3fa63449, started, etcd-192.168.7.102, https://192.168.7.102:2380, https://192.168.7.102:2379, false

3.3 验证当前 etcd 所有成员状态

<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl endpoint health --endpoints=https://192.168.7.102:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
https://192.168.7.102:2379 is healthy: successfully committed proposal: took = 9.931857ms

# for 循环
for ip in {NODE_IPS}; do ETCDCTL_API=3 /usr/bin/etcdctl endpoint
health --endpoints=https://{ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --
cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem ; done

3.4 查看 etcd 数据信息

<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl get / --prefix --keys-only # 以路径的方式所有 key 信息
/registry/apiregistration.k8s.io/apiservices/v1.

/registry/apiregistration.k8s.io/apiservices/v1.admissionregistration.k8s.io

/registry/apiregistration.k8s.io/apiservices/v1.apiextensions.k8s.io

/registry/apiregistration.k8s.io/apiservices/v1.apps

/registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io

/registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io

<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl get /registry/apiregistration.k8s.io/apiservices/v1.apps
/registry/apiregistration.k8s.io/apiservices/v1.apps
{"kind":"APIService","apiVersion":"apiregistration.k8s.io/v1beta1","metadata":{"name":"v1.apps","uid":"895b2a58-d1d9-4e75-a4f7-19368a9903aa","creationTimestamp":"2021-04-06T11:41:45Z","labels":{"kube-aggregator.kubernetes.io/automanaged":"onstart"}},"spec":{"group":"apps","version":"v1","groupPriorityMinimum":17800,"versionPriority":15},"status":{"conditions":[{"type":"Available","status":"True","lastTransitionTime":"2021-04-06T11:41:45Z","reason":"Local","message":"Local APIServices are always available"}]}}

3.5 etcd 增删改查数据

# 添加数据
<root@ubuntu182 ~>#etcdctl put /testkey "test for linux11"
OK

# 查询数据
<root@ubuntu182 ~>#etcdctl get /testkey
/testkey
test for linux11

# 改动数据
etcdctl put /testkey "test for linux11-new" # 直接覆盖就是更新数据
OK

# 验证改动
<root@ubuntu182 ~>#etcdctl get /testkey
/testkey
test for linux11-new

# 删除数据
<root@ubuntu182 ~>#etcdctl del /testkey
1
<root@ubuntu182 ~>#etcdctl get /testkey

3.6 etcd 数据 watch 机制

  • 基于不断监看数据,发生变化就主动触发通知客户端,Etcd v3 的 watch 机制支持 watch 某个固定的 key,也支持 watch 一个范围。
  • 相比 Etcd v2, Etcd v3 的一些主要变化
    • 接口通过 grpc 提供 rpc 接口,放弃了 v2 的 http 接口,优势是长连接效率提升明显,缺点是使用不如以前方便,尤其对不方便维护长连接的场景。
    • 废弃了原来的目录结构,变成了纯粹的 kv,用户可以通过前缀匹配模式模拟目录。
    • 内存中不再保存 value,同样的内存可以支持存储更多的 key。
    • watch 机制更稳定,基本上可以通过 watch 机制实现数据的完全同步。
    • 提供了批量操作以及事务机制,用户可以通过批量事务请求来实现 Etcd v2 的 CAS 机制(批量事务支持if条件判断)。
  • watch测试:
# 在 etcd node1 上 watch 一个 key,没有此 key 也可以执行 watch,后期可以再创建:
etcdctl watch /testkey
#在etcd node2修改数据,验证etcd node1是否能够发现数据变化
<root@ubuntu182 ~>#etcdctl put /testkey "test for linux11-new"
OK

# 验证
<root@ubuntu182 ~>#etcdctl watch /testkey
PUT
/testkey
test for linux11-new

3.7 etcd 数据备份与恢复机制

  • WAL 是 write ahead log 的缩写,顾名思义,也就是在执行真正的写操作之前先写一个日志。
  • wal: 存放预写式日志,最大的作用是记录了整个数据变化的全部历程。在 etcd 中,所有数据的修改在提交前,都要先写入到 WAL 中

3.7.1 etcd v3版本数据备份与恢复

# V3版本备份数据:
<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl snapshot save snapshot.db
Snapshot saved at snapshot.db

# V3版本恢复数据:
<root@ubuntu182 ~>#ETCDCTL_API=3 etcdctl snapshot restore snapshot.db --data-dir=/opt/etcd-testdir # 将数据恢复到一个新的不存在的目录中
{"level":"info","ts":1617717360.5890028,"caller":"snapshot/v3_snapshot.go:296","msg":"restoring snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}
{"level":"info","ts":1617717360.6466186,"caller":"mvcc/kvstore.go:380","msg":"restored last compact revision","meta-bucket-name":"meta","meta-bucket-name-key":"finishedCompactRev","restored-compact-revision":19049}
{"level":"info","ts":1617717360.6540926,"caller":"membership/cluster.go:392","msg":"added member","cluster-id":"cdf818194e3a8c32","local-member-id":"0","added-peer-id":"8e9e05c52164694d","added-peer-peer-urls":["http://localhost:2380"]}
{"level":"info","ts":1617717360.72819,"caller":"snapshot/v3_snapshot.go:309","msg":"restored snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}

# 自动备份数据脚本
<root@ubuntu182 ~># mkdir /data/etcd-backup-dir/ -p
<root@ubuntu182 ~># cat script.sh
#!/bin/bash
source /etc/profile
DATE=`date +%Y-%m-%d_%H-%M-%S`
ETCDCTL_API=3 /usr/bin/etcdctl snapshot save /data/etcd-backup-dir/etcd-
snapshot-${DATE}.db

四、网络通信机制

  • k8s 中的网络主要涉及到 pod 的的各种访问需求,如同一 pod 的内部(单容器或者多容器)通信、pod A 与 pod B 的通信、从外部网络访问 pod 以及从 pod 访问外部网络。
  • k8s的网络基于第三方插件实现,但是定义了一些插件兼容规范,该规范有 CoreOS 和 Google 联合定制,叫做 CNI(Container Network Interface)。
  • 目前常用的的CNI网络插件有 calico 和 flannel:

4.1 calico

  • 官网:https://www.projectcalico.org/
  • Calico 是一个纯三层的网络解决方案,为容器提供多 node 间的访问通信,calico 将每一个 node 节点都当做为一个路由器 (router),各节点通过 BGP(Border Gateway Protocol) 边界网关协议学习并在 node 节点生成路由规则,从而将不同 node 节点上的 pod 连接起来进行通信。
  • BGP 是一个去中心化的协议,它通过自动学习和维护路由表实现网络的可用性,但是并不是所有的网络都支持 BGP,另外为了跨网络实现更大规模的网络管理,calico 还支持 IP-in-IP 的叠加模型,简称 IPIP,IPIP 可以实现跨不同网段建立路由通信,但是会存在安全性问题,其在内核内置,可以通过 Calico 的配置文件设置是否启用 IPIP,在公司内部如果 k8s 的 node 节点没有跨越网段建议关闭 IPIP。
    • IPIP 是一种将各 Node 的路由之间做一个 tunnel,再把两个网络连接起来的模式。启用 IPIP 模式时,Calico 将在各 Node 上创建一个名为 “tunl0” 的虚拟网络接口。
    • BGP 模式则直接使用物理机作为虚拟路由路(vRouter),不再创建额外的 tunnel。
  • calico 核心组件

Felix:calico 的 agent,运行在每一台 node 节点上,其主要是维护路由规则、汇报当前节点状态以确保 pod 的夸主机通信。
BGP Client:每台 node 都运行,其主要负责监听 node 节点上由 felix 生成的路由信息,然后通过 BGP 协议广播至其他剩余的 node 节点,从而相互学习路由实现 pod 通信。
Route Reflector:集中式的路由反射器,calico v3.3 开始支持,当 Calico BGP 客户端将路由从 FIB(Forward Information dataBase,转发信息库)通告到 Route Reflector 时,Route Reflector 会将这些路由通告给部署集群中的其他节点,Route Reflector 专门用于管理 BGP 网络路由规则,不会产生 pod 数据通信。

# 注:calico默认工作模式是 BGP 的 node-to-node mesh,如果要使用 Route Reflector 需要进行相关配置。
https://docs.projectcalico.org/v3.4/usage/routereflector
https://docs.projectcalico.org/v3.2/usage/routereflector/calico-routereflector

部署参考:https://docs.projectcalico.org/v3.4/getting-started/kubernetes/

4.1.1 验证当前路由表

calico 2.x 版本默认使用 etcd v2 API
calico 3.x 版本默认使用 etcd v3 API

root@k8s-node2:~# calicoctl node status
Calico process is running.
IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+---------------+-------------------+-------+----------+-------------+
| 192.168.7.101 | node-to-node mesh | up | 13:02:28 | Established |
| 192.168.7.102 | node-to-node mesh | up | 13:22:49 | Established |
| 192.168.7.110 | node-to-node mesh | up | 13:02:38 | Established |
+---------------+-------------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.

查看 pod 路由走向

验证开启 IPIP 和关闭 IPIP 的 k8s 集群验证

# 开启IPIP:
root@k8s-master1:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.7.254 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.31.13.128 192.168.7.111 255.255.255.192 UG 0 0 0 tunl0
172.31.58.64 192.168.7.110 255.255.255.192 UG 0 0 0 tunl0
172.31.89.192 0.0.0.0 255.255.255.192 U 0 0 0 *
172.31.185.128 192.168.7.102 255.255.255.192 UG 0 0 0 tunl0
192.168.0.0 0.0.0.0 255.255.248.0 U 0 0 0 eth0

root@k8s-master1:~# kubectl exec -it net-test1-68898c85b7-z7rgs sh
/ # traceroute 172.31.58.83
traceroute to 172.31.58.83 (172.31.58.83), 30 hops max, 46 byte packets
1 192.168.7.111 (192.168.7.111) 0.011 ms 0.010 ms 0.004 ms
2 172.31.58.64 (172.31.58.64) 0.300 ms 0.505 ms 0.324 ms
3 172.31.58.83 (172.31.58.83) 0.498 ms 0.619 ms 0.422 ms
/ #

关闭IPIP的通信状态

需要清空环境,重新部署k8s集群

# 当前路由表:
root@k8s-node1:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.7.254 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.31.13.128 192.168.7.111 255.255.255.192 UG 0 0 0 eth0
172.31.58.64 0.0.0.0 255.255.255.255 UH 0 0 0 cali2fd25f96bb2
172.31.58.64 0.0.0.0 255.255.255.192 U 0 0 0 *
172.31.58.65 0.0.0.0 255.255.255.255 UH 0 0 0 calia6efdd98c77
172.31.185.128 192.168.7.102 255.255.255.255 UGH 0 0 0 eth0
192.168.0.0 0.0.0.0 255.255.248.0 U 0 0 0 eth0

root@k8s-master1:/etc/ansible# kubectl run net-test1 --image=alpine --replicas=4 sleep 360000 #创建pod进行网络测试

root@k8s-master1:/etc/ansible# kubectl run net-test1 --image=alpine --replicas=4 sleep 360000
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/net-test1 created

root@k8s-master1:/etc/ansible# kubectl exec -it net-test1-68898c85b7-qrh7b sh
/ # traceroute 172.31.58.65
traceroute to 172.31.58.65 (172.31.58.65), 30 hops max, 46 byte packets
1 192.168.7.111 (192.168.7.111) 0.009 ms 0.008 ms 0.004 ms
2 192.168.7.110 (192.168.7.110) 0.282 ms 0.344 ms 0.145 ms
3 172.31.58.65 (172.31.58.65) 0.481 ms 0.363 ms 0.197 ms

4.2 flannel

  • 官网:https://coreos.com/flannel/docs/latest/
  • 文档:https://coreos.com/flannel/docs/latest/kubernetes.html
  • 由 CoreOS 开源的针对 k8s 的网络服务,其目的为解决 k8s 集群中各主机上的 pod 相互通信的问题,其借助于 etcd 维护网络 IP 地址分配,并为每一个 node 服务器分配一个不同的 IP地址段。
  • Flannel 网络模型 (后端),Flannel 目前有三种方式实现 UDP/VXLAN/host-gw:
UDP:早期版本的 Flannel 使用 UDP 封装完成报文的跨越主机转发,其安全性及性能略有不足。

VXLAN:Linux 内核在在2012年底的v3.7.0之后加入了 VXLAN 协议支持,因此新版本的 Flannel 也有 UDP 转换为 VXLAN,VXLAN 本质上是一种 tunnel(隧道)协议,用来基于3层网络实现虚拟的2层网络,目前 flannel 的网络模型已经是基于 VXLAN 的叠加(覆盖)网络。

Host-gw:也就是Host GateWay,通过在 node 节点上创建到达各目标容器地址的路由表而完成报文的转发,因此这种方式要求各 node 节点本身必须处于同一个局域网(二层网络)中,因此不适用于网络变动频繁或比较大型的网络环境,但是其性能较好。
  • Flannel 组件的解释
    • Cni0:网桥设备,每创建一个pod都会创建一对 veth pair,其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡),Pod中从网卡eth0发出的流量都会发送到Cni0网桥设备的端口(网卡)上,Cni0 设备获得的ip地址是该节点分配到的网段的第一个地址。
    • Flannel.1: overlay网络的设备,用来进行vxlan报文的处理(封包和解包),不同node之间的pod数据流量都从
    • overlay设备以隧道的形式发送到对端
  • Flannel的系统文件及目录

<root@ubuntu181 ~>#find / -name flannel
/opt/kube/bin/flannel
/run/flannel
/etc/kubeasz/roles/flannel
/etc/kubeasz/bin/flannel

4.2.1 flannel pod 状态

需要再部署 k8s 的时候使用 Flannel 作为网络插件

<root@ubuntu181 ~>#kubectl get pods -n kube-system
NAME                          READY   STATUS    RESTARTS   AGE
kube-flannel-ds-amd64-6r7f2   1/1     Running   0          93s
kube-flannel-ds-amd64-k4c75   1/1     Running   0          93s
kube-flannel-ds-amd64-sxdwf   1/1     Running   0          93s
kube-flannel-ds-amd64-x68d4   1/1     Running   0          92s

4.2.2 创建测试 pod

<root@ubuntu181 ~>#kubectl run test --image=busybox --replicas=3 sleep 30000
Flag --replicas has been deprecated, has no effect and will be removed in the future.
pod/test created

4.2.3 验证 pod 状态

<root@ubuntu181 ~>#kubectl get pod --all-namespaces -o wide
NAMESPACE     NAME                          READY   STATUS    RESTARTS   AGE     IP              NODE            NOMINATED NODE   READINESS GATES
default       test                          1/1     Running   0          51s     172.20.2.2      192.168.7.105   <none>           <none>
kube-system   kube-flannel-ds-amd64-6r7f2   1/1     Running   0          6m41s   192.168.7.102   192.168.7.102   <none>           <none>
kube-system   kube-flannel-ds-amd64-k4c75   1/1     Running   0          6m41s   192.168.7.104   192.168.7.104   <none>           <none>
kube-system   kube-flannel-ds-amd64-sxdwf   1/1     Running   0          6m41s   192.168.7.101   192.168.7.101   <none>           <none>
kube-system   kube-flannel-ds-amd64-x68d4   1/1     Running   0          6m40s   192.168.7.105   192.168.7.105   <none>           <none>

4.2.4 当前 node主机IP地址范围

<root@ubuntu181 ~>#cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.20.0.0/16
FLANNEL_SUBNET=172.20.1.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

4.2.5 node 主机路由

<root@ubuntu184 ~>#route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.7.254   0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.20.0.0      172.20.0.0      255.255.255.0   UG    0      0        0 flannel.1
172.20.1.0      172.20.1.0      255.255.255.0   UG    0      0        0 flannel.1
172.20.2.0      172.20.2.0      255.255.255.0   UG    0      0        0 flannel.1
192.168.0.0     0.0.0.0         255.255.248.0   U     0      0        0 eth0

4.2.6 验证跨主机 pod 通信

# 编辑yaml 文件:vim busybox.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-busy
  labels:
    app: app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app
        image: busybox

# 启动:
kubectl apply -f busybox.yaml

# 验证
<root@ubuntu181 ~>#kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE    IP           NODE            NOMINATED NODE   READINESS GATES
app-busy-8487c6fdb8-ck9q8   1/1     Running   0          3m1s   172.20.2.3   192.168.7.105   <none>           <none>
app-busy-8487c6fdb8-g98b5   1/1     Running   0          3m1s   172.20.3.2   192.168.7.104   <none>           <none>
app-busy-8487c6fdb8-rr7d6   1/1     Running   0          3m1s   172.20.2.4   192.168.7.105   <none>           <none>
test                        1/1     Running   0          25m    172.20.2.2   192.168.7.105   <none>           <none>

<root@ubuntu181 ~>#kubectl exec -it app-busy-8487c6fdb8-ck9q8 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.

/ # ping 172.20.2.4
PING 172.20.2.4 (172.20.2.4): 56 data bytes
64 bytes from 172.20.2.4: seq=0 ttl=64 time=0.273 ms
64 bytes from 172.20.2.4: seq=1 ttl=64 time=0.079 ms
64 bytes from 172.20.2.4: seq=2 ttl=64 time=0.088 ms
^C
--- 172.20.2.4 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.146/0.273 ms

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.20.2.1      0.0.0.0         UG    0      0        0 eth0
172.20.0.0      172.20.2.1      255.255.0.0     UG    0      0        0 eth0
172.20.2.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0

/ # traceroute 172.20.3.2
traceroute to 172.20.3.2 (172.20.3.2), 30 hops max, 46 byte packets
 1  172.20.2.1 (172.20.2.1)  0.005 ms  0.013 ms  0.002 ms
 2  172.20.3.0 (172.20.3.0)  0.440 ms  0.384 ms  0.159 ms
 3  172.20.3.2 (172.20.3.2)  0.290 ms  0.353 ms  0.119 ms

4.2.7 VxLAN Directrouting

Directrouting 为在同一个二层网络中的 node 节点启用直接路由机制,类似于 host-gw 模式。

修改 flannel 支持 Directrouting

# 修改 ansible config.yml 文件
# [flannel]设置flannel 后端"host-gw","vxlan"等
FLANNEL_BACKEND: "vxlan"
DIRECT_ROUTING: true

  net-conf.json: |
    {
      "Network": "{{ CLUSTER_CIDR }}",
      "Backend": {
{% if FLANNEL_BACKEND == "vxlan" and DIRECT_ROUTING %}
        "DirectRouting": true,
{% endif %}
        "Type": "{{ FLANNEL_BACKEND }}"
      }
    }

验证修改后的路由表

# 改之前的路由表
<root@ubuntu184 ~>#route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.7.254   0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.20.0.0      172.20.0.0      255.255.255.0   UG    0      0        0 flannel.1
172.20.1.0      172.20.1.0      255.255.255.0   UG    0      0        0 flannel.1
172.20.2.0      172.20.2.0      255.255.255.0   UG    0      0        0 flannel.1
192.168.0.0     0.0.0.0         255.255.248.0   U     0      0        0 eth0

<root@ubuntu184 ~>#reboot

# 改之后的路由表
<root@ubuntu184 ~>#route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.7.254   0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.20.0.0      192.168.7.102   255.255.255.0   UG    0      0        0 eth0
172.20.1.0      192.168.7.101   255.255.255.0   UG    0      0        0 eth0
172.20.2.0      192.168.7.105   255.255.255.0   UG    0      0        0 eth0
192.168.0.0     0.0.0.0         255.255.248.0   U     0      0        0 eth0

验证修改后的路由效果

<root@ubuntu181 ~>#kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES
app-busy-8487c6fdb8-cxppw   1/1     Running   0          30s   172.20.2.6   192.168.7.105   <none>           <none>
app-busy-8487c6fdb8-qdvpq   1/1     Running   0          30s   172.20.2.5   192.168.7.105   <none>           <none>
app-busy-8487c6fdb8-rkvxv   1/1     Running   0          30s   172.20.3.3   192.168.7.104   <none>           <none>

<root@ubuntu181 ~>#kubectl exec app-busy-8487c6fdb8-cxppw -it sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr A2:56:E8:7C:94:65  
          inet addr:172.20.2.6  Bcast:172.20.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:40 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:3412 (3.3 KiB)  TX bytes:1884 (1.8 KiB)

/ # traceroute 172.20.3.3
traceroute to 172.20.3.3 (172.20.3.3), 30 hops max, 46 byte packets
 1  172.20.2.1 (172.20.2.1)  0.006 ms  0.013 ms  0.002 ms
 2  192.168.7.104 (192.168.7.104)  0.268 ms  0.222 ms  0.132 ms
 3  172.20.3.3 (172.20.3.3)  0.356 ms  0.010 ms  0.309 ms

# 修改前
/ # traceroute 172.20.3.2
traceroute to 172.20.3.2 (172.20.3.2), 30 hops max, 46 byte packets
 1  172.20.2.1 (172.20.2.1)  0.005 ms  0.013 ms  0.002 ms
 2  172.20.3.0 (172.20.3.0)  0.440 ms  0.384 ms  0.159 ms
 3  172.20.3.2 (172.20.3.2)  0.290 ms  0.353 ms  0.119 ms

4.2.8 Flannel 不同 node 上的 pod 的通信流程

Flannel.1 是一个 overlay 网络的设备,用来进行 vxlan 报文的处理(封包和解包),不同 node 之间的 pod 数据流量都从 overlay 设备以隧道的形式发送到对端。

->: pod中产生数据,根据pod的路由信息,将数据发送到Cni0
->: Cni0 根据节点的路由表,将数据发送到隧道设备flannel.1
->: Flannel.1查看数据包的目的ip,从flanneld获得对端隧道设备的必要信息,封装数据包。
->: Flannel.1将数据包发送到对端设备,对端节点的网卡接收到数据包
->: 对端节点发现数据包为overlay数据包,解开外层封装,并发送到到本机flannel.1设备。
->: Flannel.1设备查看数据包,根据路由表匹配,将数据发送给Cni0设备。
->: Cni0匹配路由表,发送数据给网桥上对应的端口(pod)。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇