Kubernetes高可用部署

news2024/9/23 1:33:22

 💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

Kubernetes 高可用部署
技能目标:
- 了解 Kubernetes 高可用方案
- Master 多节点部署与配置
- Load Balance 多节点部署与配置
- Node 节点的 VIP 配置

9.1 案例分析

9.1.1 案例概述

Kubernetes 高可用是保证 Master 节点中的 API Server 服务的高可用。API Server

供了 Kubernetes 各类资源对象增删改查的唯一访问入口,是整个 Kubernetes 系统的数据

总线和数据中心。采用负载均衡(Load Balance)连接两个 Master 节点可以提供稳定容器

云业务。本章主要学习 Kubernetes 高可用的部署方法。

9.1.2 案例前置知识点

1. Etcd 概念与作用

Etcd 是一个分布式键值对存储系统,由 CoreOS 开发,内部采用 Raft 协议作为一致性

算法,用于可靠、快速地保存关键数据并提供访问。通过分布式锁、Leader 选举和写屏障(W

rite Barriers),来实现可靠的分布式协作。Etcd 集群是为高可用、持久化数据存储和检索而

准备的。

Etcd 具备以下几个优点:

简单:安装、配置、使用均比较简单,且提供 HTTP API 进行交互;

安全:支持 SSL 证书验证;

快速:根据官方提供的 benchmark 数据,单实例支持每秒 2k+读操作;

可靠:采用 Raft 算法,实现分布式系统数据的可用性和一致性。

2. Flannel 组件

Flannel CoreOS 团队针对 Kubernetes 设计的一个网络规划服务,其作用是让集群
中不同节点创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。
在默认的 Docker 配置中,每个节点上的 Docker 服务会分别负责所在节点容器的 IP
址分配。这就会导致,不同节点上容器可能获得相同的内网 IP 地址。
Flannel 的设计目的就是为集群中的所有节点重新规划 IP 地址的使用规则,从而使得不
同节点上的容器能够获得同属一个内网不重复的”IP 地址,并让属于不同节点上的容器
能够直接通过内网 IP 地址进行通信。
Flannel 实质上是一种覆盖网络(Overlay Network)”,也就是将 TCP 数据包装在另一种
网络包里面进行路由转发和通信目前已经支持 UDPVxLANAWS VPC GCE 路由等数
据转发方式,默认的节点间数据通信方式是 UDP 转发。
Flannel 工作原理如图 9.1 所示。
9.1
Flannel 工作原理图
数据从源容器中发出后,经由所在主机的 docker0 虚拟网卡转发到 flannel0 虚拟网卡,
这是个 P2P 的虚拟网卡,Flanneld 服务监听在网卡的另外一端。
Flannel 通过 Etcd 服务维护了一张节点间的路由表。
源主机的Flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节
点的 Flanneld 服务。数据到达以后被解包,然后直接进入目的节点的 flannel0 虚拟网卡,
再被转发到目的主机的 docker0 虚拟网卡。

3. API Server 组件

(1)API Server 概述

API Server 提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的 API

来操作资源数据,只有 API Server 与存储通信,其他模块通过 API Server 访问集群状态。

作为 Kubernetes 系统的入口,封装了核心对象的增删改查操作,以 RESTFul 接口方式提

供给外部客户和内部组件调用。对相关的资源数据全量查询”+“变化监听,实时完成相关的

业务功能。

(2)API Server 组件的功能

提供了集群管理的 REST API 接口(包括认证授权、数据校验以及集群状态变更)

提供其他模块之间的数据交互和通信的枢纽(其他模块通过 API Server 查询或修

改数据,只有 API Server 才直接操作 Etcd);

是资源配额控制的入口;

拥有完备的集群安全机制。

(3)API Server 安全访问机制

Authentication(认证):对用户身份进行验证。共有 8 种认证方式,可以启用一

种或多种认证方式,只要有一种认证方式通过,就不再进行其它方式的认证。通常

启用 X509 Client Certs Service Accout Tokens 两种认证方式。

Authorization(授权):验证用户是否拥有访问权限。共有 6 种授权方式现,可以

启用一种或多种授权方式,启用的任一种方式依据授权策略明确允许或拒绝请求,

则立即返回,不再进行其它方式的授权。通常启用 RBAC Node 授权方式。

Admission Control(准入控制):对 API 资源对象修改、校验。它有一个插件列

表,所有请求需要经过这个列表中的每个准入控制插件修改、校验,如果某一个准

入控制插件验证失败,就拒绝请求。

4. Scheduler 组件

(1)Scheduler 概述

Scheduler Kubernetes 的调度器,主要任务是把定义的 Pod 分配到集群的节点上。

在调度时需要考虑以下几个问题:

公平:如何保证每个节点都能被分配资源;

资源高效利用:集群所有资源最大化被使用;

效率:调度的性能要好,能够尽快的对大批量的 Pod 完成调度工作;

灵活:允许用户根据自己的需求控制调度的逻辑。

(2)Scheduler 工作原理

Scheduler 作为一个单独的进程部署在 Master 节点上,它会 watch kube-apiserver
程去发现 PodSpec.NodeName 为空的 Pod,然后根据指定的算法将 Pod 调度到合适的 No
de ,这一过程也叫绑定(Bind)Scheduler 输入是需要被调度 Pod Node 的信息,输出
是经过调度算法筛选出条件最优的 Node,并将该 Pod 绑定到这个 Node 上。Scheduler
构图如图 9.2 所示。
9.2 Scheduler 工作原理图
通过上图可以看到,调度器实际上主要是由两个控制循环来完成对 PodService
等调度。
 Informer Path
第一个循环 Informer Path 中,调度器通过一系列的 Informer 来对 PodNodeS
ervice 等信息进行 list and watch。当对应资源(比如 Pod)有改变时,Informer 会收
到来自 API Server 的变化通知,然后 Informer 会将资源变动信息更新到调度器缓存中
用于后续调度算法的判定依据。使用缓存的好处是避免对 API Server 进行大量重复的
请求操作,从而提升调度效率,特别是后面的调度算法判定阶段。
如果有新增的资源,比如有个新的 Pod,那么 Informer 会将其添加到调度队列中。
调度队列是一个优先级的队列,它在保证 FIFO(先进先出)基本功能的同时还能满足
调度器的一些特殊操作,比如基于优先级的抢占操作。
 Scheduling Path
Scheduling Path 中,调度器会从调度队列里不断取出需要调度的资源,然后通
Predicates 算法对调度器缓存中的 Nodes 进行过滤,拿到合适的 Node 列表。然后
根据 Priorities 算法对 Node 列表进行打分,选出得分最高的 Node
经过 Priorities 算法后,修改资源的 nodeName 字段为选出的 Node,并更新调度
器缓存中 Pod Node 的信息,然后启动一个异步的线程去请求 API Server 去修改持
久化的 Pod 信息。这样做的好处是提高了调度器的调度效率。如果异步线程失败了也
无所谓,缓存中的信息会随着后续的更新而恢复正常,调度失败的资源会在后续进行重
新调度。当然这种基于乐观绑定的设计,就需要 Kubelet 在实际运行资源的时候再次通
过基本的调度算法进行确认,看当前 Pod 是否能够在当前 Node 运行。同时为了进一步
提升调度的效率,调度器对 Predicates Priorities 过程都是启动多个线程来并发地对
多个资源进行判定,同时在 Priorities 阶段以 MapReduce 的方式来进行打分。整个过
程只有在资源出队和更新缓存的时候会加锁,从而保证了调度器的执行效率。
(3)Scheduler 调度流程
请求及 Scheduler 调度步骤:
预选:根据配置的 Predicates Policies(默认为 DefaultProvider 中定义的 def
ault predicates policies 集合)过滤掉那些不满足这些 Policies 的的 Nodes
剩下的 Nodes 就作为优选的输入;
优选:根据配置的 Priorities Policies(默认为 DefaultProvider 中定义的 defa
ult priorities policies 集合)给预选后的 Nodes 进行打分排名;
选定:根据 Priorities 得分最高的 Node 即作为最适合的 Node,该 Pod Bin
d 到这个 Node
图 9.3
Scheduler 调度流程
如图 9.3 所示,Scheduler 调度流程分为以下几个步骤:
(1) 用户通过 Kubernetes 客户端 Kubectl 提交创建 Pod Yaml 的文件,向 Kubernet
es 系统发起创建 Pod 的资源请求;
(2) Kubectl 命令行工具向 Kubernetes 集群(即 API Server)发送 POST 请求,来创
Pod
(3) API Server 接收到请求后把创建 Pod 的信息存储到 Etcd 中;
(4) 从集群运行的那一刻起,资源调度系统 Scheduler 采用 watch 机制,定时去监控 A
PI Server 获取 Pod 的信息。当 Scheduler 发现 Pod 属性中的 Dest Node 为空时
Dest Node=””)便会立即触发调度流程进行调度;
创建一个 Pod 对象,在调度的过程当中有三个阶段:节点预选、节点优选、节点
选定。通过这三个阶段,筛选出最佳的节点。当最佳节点多于 1 个时,则进行随机选择。

5. Controller-Manager 组件

(1)Controller-Manager 概述

Controller Manager 作为集群内部的管理控制中心,负责集群内的 NodePod

本、服务端点(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理。当某个 Node 意外宕机时,Controller Manager

会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。

每个 Controller 通过 API Server 提供的接口实时监控整个集群的每个资源对象的

当前状态,当发生各种故障导致系统状态发生变化时,会尝试将系统状态修复到“期望

状态”。

9.4 Controller-Manager

(2)Replication Controller

为了区分资源对象 Replication ControllerController Manager中的Replication

Controlle,通常将资源对象 Replication Controller 简称 RC。而本文 Controller Mana

ger 中的 Replication Controller,称为副本控制器。副本控制器的作用是保证集群中一

RC 所关联的 Pod 副本数始终保持预设值。

只有当 Pod 的重启策略是 Always 的时候(RestartPolicy=Always),副本控制器

才会管理该 Pod 的操作(创建、销毁、重启等)。如果一个 Pod 失败重启,重启的 No

de Replication Controller 决定,不一定是原先的 Node

RC 中的 Pod 模板就像一个模具,模具制造出来的东西一旦离开模具,它们之间就

再没关系了。一旦 Pod 被创建,无论模板如何变化,也不会影响到已经创建的 Pod

Pod 可以通过修改 Label 来脱离 RC 的管控,该方法可以用于 Pod 从集群中迁移、

数据修复等调试。

删除一个 RC 不会影响它所创建的 Pod,如果要删除 Pod 需要将 RC 的副本数属性

设置为 0。不建议越过 RC 创建 Pod,因为 RC 可以实现自动化控制 Pod,提高容灾能

力。

Replication Controller 的职责:

确保集群中有且仅有 N Pod 实例,N RC 中定义的 Pod 副本数量;

通过调整 RC 中的 spec.replicas 属性值来实现系统扩容或缩容;

通过改变 RC 中的 Pod 模板来实现系统的滚动升级。

9- Replication Controller 使用场景

使用场景

说明

使用命令

重新调度

当发生节点故障或 Pod 被意外终止运行时,可 以重新调度保证集群中仍然运行指定的副本

数。

弹性伸缩

通过手动或自动扩容代理修复副本控制器的 s pec.replicas 属性,可以实现弹性伸缩。

kubectl scale

滚动更新

创建一个新的 RC 文件,通过 kubectl 命令或 API 执行,则会新增一个新的副本同时删除旧

的副本,当旧副本为 0 时,删除旧的 RCkubectl rolls'sing-update

(3)Node Controller

Kubelet 在启动时会通过 API Server 注册自身的节点信息,并定时向 API Server

汇报状态信息,API Server 接收到信息后将信息更新到 Etcd 中。而 Node Controller

可以通过 API Server 实时获取 Node 的相关信息,实现管理和监控集群中的各个 Nod

e 节点的相关控制功能。Node Controller 的具体工作流程如图 9.5 所示。

9.5 Node Controller 流程

Controller Manager 在启动时如果设置了–cluster-cidr 参数,那么就会为每个没有

设置 Spec.PodCIDR Node 节点生成一个 CIDR 地址,并用该 CIDR 地址设置节点的

Spec.PodCIDR 属性,防止不同节点的 CIDR 地址发生冲突。逐个读取节点信息,如果

节点状态变成非就绪状态,则将节点加入待删除队列,否则将节点从该队列删除。

(4)Namespace Controller

用户通过 API Server 可以创建新的 Namespace 并保存在 Etcd 中,Namespace

Controller 定时通过 API Server 读取这些 Namespace 信息。

如果 Namespace API 标记为优雅删除(即设置删除期限,DeletionTimestamp),

则将该 Namespace 状态设置为“Terminating”,并保存到 Etcd 中。同时 Namespace C

ontroller 删除该 Namespace 下的 ServiceAccountRCPod 等资源对象。

6. kubeconfig

kubeconfig 文件用于组织关于集群、用户、命名空间和认证机制的信息。命令行工

Kubectl kubeconfig 文件中得到它要选择的集群以及跟集群API server交互的信

息。

需要注意的是,用于配置集群访问信息的文件叫作 kubeconfig 文件,这是一种引用

配置文件的通用方式,并不是说它的文件名就是 kubeconfig

默认情况下,Kubectl 会从 $HOME/.kube 目录下查找文件名为 config 的文件。可

以通过设置环境变量 KUBECONFIG 或者通过设置--kubeconfig 去指定其它 kubeconfi

g 文件。

7. Kubelet 组件

(1)Kubelet 概述

Kubernetes 集群中,每个 Node 节点都会启动 Kubelet 进程,用来处理 Master 节点

下发到本节点的任务,管理 Pod 和其中的容器。Kubelet 会在 API Server 上注册节点信息,

定期向 Master 汇报节点资源使用情况,并通过 cAdvisor 监控容器和节点资源。可以把 Ku

belet 理解成【Server-Agent】架构中的 Agent,是 Node 上的 Pod 管家。

(2)节点管理

节点通过设置 Kubelet 的启动参数“–register-node”来决定是否向 API Server 注册自

己,默认为 true。可以通过 kubelet --help 命令来查看该参数。

Kubelet 的默认配置文件在/etc/kubernetes/kubelet 中,其中

–api-servers:用来配置 Master 节点的 IP 地址和端口。

–kubeconfig:用来配置 kubeconfig 的路径,kubeconfig 文件常用来指定证书。

–hostname-override:用来配置该节点在集群中显示的主机名。

–node-status-update-frequency:配置 Kubelet Master 心跳上报的频率,默认

10s

(3)Pod 管理

Kubelet 有多种方式可以获取自身 Node 上所需要运行的 Pod 清单。但本文只讨论通过

API Server 监听 Etcd 目录,同步 Pod 列表的方式。

Kubelet 通过 API Server Client 使用 WatchAndList 的方式监听 Etcd /registry/node

s/${当前节点名称}/registry/pods 的目录,将获取的信息同步到本地缓存中。

Kubelet 监听 Etcd,执行对 Pod 的操作,对容器的操作则是通过 Docker Client 执行,

例如启动删除容器等。

Kubelet 创建和修改 Pod 流程:

为该 Pod 创建一个数据目录;

API Server 读取该 Pod 清单;

为该 Pod 挂载外部卷(External Volume);

下载 Pod 用到的 Secret

检查运行的 Pod,执行 Pod 中未完成的任务;

先创建一个 Pause 容器,该容器接管 Pod 的网络,再创建其他容器;

Pod 中容器的处理流程:

比较容器 Hash 值并做相应处理;

如果容器被终止了且没有指定重启策略,则不做任何处理;

调用 Docker Client 下载容器镜像,调用 Docker Client 运行容器。

8. Kube-Proxy 组件

Service 在逻辑上代表后端的多个 Pod,外界通过 Service 访问 PodService 接收

到请求就需要 Kube-Proxy 转发到 Pod。每个 Node 都会运行 Kube-Proxy 服务,负责

将访问 Service TCP/UDP 数据流转发到后端的容器。如果有多个副本,Kube-Proxy

会实现负载均衡,负载均衡的方式有 LVS 或者 Iptables

9 Load Balance 作用

NodePort 基础上,Kubernetes 可以请求底层云平台创建一个负载均衡器,将每

Node 作为后端,进行服务分发。该模式需要底层云平台(例如 GCE)支持。

9.1.3 案例环境
1. 本案例环境
本案例的实验环境如表 9-1 所示,并设置群集 VIP 地址为 192.168.100.200
主机名IP地址操作系统主要软件
k8s-master01192.168.100.51CentOS 7.3Etcd+Kubernetes
k8s-master02192.168.100.52CentOS 7.3Etcd+Kubernetes
k8s-node01192.168.100.53CentOS 7.3Etcd+Kubernetes+Flannel+Docker
k8s-node02192.168.100.54CentOS 7.3Etcd+Kubernetes+Flannel+Docker
k8s-lb01192.168.100.55CentOS 7.3Nginx+Keepalived
k8s-lb02192.168.100.56CentOS 7.3Nginx+Keepalived

9-1 创建并管理 Kubernetes 高可用案例环境
创建并管理 Kubernetes 高可用架构,具体的拓扑如图 9.6 所示。
9.6 Kubernetes 高可用架构
2. 案例需求
使用 Nginx+Keepalived+Kubernetes 部署 Kubernetes HA,并实现故障切换效果。
3. 案例实现思路
1)基础环境配置;
2)部署群集证书;
3)部署 Etcd 群集;
4)部署 API Server 组件(Master 节点);
5)部署 Scheduler 组件(Master 节点);
6)部署 Controller-Manager 组件(Master 节点);
7)部署 DockerNode 节点);
8)部署 Flannel 配置(Node 节点);
9)部署 kubeconfig 配置(Node 节点);
10Node 节点部署 Kubelet 组件(Node 节点);
11Node 节点部署 Kube-Proxy 组件(Node 节点);
12)部署 Nginx 反向代理(Lb 节点);
13)部署 Keepalived 配置(Lb 节点)。
9.2 案例实施
9.2.1 基础环境配置
(1)配置基础网络信息
为所有主机配置 IP 地址、网关、DNS 等基础网络信息(此过程略)。建议主机设置为
静态 IP 地址,避免因为 IP 地址变化出现群集中无法连接 API Server 的现象,导致
Kubernetes 群集不可用。
(2)配置主机名与地址解析记录
为所有主机配置主机名并添加地址解析记录,下面以 k8s-master01 主机为例进行操作
演示。
[root@localhost ~]# hostnamectl set-hostname k8s-master01
[root@localhost ~]# bash
[root@k8s-master01 ~]# cat << EOF >> /etc/hosts
//六台主机均操作
192.168.100.51 k8s-master01
192.168.100.52 k8s-master02
192.168.100.53 k8s-node01
192.168.100.54 k8s-node02
192.168.100.55 k8s-lb01
192.168.100.56 k8s-lb02
EOF
(3)禁用防火墙与 Selinux
//六台主机均操作
[root@k8s-master01 ~]# systemctl stop firewalld.service
[root@k8s-master01 ~]# systemctl disable firewalld.service
[root@k8s-master01 ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
[root@k8s-master01 ~]# shutdown -r now
//重启使 Selinux 配置生效
9.2.2 部署群集证书
k8s-master01 主机上创建的目录“/k8s”,并将准备好的脚本文件 etcd-cert.sh
etcd.sh 上传至/k8s 目录中。其中 etcd-cert.sh 脚本是 Etcd 证书创建的脚本;etcd.sh
脚本是 Etcd 服务脚本,包含配置文件及启动脚本。
[root@k8s-master01 ~]# mkdir /k8s
[root@k8s-master01 ~]# cd /k8s
[root@k8s-master01 k8s]# ls
etcd-cert.sh etcd.sh
创建目录/k8s/etcd-cert,证书全部存放至该目录中,方便管理。[root@k8s-master01 k8s]# mkdir /k8s/etcd-cert
[root@k8s-master01 k8s]# mv /k8s/etcd-cert.sh /k8s/etcd-cert
编辑 cfssl 创建脚本,并使用 bash 命令下载 cfssl 软件包。下载过程需要等一段时间,
下载完成后查看/usr/local/bin 目录下 cfssl 工具相关命令是否存在,并且赋予工具执行权限。
[root@k8s-master01 k8s]# cat << EOF > cfssl.ssh
curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl
curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson
curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo
EOF
[root@k8s-master01 k8s]# bash cfssl.ssh
[root@k8s-master01 k8s]# ls /usr/local/bin/
cfssl cfssl-certinfo cfssljson
[root@k8s-master01 k8s]# chmod +x /usr/local/bin/cfssl*
1. 创建 CA 证书
[root@k8s-master01 ~]# cd /k8s/etcd-cert/
[root@k8s-master01 etcd-cert]# cat << EOF > ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
[root@k8s-master01 etcd-cert]# cat << EOF > ca-csr.json
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
[root@k8s-master01 etcd-cert]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
2020/05/14 15:02:07 [INFO] generating a new CA key and certificate from CSR
2020/05/14 15:02:07 [INFO] generate received request
2020/05/14 15:02:07 [INFO] received CSR
2020/05/14 15:02:07 [INFO] generating key: rsa-2048
2020/05/14 15:02:07 [INFO] encoded CSR
2020/05/14 15:02:07 [INFO] signed certificate with serial number 94675105934942996557611
035272793116396837196529
2. 创建 Server 证书
[root@k8s-master01 etcd-cert]# cat << EOF > server-csr.json
{
"CN": "etcd",
"hosts": [
"192.168.100.51",
"192.168.100.52",
"192.168.100.53",
"192.168.100.54"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
]
}
EOF
[root@k8s-master01 etcd-cert]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-c
onfig.json -profile=www server-csr.json | cfssljson -bare server
2020/05/14 15:06:09 [INFO] generate received request
2020/05/14 15:06:09 [INFO] received CSR
2020/05/14 15:06:09 [INFO] generating key: rsa-2048
2020/05/14 15:06:09 [INFO] encoded CSR
2020/05/14 15:06:09 [INFO] signed certificate with serial number 16143015569652973240786
6931547543928991708583062
2020/05/14 15:06:09 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitabl
e for
websites. For more information see the Baseline Requirements for the Issuance and Manage
ment
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
9.2.3 部署 Etcd 群集
1. 准备 Etcd 相关工具与启动所需证书
[root@k8s-master01 etcd-cert]# cd /k8s/
[root@k8s-master01 k8s]# ls *.tar.gz
etcd-v3.3.18-linux-amd64.tar.gz
[root@k8s-master01 k8s]# tar zxvf etcd-v3.3.18-linux-amd64.tar.gz
[root@k8s-master01 k8s]# ls etcd-v3.3.18-linux-amd64
Documentation etcd etcdctl README-etcdctl.md README.md READMEv2-etcdctl.md
[root@k8s-master01 k8s]# mkdir /opt/etcd/{cfg,bin,ssl} -p
[root@k8s-master01 k8s]# cd etcd-v3.3.18-linux-amd64
[root@k8s-master01 etcd-v3.3.18-linux-amd64]# mv etcd etcdctl /opt/etcd/bin/
[root@k8s-master01 etcd-v3.3.18-linux-amd64]# cp /k8s/etcd-cert/*.pem /opt/etcd/ssl/
[root@k8s-master01 etcd-v3.3.18-linux-amd64]# ls /opt/etcd/ssl/
ca-key.pem ca.pem server-key.pem server.pem
2. 部署 Etcd 群集
[root@k8s-master01 etcd-v3.3.18-linux-amd64]# cd /k8s/
[root@k8s-master01 k8s]# bash etcd.sh etcd01 192.168.100.51 etcd02=https://192.168.100.
52:2380,etcd03=https://192.168.100.53:2380,etcd04=https://192.168.100.54:2380
[root@k8s-master01 k8s]# scp -r /opt/etcd/ root@k8s-master02:/opt/
[root@k8s-master01 k8s]# scp -r /opt/etcd/ root@k8s-node01:/opt/
[root@k8s-master01 k8s]# scp -r /opt/etcd/ root@k8s-node02:/opt/
[root@k8s-master01
k8s]#
scp
/usr/lib/systemd/system/etcd.service
root@k8s-master02:/usr/lib/systemd/system/
[root@k8s-master01
k8s]#
scp
/usr/lib/systemd/system/etcd.service
root@k8s-node01:/usr/lib/systemd/system/
[root@k8s-master01
k8s]#
scp
/usr/lib/systemd/system/etcd.service
root@k8s-node02:/usr/lib/systemd/system/
[root@k8s-master02 ~]# vim /opt/etcd/cfg/etcd
#[Member]
ETCD_NAME="etcd02"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.100.52:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.100.52:2379"
#[Clustering]ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.100.52:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.100.52:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.100.51:2380,etcd02=https://192.168.100.52:2
380,etcd03=https://192.168.100.53:2380,etcd04=https://192.168.100.54:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
[root@k8s-node01 ~]# vim /opt/etcd/cfg/etcd
#[Member]
ETCD_NAME="etcd03"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.100.53:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.100.53:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.100.53:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.100.53:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.100.51:2380,etcd02=https://192.168.100.52:2
380,etcd03=https://192.168.100.53:2380,etcd04=https://192.168.100.54:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
[root@k8s-node02 ~]# vim /opt/etcd/cfg/etcd
#[Member]
ETCD_NAME="etcd04"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.100.54:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.100.54:2379"
#[Clustering]
21 页 共 60 ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.100.54:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.100.54:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.100.51:2380,etcd02=https://192.168.100.52:2
380,etcd03=https://192.168.100.53:2380,etcd04=https://192.168.100.54:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
//master01master02node01node02 4 台主机上均执行以下操作
[root@k8s-master01 k8s]# systemctl daemon-reload
[root@k8s-master01 k8s]# systemctl restart etcd
[root@k8s-master01 k8s]# systemctl enable etcd
//master01 主机上执行以下操作
[root@k8s-master01 k8s]# cd /k8s/etcd-cert/
[root@k8s-master01 etcd-cert]# /opt/etcd/bin/etcdctl --ca-file=ca.pem --cert-file=server.pem
--key-file=server-key.pem
--endpoints="https://192.168.100.51:2379,https://192.168.100.52:2379,https://192.168.100.53:
2379,https://192.168.100.54:2379" cluster-health
member 3037d420fe23208 is healthy: got healthy result from https://192.168.100.54:2379
member b328594e57a6845a is healthy: got healthy result from https://192.168.100.51:2379
member e10aa672cd8b9c7b is healthy: got healthy result from https://192.168.100.52:2379
member f25c00105dcfb350 is healthy: got healthy result from https://192.168.100.53:2379
cluster is healthy
9.2.4 部署 APIServer 组件
1. 创建所需证书
上传并解压 master.zip 包后会生成三个脚本:apiserver.shcontroller-manager.sh
scheduler.sh。为脚本文件添加执行权限,后面每一个服务的启动都要依赖于这三个脚本。
[root@k8s-master01 ~]# cd /k8s/
[root@k8s-master01 k8s]# unzip master.zip
Archive: master.zip
inflating: scheduler.sh
inflating: apiserver.sh
inflating: controller-manager.sh
[root@k8s-master01 k8s]# chmod +x *.sh
创建/k8s/k8s-cert 目录,作为证书自签的工作目录,将所有证书都生成到此目录中。在
/k8s/k8s-cert 目录中创建证书生成脚本 k8s-cert.sh,脚本内容如下所示。执行 k8s-cert.sh
脚本即可生成 CA 证书、服务器端的私钥、admin 证书、proxy 代理端证书。
[root@k8s-master01 k8s]# mkdir /k8s/k8s-cert
[root@k8s-master01 k8s]# cd /k8s/k8s-cert/
[root@k8s-master01 k8s-cert]# vim k8s-cert.sh
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
#-----------------------
cat > server-csr.json <<EOF
{
"CN": "kubernetes",
"hosts": [
"10.0.0.1",
"127.0.0.1",
"192.168.100.51",
"192.168.100.52",
"192.168.100.53",
"192.168.100.54",
"192.168.100.200",
//VIP 地址
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing","ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server
-csr.json | cfssljson -bare server
#-----------------------
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "system:masters",
"OU": "System"
}
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin
-csr.json | cfssljson -bare admin
#-----------------------
cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-
proxy-csr.json | cfssljson -bare kube-proxy
执行 k8s-cert.sh 脚本会生成 8 张证书。
[root@k8s-master01 k8s-cert]# bash k8s-cert.sh
2020/05/14 16:55:28 [INFO] generating a new CA key and certificate from CSR
2020/05/14 16:55:28 [INFO] generate received request
2020/05/14 16:55:28 [INFO] received CSR
2020/05/14 16:55:28 [INFO] generating key: rsa-2048
2020/05/14 16:55:29 [INFO] encoded CSR
2020/05/14 16:55:29 [INFO] signed certificate with serial number 53655882604469890585145
8327888456464378001962019
2020/05/14 16:55:29 [INFO] generate received request
2020/05/14 16:55:29 [INFO] received CSR
2020/05/14 16:55:29 [INFO] generating key: rsa-2048
2020/05/14 16:55:29 [INFO] encoded CSR
2020/05/14 16:55:29 [INFO] signed certificate with serial number 63444134019371454709531
3283838003073752822095926
2020/05/14 16:55:29 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitabl
e for
websites. For more information see the Baseline Requirements for the Issuance and Manage
ment
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
2020/05/14 16:55:29 [INFO] generate received request
2020/05/14 16:55:29 [INFO] received CSR
2020/05/14 16:55:29 [INFO] generating key: rsa-2048
2020/05/14 16:55:30 [INFO] encoded CSR
2020/05/14 16:55:30 [INFO] signed certificate with serial number 52925014622285215862108
7101856320352532294647127
2020/05/14 16:55:30 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitabl
e for
websites. For more information see the Baseline Requirements for the Issuance and Manage
ment
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
2020/05/14 16:55:30 [INFO] generate received request
2020/05/14 16:55:30 [INFO] received CSR
2020/05/14 16:55:30 [INFO] generating key: rsa-2048
2020/05/14 16:55:30 [INFO] encoded CSR
2020/05/14 16:55:30 [INFO] signed certificate with serial number 27685644161984818928939
6829552650583118840259081
2020/05/14 16:55:30 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitabl
e for
websites. For more information see the Baseline Requirements for the Issuance and Manage
ment
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
[root@k8s-master01 k8s-cert]# ls *pem
admin-key.pem admin.pem ca-key.pem ca.pem kube-proxy-key.pem kube-proxy.pem ser
ver-key.pem server.pem
证书生成以后,需要将其中的 CA Server 相关证书拷贝到 Kubernetes 的工作目
录。创建/opt/kubernetes/{cfg,bin,ssl}目录 ,分别用于存放配置文件、可执行文件以及
证书文件。
[root@k8s-master01 ~]# mkdir /opt/kubernetes/{cfg,bin,ssl} -p
[root@k8s-master01 ~]# cd /k8s/k8s-cert/
[root@k8s-master01 k8s-cert]# cp ca*pem server*pem /opt/kubernetes/ssl/
[root@k8s-master01 k8s-cert]# ls /opt/kubernetes/ssl/
29 页 共 60 ca-key.pem ca.pem server-key.pem server.pem
2. 部署 APIServer 组件
上传并解压 Kubernetes 软件压缩包,将压缩包中的 kube-apiserverkubectl
kube-controller-manager kube-scheduler 组件的脚本文件拷贝到/opt/kubernetes/bin/
目录下。
[root@k8s-master01 ~]# cd /k8s/
[root@k8s-master01 k8s]# tar zxvf kubernetes-server-linux-amd64.tar.gz
[root@k8s-master01 k8s]# cd /k8s/kubernetes/server/bin/
[root@k8s-master01 bin]# cp kube-apiserver kubectl kube-controller-manager kube-sched
uler /opt/kubernetes/bin/
[root@k8s-master01 bin]# ls /opt/kubernetes/bin/
kube-apiserver kube-controller-manager kubectl kube-scheduler
/opt/kubernetes/cfg/目录中创建名为 token.csv token 文件,其本质就是创建一个
用户角色,可以理解为管理性的角色。Node 节点加入到群集当中也是通过这个角色去控制。
但是,在此之前需要通过 head 命令生成随机序列号作为 token 令牌。token 文件的主要内
容如下所示,其中:
ec2f26dd61227acb550290fd35bee0ca token 令牌;
Kubelet-bootstrap 为角色名;
100001 为角色 ID
"system:kubelet-bootstrap"为绑定的超级用户权限。
[root@k8s-master01 ~]# head -c 16 /dev/urandom | od -An -t x | tr -d ' '
ec2f26dd61227acb550290fd35bee0ca
[root@k8s-master01 ~]# vim /opt/kubernetes/cfg/token.csv
ec2f26dd61227acb550290fd35bee0ca,kubelet-bootstrap,10001,"system:kubelet-bootstrap"
k8s-master01 主机/opt/kubernetes/目录下的所有文件拷贝到 k8s-master02 主机中。
[root@k8s-master01 ~]# ls -R /opt/kubernetes/
/opt/kubernetes/:
bin cfg ssl
/opt/kubernetes/bin:
kube-apiserver kube-controller-manager kubectl kube-scheduler
/opt/kubernetes/cfg:
token.csv
/opt/kubernetes/ssl:
ca-key.pem ca.pem server-key.pem server.pem
[root@k8s-master01 ~]# scp -r /opt/kubernetes/ root@k8s-master02:/opt
运行 apiserver.sh 脚本,运行脚本需要填写两个位置参数。第一个位置参数是本地的 IP
地址,第二个位置参数是 API Server 群集列表。
[root@k8s-master01 ~]# cd /k8s/
[root@k8s-master01 k8s]# bash apiserver.sh 192.168.100.51 https://192.168.100.51:2379,htt
ps://192.168.100.52:2379,https://192.168.100.53:2379,https://192.168.100.54:2379
[root@k8s-master01 k8s]# ps aux | grep [k]ube
root
2955 112 15.7 384040 294644 ?
Ssl 13:33
0:15 /opt/kubernetes/bin/ku
be-apiserver --logtostderr=true --v=4 --etcd-servers=https://192.168.100.51:2379,https://192.168.
100.52:2379,https://192.168.100.53:2379,https://192.168.100.54:2379 --bind-address=192.168.10
0.51 --secure-port=6443 --advertise-address=192.168.100.51 --allow-privileged=true --service-cl
uster-ip-range=10.0.0.0/24 --enable-admission-plugins=NamespaceLifecycle,LimitRanger,Service
Account,ResourceQuota,NodeRestriction --authorization-mode=RBAC,Node --kubelet-https=true
--enable-bootstrap-token-auth --token-auth-file=/opt/kubernetes/cfg/token.csv --service-node-port
range=30000-50000 --tls-cert-file=/opt/kubernetes/ssl/server.pem --tls-private-key-file=/opt/kubern
etes/ssl/server-key.pem --client-ca-file=/opt/kubernetes/ssl/ca.pem --service-account-key-file=/opt/
kubernetes/ssl/ca-key.pem --etcd-cafile=/opt/etcd/ssl/ca.pem --etcd-certfile=/opt/etcd/ssl/server.pe
m --etcd-keyfile=/opt/etcd/ssl/server-key.pem
查看 k8s-master01 节点的 6443 安全端口以及 https 8080 端口是否启动。
[root@k8s-master01 ~]# netstat -ntap | grep 6443
tcp 0 0 192.168.100.51:6443 0.0.0.0:*
LISTEN
2955/kube-apiserver
tcp 0 0 192.168.100.51:6443 192.168.100.51:50376
ESTABLISHED 2955/kube-apiserver
tcp 0 0 192.168.100.51:50376 192.168.100.51:6443
ESTABLISHED 2955/kube-apiserver
[root@k8s-master01 ~]# netstat -ntap | grep 8080
tcp 0 0 127.0.0.1:8080
0.0.0.0:*
LISTEN
2955/kube-apiserver
/opt/kubernetes/cfg/工作目录下的 kube-apiserver 配置文件及其 token.csv 令牌文件
拷贝到 k8s-master02 主机上。在 k8s-master02 主机上修改 kube-apiserver 配置文件,将
bind-addressadvertise-address 地址修改为本机地址。
[root@k8s-master01 ~]# scp /opt/kubernetes/cfg/* root@k8s-master02:/opt/kubernetes/cfg/
[root@k8s-master02 ~]# vim /opt/kubernetes/cfg/kube-apiserver
......
//省略部分内容
--bind-address=192.168.100.52 \
--secure-port=6443 \
--advertise-address=192.168.100.52 \
......
//省略部分内容
k8s-master01 节点的 kube-apiserver.service 启动脚本拷贝到 k8s-master02 节点的
/usr/lib/systemd/system 目录下,并且在 k8s-master02 启动 API Server,并且查看端口信
息。
[root@k8s-master01 ~]# scp /usr/lib/systemd/system/kube-apiserver.service root@k8s-mas
ter02:/usr/lib/systemd/system/
[root@k8s-master02 ~]# systemctl start kube-apiserver && systemctl enable kube-apiserv
er
[root@k8s-master02 ~]# netstat -ntap | grep 6443
tcp 0 0 192.168.100.52:6443
0.0.0.0:*
LISTEN
2607/kube-apiserver
tcp 0 0 192.168.100.52:34140
192.168.100.52:6443
ESTABLISHED 2607/kube-apiserver
tcp 0 0 192.168.100.52:6443
192.168.100.52:34140 ESTABLISHED 2607/kube-apiserver
[root@k8s-master02 ~]# netstat -ntap | grep 8080
tcp
0
0 127.0.0.1:8080
0.0.0.0:*
LISTEN
2607/kube-apiserver
9.2.5 部署 Scheduler 组件
k8s-master01 节点,启动 Scheduler 服务。
[root@k8s-master01 ~]# cd /k8s/
[root@k8s-master01 k8s]# ./scheduler.sh 127.0.0.1
[root@k8s-master01 k8s]# ps aux |grep [k]ube
root
2955 4.4 13.0 403972 244340 ?
Ssl 13:33
0:53 /opt/kubernetes/bin/kub
e-apiserver --logtostderr=true --v=4 --etcd-servers=https://192.168.100.51:2379,https://192.168.1
00.52:2379,https://192.168.100.53:2379,https://192.168.100.54:2379 --bind-address=192.168.100.
51 --secure-port=6443 --advertise-address=192.168.100.51 --allow-privileged=true --service-clus
ter-ip-range=10.0.0.0/24 --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAc
count,ResourceQuota,NodeRestriction --authorization-mode=RBAC,Node --kubelet-https=true --e
nable-bootstrap-token-auth --token-auth-file=/opt/kubernetes/cfg/token.csv --service-node-port-ra
nge=30000-50000 --tls-cert-file=/opt/kubernetes/ssl/server.pem --tls-private-key-file=/opt/kubernet
es/ssl/server-key.pem --client-ca-file=/opt/kubernetes/ssl/ca.pem --service-account-key-file=/opt/
kubernetes/ssl/ca-key.pem --etcd-cafile=/opt/etcd/ssl/ca.pem --etcd-certfile=/opt/etcd/ssl/server.pe
m --etcd-keyfile=/opt/etcd/ssl/server-key.pem
root
3026 1.9 1.0 45620 20476 ?
Ssl 13:52
0:00 /opt/kubernetes/bin/kub
e-scheduler --logtostderr=true --v=4 --master=127.0.0.1:8080 --leader-elect
k8s-master01 节点的 kube-scheduler 配置文件与 kube-scheduler.service 启动脚本
拷贝到 k8s-master02 节点上,并且在 k8s-master02 启动 Scheduler
[root@k8s-master01 k8s]# scp /opt/kubernetes/cfg/kube-scheduler root@k8s-master02:/opt
/kubernetes/cfg/
[root@k8s-master01 k8s]# scp /usr/lib/systemd/system/kube-scheduler.service root@k8s-m
aster02:/usr/lib/systemd/system/
[root@k8s-master02 ~]# systemctl start kube-scheduler
[root@k8s-master02 ~]# systemctl enable kube-scheduler
9.2.6 部署 Controller-Manager 组件
k8s-master01 节点,启动 Controller-Manager 服务。
[root@k8s-master01 k8s]# ./controller-manager.sh 127.0.0.1
k8s-master01 节 点 的 kube-controller-manager 配 置 文 件 和
controller-manager.service 启动脚本拷贝到 k8s-master02 节点的/opt/kubernetes/cfg 目录
下,并且在 k8s-master02 节点上启动 Controller-Manager
[root@k8s-master01 k8s]# scp /opt/kubernetes/cfg/kube-controller-manager root@k8s-mast
er02:/opt/kubernetes/cfg/
[root@k8s-master01 k8s]# scp /usr/lib/systemd/system/kube-controller-manager.service ro
ot@k8s-master02:/usr/lib/systemd/system/
[root@k8s-master02 ~]# systemctl start kube-controller-manager
[root@k8s-master02 ~]# systemctl enable kube-controller-manager
k8s-master01 k8s-master02 节点上,查看各组件状态。
[root@k8s-master01 ~]# /opt/kubernetes/bin/kubectl get cs
NAME
STATUS
MESSAGE
ERROR
scheduler
Healthy
ok
controller-manager
Healthy
ok
etcd-0
Healthy
{"health":"true"}
etcd-1
Healthy
{"health":"true"}
etcd-2
Healthy
{"health":"true"}
etcd-3
Healthy
{"health":"true"}
[root@k8s-master02 ~]# /opt/kubernetes/bin/kubectl get cs
NAME
STATUS
MESSAGE
ERROR
scheduler
Healthy
ok
controller-manager
Healthy
ok
etcd-2
Healthy
{"health":"true"}
etcd-3
Healthy
{"health":"true"}
etcd-0
Healthy
{"health":"true"}
etcd-1
Healthy
{"health":"true"}
9.2.7 部署 Docker//在两台 node 节点上均需要操作
[root@k8s-node01 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
[root@k8s-node01 ~]# yum-config-manager --add-repo https://download.docker.com/linux/c
entos/docker-ce.repo
[root@k8s-node01 ~]# yum install docker-ce docker-ce-cli containerd.io -y
[root@k8s-node01 ~]# mkdir -p /etc/docker
[root@k8s-node01 ~]# tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://9cpn8tt6.mirror.aliyuncs.com"]
}
EOF
[root@k8s-node01 ~]# systemctl enable docker && systemctl start docker
9.2.8 部署 Flannel 网络组件
虽然在两台 node 节点上安装了 Docker,但是 Docker 运行的容器还需要网络组件
Flannel 的支持来实现彼此之间互联互通。
首先需要将分配的子网段写入到 Etcd 中,以便 Flannel 使用。网络中涉及到的路由如
何转发、源目地址如何封装等信息均存储到 Etcd 中。
通过执行以下的 etcdctl 命令,定义以逗号进行分割列出群集中的 IP 地址,set 指定网络
中的配置,对应的参数 etcd 是一个键值对,设置网段为 172.17.0.0/16,类型是 vxlan
执行完后,查看两台 node 节点的 docker0 地址,即 docker 网关的地址是否为
172.17.0.0/16 网段的地址。
[root@k8s-master01 ~]# cd /k8s/etcd-cert/
[root@k8s-master01 etcd-cert]# /opt/etcd/bin/etcdctl --ca-file=ca.pem --cert-file=server.pem -
-key-file=server-key.pem --endpoints="https://192.168.100.51:2379,https://192.168.100.52:23
79,https://192.168.100.53:2379,https://192.168.100.54:2379" set /coreos.com/network/config
36 页 共 60 '{"Network": "172.17.0.0/16","Backend": {"Type": "vxlan"}}'
{"Network": "172.17.0.0/16","Backend": {"Type": "vxlan"}}
[root@k8s-node01 ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:5f:ed:79:f9 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
查看写入的网络信息。
[root@k8s-master etcd-cert]# /opt/etcd/bin/etcdctl --ca-file=ca.pem --cert-file=server.pem --k
ey-file=server-key.pem --endpoints=https://192.168.100.51:2379,https://192.168.100.52:2379,
https://192.168.100.53:2379,https://192.168.100.54:2379 set /coreos.com/network/config '{"
Network": "172.17.0.0/16","Backend":{"Type": "vxlan"}}' get /coreos.com/network/config
{"Network": "172.17.0.0/16","Backend":{"Type": "vxlan"}}
flannel-v0.10.0-linux-amd64.tar.gz 软件包上传两个 node 节点服务器,并进行解压
缩。
//在两台 node 节点上均需要操作
[root@k8s-node01 ~]# tar xfvz flannel-v0.12.0-linux-amd64.tar.gz
flanneld
mk-docker-opts.sh
README.md
在两台 node 节点上创建 k8s 工作目录。将 flanneld 脚本和 mk-docker-opts.sh 脚本剪
切至 k8s 工作目录中。
[root@k8s-node01 ~]# mkdir /opt/kubernetes/{cfg,bin,ssl} -p
[root@k8s-node01 ~]# mv mk-docker-opts.sh flanneld /opt/kubernetes/bin/
将准备好的 flannel.sh 脚本拖至到两台 node 节点上,用以启动 Flannel 服务和创建配
置文件。其中:指定配置文件路径/opt/kubernetes/cfg/flanneldEtcd 的终端地址以及需要
认证的证书秘钥文件;指定启动脚本路径/usr/lib/systemd/system/flanneld.service,添加至
自定义系统服务中,交由系统统一管理。
[root@k8s-node01 ~]# cat flannel.sh
#!/bin/bash
ETCD_ENDPOINTS=${1:-"http://127.0.0.1:2379"}
cat <<EOF >/opt/kubernetes/cfg/flanneld
FLANNEL_OPTIONS="--etcd-endpoints=${ETCD_ENDPOINTS} \
-etcd-cafile=/opt/etcd/ssl/ca.pem \
-etcd-certfile=/opt/etcd/ssl/server.pem \
-etcd-keyfile=/opt/etcd/ssl/server-key.pem"
EOF
cat <<EOF >/usr/lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/opt/kubernetes/cfg/flanneld
ExecStart=/opt/kubernetes/bin/flanneld --ip-masq \$FLANNEL_OPTIONS
ExecStartPost=/opt/kubernetes/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /r
un/flannel/subnet.env
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable flanneld
systemctl restart flanneld
在两台 node 节点上执行 flannel.sh 脚本,并且$1 的位置变量为 k8s 的群集地址,所有
的注册都是存储在 Etcd 群集中。下面以 k8s-node01 主机为例,介绍具体操作。
[root@k8s-node01 ~]# bash flannel.sh https://192.168.100.51:2379,https://192.168.100.52:23
79,https://192.168.100.53,https://192.168.100.54:2379
两台 node 节点配置 Docker 连接 Flanneldocker.service 需要借助 Flannel 进行通信,
需要修改 docker.service。添加 EnvironmentFile=/run/flannel/subnet.env,借助 Flannel
子网进行通信以及添加$DOCKER_NETWORK_OPTIONS 网络参数。以上两个参数均是官
网要求。下面以 k8s-node01 主机为例进行操作演示。
[root@k8s-node01 ~]# vim /usr/lib/systemd/system/docker.service
......
//省略部分内容
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
EnvironmentFile=/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS -H fd:// --containerd=/run/contain
erd/containerd.sock
......
//省略部分内容
在两台 node 节点上查看使用的子网地址分别为 172.17.88.1/24 172.17.44.1/24bip
是指定启动时的子网。
[root@k8s-node01 ~]# cat /run/flannel/subnet.env
DOCKER_OPT_BIP="--bip=172.17.88.1/24"
DOCKER_OPT_IPMASQ="--ip-masq=false"
DOCKER_OPT_MTU="--mtu=1450"
DOCKER_NETWORK_OPTIONS=" --bip=172.17.88.1/24 --ip-masq=false --mtu=1450"
[root@k8s-node02 ~]# cat /run/flannel/subnet.env
DOCKER_OPT_BIP="--bip=172.17.44.1/24"
DOCKER_OPT_IPMASQ="--ip-masq=false"
DOCKER_OPT_MTU="--mtu=1450"DOCKER_NETWORK_OPTIONS=" --bip=172.17.44.1/24 --ip-masq=false --mtu=1450"
在两台 node 节点上修改完启动脚本之后,需要重新启动 Docker 服务。分别查看两台
node 节点的 docker0 网卡信息。
[root@k8s-node01 ~]# systemctl daemon-reload && systemctl restart docker
[root@k8s-node01 ~]# ip addr show docker0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DO
WN
link/ether 02:42:2b:83:a7:27 brd ff:ff:ff:ff:ff:ff
inet 172.17.88.1/24 brd 172.17.88.255 scope global docker0
valid_lft forever preferred_lft forever
[root@k8s-node02 ~]# systemctl daemon-reload && systemctl restart docker
[root@k8s-node02 ~]# ip addr show docker0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DO
WN
link/ether 02:42:e6:a7:68:3a brd ff:ff:ff:ff:ff:ff
inet 172.17.44.1/24 brd 172.17.44.255 scope global docker0
valid_lft forever preferred_lft forever
在两台 node 节点上分别运行 busybox 容器。(busybox 是一个集成了三百多个常用
Linux 命令和工具的软件工具箱,在本案例中用于测试)。
进入容器内部查看 k8s-node01 节点的地址是 172.17.88.2k8s-node02 节点的地址是
172.17.44.2。与/run/flannel/subnet.env 文件中看到的子网信息处于同一个网段。
接着再通过 ping 命令测试,如果 k8s-node02 容器能 ping k8s-node01 容器的 IP
址就代表两个独立的容器可以互通,说明 Flannel 组件搭建成功。
[root@k8s-node01 ~]# docker pull busybox
[root@k8s-node01 ~]# docker run -it busybox /bin/sh
/ # ipaddr show eth0
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:ac:11:58:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.88.2/24 brd 172.17.88.255 scope global eth0
valid_lft forever preferred_lft forever
[root@k8s-node02 ~]# docker pull busybox
[root@k8s-node02 ~]# docker run -it busybox /bin/sh
/ # ipaddr show eth0
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:ac:11:5b:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.91.2/24 brd 172.17.91.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping -c 4 172.17.88.2
PING 172.17.88.2 (172.17.88.2): 56 data bytes
64 bytes from 172.17.88.2: seq=0 ttl=62 time=1.372 ms
64 bytes from 172.17.88.2: seq=1 ttl=62 time=0.506 ms
64 bytes from 172.17.88.2: seq=2 ttl=62 time=0.416 ms
64 bytes from 172.17.88.2: seq=3 ttl=62 time=0.403 ms
--- 172.17.88.2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.403/0.674/1.372 ms
9.2.9 部署 kubeconfig 配置
k8s-master01 节点上将 kubelet kube-proxy 执行脚本拷贝到两台 node 节点上。
[root@k8s-master01 ~]# cd /k8s/kubernetes/server/bin/
[root@k8s-master01 bin]# scp kubelet kube-proxy root@k8s-node01:/opt/kubernetes/bin/
[root@k8s-master01 bin]# scp kubelet kube-proxy root@k8s-node02:/opt/kubernetes/bin/
node.zip 上传至两台 node 节点,并解压 node.zip,可获得 proxy.sh kubelet.sh
两个执行脚本。以 k8s-node01 为例进行操作演示。
[root@k8s-node01 ~]# unzip node.zip
Archive: node.zip
inflating: proxy.sh
inflating: kubelet.sh
k8s-master01 节点上创建 kubeconfig 工作目录。将 kubeconfig.sh 脚本上传至当前
目录 k8s/kubeconfig/下,此脚本中包含有创建 TLS Bootstrapping Token、创建 kubelet
bootstrapping kubeconfig、设置集群参数、设置客户端认证参数、设置上下文参数、设置
默认上下文、创建 kube-proxy kubeconfig 文件。
查看序列号将其拷贝到客户端认证参数。更新 kubeconfig.sh 脚本的 token 值。
[root@k8s-master01 ~]# mkdir /k8s/kubeconfig
[root@k8s-master01 ~]# cd /k8s/kubeconfig/
[root@k8s-master01 kubeconfig]# ls
kubeconfig.sh
[root@k8s-master01 kubeconfig]# cat /opt/kubernetes/cfg/token.csv
ec2f26dd61227acb550290fd35bee0ca,kubelet-bootstrap,10001,"system:kubelet-bootstrap"
[root@k8s-master01 kubeconfig]# vim kubeconfig.sh
# 创建 TLS Bootstrapping Token
#BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
BOOTSTRAP_TOKEN=5fb8f1bc1711d0a35c09e92b9a0d6603
//更新 token
cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
#----------------------
APISERVER=$1
SSL_DIR=$2
# 创建 kubelet bootstrapping kubeconfig
export KUBE_APISERVER="https://$APISERVER:6443"
# 设置集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=$SSL_DIR/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=bootstrap.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap \
--token=0fb61c46f8991b718eb38d27b605b008 \
--kubeconfig=bootstrap.kubeconfig# 设置上下文参数
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=bootstrap.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
#----------------------
# 创建 kube-proxy kubeconfig 文件
kubectl config set-cluster kubernetes \
--certificate-authority=$SSL_DIR/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy \
--client-certificate=$SSL_DIR/kube-proxy.pem \
--client-key=$SSL_DIR/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
-kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
为 了 便 于 识 别 在 k8s-master01 k8s-master02 节 点 上 声 明 路 径 export
PATH=$PATH:/opt/kubernetes/bin/到环境变量中。
[root@k8s-master01 ~]# echo "export PATH=$PATH:/opt/kubernetes/bin/" >> /etc/profile
[root@k8s-master01 ~]# source /etc/profile
[root@k8s-master02 ~]# echo "export PATH=$PATH:/opt/kubernetes/bin/" >> /etc/profile
[root@k8s-master02 ~]# source /etc/profile
kubeconfig.sh 重 命名 为 kubeconfig , 执行 kubeconfig 脚 本。 使用 bash 执 行
kubeconfig,第一个参数是当前 APIServer IP,它会写入整个配置当中;第二个参数指
定 证 书 kubenets 的 证 书 位 置 。 执 行 完 成 以 后 会 生 成 bootstrap.kubeconfig
kube-proxy.kubeconfig 两个文件。
[root@k8s-master01 ~]# cd /k8s/kubeconfig/
[root@k8s-master01 kubeconfig]# mv kubeconfig.sh kubeconfig
[root@k8s-master01 kubeconfig]# bash kubeconfig 192.168.100.51 /k8s/k8s-cert/
Cluster "kubernetes" set.
User "kubelet-bootstrap" set.
Context "default" created.
Switched to context "default".
Cluster "kubernetes" set.
User "kube-proxy" set.
Context "default" created.
Switched to context "default".
[root@k8s-master01 kubeconfig]# ls
bootstrap.kubeconfig kubeconfig kube-proxy.kubeconfig token.csv
bootstrap.kubeconfig kube-proxy.kubeconfig 文件拷贝到两台 node 节点上。
[root@k8s-master01 kubeconfig]# scp bootstrap.kubeconfig kube-proxy.kubeconfig root@k
8s-node01:/opt/kubernetes/cfg/
[root@k8s-master01 kubeconfig]# scp bootstrap.kubeconfig kube-proxy.kubeconfig root@k
8s-node02:/opt/kubernetes/cfg/
创建 bootstrap 角色,并赋予权限。用于连接 API Server 请求签名(关键)。查看
k8s-node01 节点的 bootstrap.kubeconfigKubelet 在启动的时候如果想加入群集中,需要
请求申请 API Server 请求签名。kubeconfig 的作用是指明如果想要加入群集,需要通过哪
一个地址、端口才能申请到所需要的证书。
[root@k8s-master01 kubeconfig]# kubectl create clusterrolebinding kubelet-bootstrap --clu
sterrole=system:node-bootstrapper --user=kubelet-bootstrap
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created
[root@k8s-node01 ~]# cat /opt/kubernetes/cfg/bootstrap.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR2akNDQX
......
//省略部分内容
server: https://192.168.100.51:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubelet-bootstrap
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: kubelet-bootstrap
user:
token: ec2f26dd61227acb550290fd35bee0c
9.2.10 部署 Kubelet 组件
在两台 node 节点上,执行 kubelet 脚本,并通过 ps 命令查看服务启动情况。kublet
启动之后会自动联系 API Server 进行证书申请。在 k8s-master01 节点上通过 get csr 命令
查看是否收到请求申请。当看到处于 Pending 状态时,即为等待集群给该节点颁发证书。
[root@k8s-node01 ~]# bash kubelet.sh 192.168.100.53
[root@k8s-node01 ~]# ps aux | grep [k]ube
root
3398 0.1 1.0 398020 20060 ?
Ssl 13:34
0:05 /opt/kubernetes/bin/flan
neld --ip-masq --etcd-endpoints=https://192.168.100.51:2379,https://192.168.100.52:2379,https://
192.168.100.53,https://192.168.100.54:2379 -etcd-cafile=/opt/etcd/ssl/ca.pem -etcd-certfile=/opt/e
tcd/ssl/server.pem -etcd-keyfile=/opt/etcd/ssl/server-key.pem
[root@k8s-node02 ~]# bash kubelet.sh 192.168.100.54
[root@k8s-node02 ~]# ps aux | grep [k]ube
root
3505 0.1 1.1 463556 22124 ?
Ssl 13:33
0:03 /opt/kubernetes/bin/flan
neld --ip-masq --etcd-endpoints=https://192.168.100.51:2379,https://192.168.100.52:2379,https://
192.168.100.53,https://192.168.100.54:2379 -etcd-cafile=/opt/etcd/ssl/ca.pem -etcd-certfile=/opt/e
tcd/ssl/server.pem -etcd-keyfile=/opt/etcd/ssl/server-key.pem
[root@k8s-master01 kubeconfig]# kubectl get csr
NAME
AGE
REQUESTOR
CONDITION
node-csr-iAOH54APqisMFO24nBBYfK51CejiMJ8Tt_Q9gmy7A4A
39s
kubelet-bootstrap
P
ending
node-csr-kZPYjpQY1rPDR_L19Gq-R-zvG4D1adEOiSqaWu53ENc
44s
kubelet-bootstrap
Pending
k8s-master01 节点颁发证书给两台 node 节点。通过 get csr 命令可以查看到证书已经
颁发。使用 get node 查看,两台 node 节点都已经加入到了群集中。
[root@k8s-master01 kubeconfig]# kubectl certificate approve node-csr-iAOH54APqisMFO24
nBBYfK51CejiMJ8Tt_Q9gmy7A4A
[root@k8s-master01 kubeconfig]# kubectl certificate approve node-csr-kZPYjpQY1rPDR_L1
9Gq-R-zvG4D1adEOiSqaWu53ENc
[root@k8s-master01 kubeconfig]# kubectl get csr
NAME
AGE
REQUESTOR
CONDITION
node-csr-iAOH54APqisMFO24nBBYfK51CejiMJ8Tt_Q9gmy7A4A
3m25s
kubelet-bootstrap
Approved,Issued
node-csr-kZPYjpQY1rPDR_L19Gq-R-zvG4D1adEOiSqaWu53ENc
3m30s
kubelet-bootstrap
Approved,Issued
[root@k8s-master01 kubeconfig]# kubectl get node
NAME
STATUS
ROLES
AGE
VERSION
192.168.100.53
Ready
<none>
75s
v1.12.3
192.168.100.54
Ready
<none>
108s
v1.12.3
9.2.11 部署 Kube-Proxy 组件
在两台 node 节点上执行 proxy.sh 脚本。
[root@k8s-node01 ~]# bash proxy.sh 192.168.100.53
[root@k8s-node02 ~]# bash proxy.sh 192.168.100.54
[root@k8s-node02 ~]# systemctl status kube-proxy.service
● kube-proxy.service - Kubernetes Proxy
Loaded: loaded (/usr/lib/systemd/system/kube-proxy.service; enabled; vendor preset: disabl
ed)
Active: active (running) since 2020-05-19 17:28:03 CST; 32s ago
......
//省略部分内容
9.2.12 部署 Nginx 反向代理
安装配置 Nginx 服务。
//lb01lb02 主机上均执行以下操作
[root@k8s-lb01 ~]# yum -y install epel-release
[root@k8s-lb01 ~]# yum -y install nginx
[root@k8s-lb01 ~]# vim /etc/nginx/nginx.conf
//配置四层转发负载均衡
.....
//省略部分内容
events {
worker_connections 1024;
}
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_
bytes_sent';
access_log /var/log/nginx/k8s-access.log main;
upstream k8s-apiserver {
server 192.168.100.51:6443;
server 192.168.100.52:6443;
}
server {
listen 6443;
proxy_pass k8s-apiserver;
}
}
http {
......
//省略部分内容
[root@k8s-lb01 ~]# nginx -t
[root@k8s-lb01 ~]# systemctl start nginx && systemctl enable nginx
修改两台 Nginx 节点的首页,以示区分,并且浏览器中访问两台 LB 节点,访问结果如
9.7、图 9.8 所示。
[root@k8s-lb01 ~]# echo "This is Master Server" > /usr/share/nginx/html/index.html
[root@k8s-lb02 ~]# echo "This is Backup Server" > /usr/share/nginx/html/index.html
9.7 访问 k8s-lb01 节点的 Nginx 测试默认首页
9.8 访问 k8s-lb02 节点的 Nginx 测试默认首页
9.2.13 部署 Keepalived
安装并配置 Keepalived 服务。
[root@k8s-lb01 ~]# yum install keepalived -y
//lb01lb02 主机上均执行以下操作
[root@k8s-lb01 ~]# vim /etc/keepalived/keepalived.conf
.......
//省略部分内容
vrrp_script check_nginx {
script "/etc/nginx/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
interface ens37
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.100.200/24
}
track_script {
check_nginx
}
}
[root@k8s-lb02~]# vim /etc/keepalived/keepalived.conf
.......
//省略部分内容
vrrp_script check_nginx {
script "/etc/nginx/check_nginx.sh"
}
vrrp_instance VI_1 {
state BACKUP
interface ens37
virtual_router_id 51
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass 1111}
virtual_ipaddress {
192.168.100.200/24
}
track_script {
check_nginx
}
}
在两台 LB 节点上创建触发脚本。统计数据进行比对,值为 0 的时候,关闭 Keepalived
服务。
//lb01lb02 主机上均执行以下操作
[root@k8s-lb01 ~]# vim /etc/nginx/check_nginx.sh
count=$(ps -ef |grep nginx |egrep -cv "grep|$$")
if [ "$count" -eq 0 ];then
systemctl stop keepalived
fi
[root@k8s-lb01 ~]# chmod +x /etc/nginx/check_nginx.sh
[root@k8s-lb01 ~]# systemctl start keepalived && systemctl enable keepalived
查看网卡信息,可以看到 k8s-lb01 节点上有漂移地址 192.168.100.200/24,而 k8s-lb02
节点上没有漂移地址。
[root@k8s-lb01 ~]# ip addr show ens37
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP ql
en 1000
link/ether 00:0c:29:6e:d6:16 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.55/24 brd 192.168.100.255 scope global ens37
valid_lft forever preferred_lft forever
inet 192.168.100.200/24 scope global secondary ens37
valid_lft forever preferred_lft forever
.......
//省略部分内容
[root@k8s-lb02 ~]# ip addr show ens37
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP ql
en 1000
link/ether 00:0c:29:73:27:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.56/24 brd 192.168.100.255 scope global ens37
valid_lft forever preferred_lft forever
inet6 fe80::b58f:f6aa:fa03:81bd/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
验证故障转移切换:首先将 k8s-lb01 节点上的 Nginx 服务关闭,查看 IP 信息可以看出
k8s-lb01 的漂移 IP 已经不存在,Keepalived 服务也关闭了;查看 k8s-lb02 IP 信息,漂
IP 地址已经绑定在 k8s-lb02 节点上。此时再将 k8s-lb01 Nginx Keepalived 服务开
启,漂移 IP 地址就会重新 k8s-lb01 节点上。
[root@k8s-lb01 ~]# systemctl stop nginx
[root@k8s-lb01 ~]# ps aux |grep [k]eepalived
[root@k8s-lb01 ~]# ip addr show ens37
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP ql
en 1000
link/ether 00:0c:29:6e:d6:16 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.55/24 brd 192.168.100.255 scope global ens37
valid_lft forever preferred_lft forever
inet6 fe80::b58f:f6aa:fa03:81bd/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
[root@k8s-lb02 ~]# ip addr show ens37
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP ql
en 1000
link/ether 00:0c:29:73:27:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.56/24 brd 192.168.100.255 scope global ens37
valid_lft forever preferred_lft forever
inet 192.168.100.200/24 scope global secondary ens37
.......
//省略部分内容
[root@k8s-lb01 ~]# systemctl start nginx
[root@k8s-lb01 ~]# systemctl start keepalived
[root@k8s-lb01 ~]# ip addr show ens37
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP ql
en 1000
link/ether 00:0c:29:6e:d6:16 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.55/24 brd 192.168.100.255 scope global ens37
valid_lft forever preferred_lft forever
inet 192.168.100.200/24 scope global secondary ens37
.......
//省略部分内容
修 改 两 台 node 节 点 上 的 bootstrap.kubeconfig kubelet.kubeconfig
kube-proxy.kubeconfig 配置文件,这三个文件中指向 API Server IP 地址,将此地址更新
VIP 地址。
//node01node02 主机上均执行以下操作
[root@k8s-node01 ~]# cd /opt/kubernetes/cfg/
[root@k8s-node01 cfg]# vim bootstrap.kubeconfig
.......
//省略部分内容
server: https://192.168.100.200:6443
.......
//省略部分内容
[root@k8s-node01 cfg]# vim kubelet.kubeconfig
.......
//省略部分内容
server: https://192.168.100.200:6443
.......
//省略部分内容
[root@k8s-node01 cfg]# vim kube-proxy.kubeconfig
.......
//省略部分内容
server: https://192.168.100.200:6443
.......
//省略部分内容
[root@k8s-node01 cfg]# grep 200 *
bootstrap.kubeconfig:
server: https://192.168.100.200:6443
kubelet.kubeconfig:
server: https://192.168.100.200:6443
kube-proxy.kubeconfig:
server: https://192.168.100.200:6443
重启两台 node 节点相关服务。
//node01node02 主机上均执行以下操作
[root@k8s-node01 cfg]# systemctl restart kubelet
[root@k8s-node01 cfg]# systemctl restart kube-proxy
k8s-lb01 节点上动态查看 Nginx 的访问日志。从日志中可以看出了负载均衡已经实现。
[root@k8s-lb01 ~]# tail -f /var/log/nginx/k8s-access.log
192.168.100.54 192.168.100.51:6443 - [19/May/2020:19:30:50 +0800] 200 1119
192.168.100.54 192.168.100.52:6443 - [19/May/2020:19:30:50 +0800] 200 1121
192.168.100.53 192.168.100.51:6443 - [19/May/2020:19:30:52 +0800] 200 1121
192.168.100.53 192.168.100.51:6443 - [19/May/2020:19:30:52 +0800] 200 1120
k8s-master01 节点上创建 Pod,使用的镜像是 Nginx
[root@k8s-master01 ~]# kubectl run nginx --image=nginx
kubectl run --generator=deployment/apps.v1beta1 is DEPRECATED and will be removed in a
future version. Use kubectl create instead.
deployment.apps/nginx created
[root@k8s-master01 ~]# kubectl get pod
NAME
READY
STATUS
RESTARTS
AGE
nginx-dbddb74b8-q496b
1/1
Running
0
7m6s
开启查看日志权限。
[root@k8s-master01 ~]# kubectl create clusterrolebinding cluster-system-anonymous --clu
sterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/cluster-system-anonymous created
通过-o wide 参数,输出整个网络状态。可以查看此容器的 IP 172.17.44.2,容器是
放在 IP 地址为 192.168.100.54 node 节点中。
[root@k8s-master01 ~]# kubectl get pods -o wide
NAME
READY
STATUS
RESTARTS
AGE
IP
NO
DE
NOMINATED NODE
nginx-dbddb74b8-q496b
1/1
Running
0
8m56s
172.17.44.2
192.168.1
00.54
<none>
[root@k8s-node02 ~]# ip addr show flannel.1
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNK
NOWN
link/ether 66:67:24:14:ce:21 brd ff:ff:ff:ff:ff:ff
inet 172.17.44.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
使用 curl 访问 Pod 容器地址 172.17.44.2。访问日志会产生信息,回到 k8s-master01
节点中查看日志信息。并且查看容器。其他的 node 节点也能访问到。
[root@k8s-node01 ~]# curl 172.17.44.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-master01 ~]# kubectl logs nginx-dbddb74b8-q496b
172.17.44.0 - - [19/May/2020:11:49:22 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2090797.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极限的性质【上】《用Manim可视化》

通过前面的极限的定义&#xff0c;现在是计算极限的时候了。然而&#xff0c;在此之前&#xff0c;我们需要一些极限的性质&#xff0c;这将使我们的工作变得简单一些。我们先来看看这些。 极限的性质&#xff1a; 1.常数对极限的影响 1.首先&#xff0c;我们假设和存在&…

Tengine框架之配置表的Luban转换与加载

对于一个游戏来说&#xff0c;配置表是必不可少的&#xff0c;而且文件数量还比较多&#xff0c;像活动、任务成就、图鉴、地图、皮肤、本地化语言、技能等等之类。配置表一般使用Excel格式&#xff0c;便于策划来配置。但游戏中一般使用txt/json/xml/二进制格式文件&#xff0…

碎碎念之Android中CPU架构arm-v8a、arm-v7a、x86

0 碎碎念 之前写博客都是为了复习基础知识&#xff0c;不过好像也忘得很快hh。 以后估计会写点感兴趣的自己碎碎念&#xff0c;缓解下emo的心情。&#xff08;不像之前的博客&#xff0c;这些博客不准备复现也不贴代码所以不一定对&#xff0c; 仅供个人参考 &#xff09; 现在…

Python酷库之旅-第三方库Pandas(111)

目录 一、用法精讲 486、pandas.DataFrame.count方法 486-1、语法 486-2、参数 486-3、功能 486-4、返回值 486-5、说明 486-6、用法 486-6-1、数据准备 486-6-2、代码示例 486-6-3、结果输出 487、pandas.DataFrame.cov方法 487-1、语法 487-2、参数 487-3、功…

鸿蒙项目签名配置

配置需要以下四个文件&#xff1a; 1. p12文件 2. csr文件 3. cer文件 打开AGC平台 点击申请调试证书 4. p7b文件 最后在项目中进行配置 配置项目的module.json5中

selenium使用指南

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 概述 selenium是网页应用中最流行的自动化测试工具&#xff0c;可以用来做自动化测试或者浏览器爬虫等。官网地址为&#xff1a;相对于另外一款web自动化测试工…

Linux安装Hadoop(单机版)详细教程

目录 一、JDK安装 1、下载JDK安装包 2、解压下载的JDK安装包 3、移动并重命名JDK包 4、配置Java环境变量 5、验证安装是否成功 二、Hadoop安装 1、下载Hadoop安装包 2、解压Hadoop安装包 3、配置Hadoop环境变量 4、修改配置文件 5、验证Hadoop是否安装成功 三&…

C# 开发环境搭建(Avalonia UI、Blazor Web UI、Web API 应用示例)

文章目录 C# 文档.NET SDK 下载安装 .NET SDK安装完验证VS Code 配置C# 开发插件settings.json WPF UI 框架Avalonia UI 框架创建 Avalonia 项目Avalonia 官方示例Avalonia 桌面 UI 库 Blazor Web UI 框架创建应用项目结构 ASP.NET Core 控制器创建 Web APIdotnet 命令dotnet n…

探索Unity与C#的无限潜能:从新手到高手的编程之旅

在数字创意与技术创新交织的今天&#xff0c;Unity游戏引擎凭借其强大的跨平台能力和灵活的编程接口&#xff0c;成为了无数开发者心中的首选。而C#&#xff0c;作为Unity的官方脚本语言&#xff0c;更是以其面向对象的特性和丰富的库支持&#xff0c;为游戏开发注入了无限可能…

克隆技术在代码溯源和复用及变更分析中的应用

摘要&#xff1a; 克隆技术已在软件代码溯源分析领域得到广泛应用&#xff0c;而轩宇软件成分分析系统基于溯源分析和同源分析技术&#xff0c;通过先进的特征向量提取、相似性匹配、高效检索引擎等多项技术&#xff0c;帮助企业高效识别代码来源、评估自主可控率&#xff0c;…

【数据结构】关于哈希表内部原理,你到底了解多少???(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解关于哈希表的内部实现原理&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;http://t.csdnimg.cn/7D225 &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 目录 &a…

安嘉空间:智慧科技守护空间健康

在当今社会&#xff0c;随着人们对生活质量要求的不断提升&#xff0c;室内环境的健康与安全问题日益受到重视。安嘉空间&#xff0c;作为一家致力于人居健康空间技术研发的高科技企业&#xff0c;以其独创的技术和卓越的产品&#xff0c;为广大用户提供了一套全面的空间健康解…

进销存自动统计单据表格——未来之窗行业应用跨平台架构

一、代码 function 未来之窗_人工智能_计算单据(objbyclass,obj目标显示,obj目标值){console.log("未来之窗_人工智能_计算单据"objbyclass);var 计算结果0;$("."objbyclass).each(function(){var 输入框值 $(this).val();console.log("输入框值"…

去中心化(Decentralization)

去中心化&#xff08;Decentralization) 并不是一个新概念&#xff0c;它已在战略、管理和政府中使用了很长时间。去中心化的基本思想是将控制权和权限分配给组织的外围&#xff0c;而不是由一个中心机构完全控制组织。这种配置为组织带来了许多好处&#xff0c;例如提高了效率…

欧洲用户对中国应用程序的感知:一个复杂的挂毯

在数字时代&#xff0c;中国应用程序迅速在全球范围内占有一席之地&#xff0c;吸引了全球用户的注意力和好奇心。在欧洲&#xff0c;这些应用程序引发了人们的兴趣、阴谋和担忧&#xff0c;不同国家和人口统计数据的看法差异很大。 对中国应用程序感兴趣的主要驱动力之一是它…

git命令使用详情

目录 一. 安装教程 二. git配置 1. 查看git配置参数 2. 设置邮箱和用户名 3. SSH配置 4. 配置git远程库公钥 5. 编码设置 三. git 提交流程 1. 整体操作流程图 2. Git仓库包含5个区域 3. 下载、提交、更新命令 3.1. 下载 3.2. 提交 3.3. 更新&#xff08;两种方式…

无人机 PX4 飞控 | ROS应用层开发:基础代码框架构建

无人机 PX4 飞控 | ROS应用层开发&#xff1a;基础代码框架构建 基础代码框架构建文件建立代码基本构建测试 基础代码框架构建 本篇博客拟在构建一个 无人机 PX4 飞控 ROS应用层开发 的 基础代码框架。 其中包含了基础类文件、类头文件、main主函数文件&#xff0c;及其编译所…

数据结构-c/c++实现栈(详解,栈容量可以动态增长)

一.栈的基本介绍 栈是一种只能够在一端进行插入和删除的顺序表。如下图 空栈&#xff1a;表示不含任何元素的栈 栈顶&#xff1a;表示允许进行插入和删除元素的一端 栈底&#xff1a;表示不允许进行插入和删除元素的一端 即栈是一种后进先出的线性表数据结构 二.栈的常见操…

Redis高级---面试总结之内存过期策略及其淘汰策略

目前已更新系列&#xff1a; 当前&#xff1a;Redis高级---面试总结之内存过期策略及其淘汰策略 并发编程之----线程池ThreadPoolExecutor,Excutors的使用及其工作原理 Redis高级----主从、哨兵、分片、脑裂原理-CSDN博客 计算机网络--面试知识总结一 计算机网络-----面试知…

【深度学习】yolov8的微调

yolov8的集成度太高了&#xff0c;除了config的哪些参数以外&#xff0c;需要更精细的微调。 比如这里&#xff1a; https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/tuner.py 应用场景&#xff0c;交通标志的向左转&#xff0c;向右转之类的&#x…