1、基础设施的迭代
App可以是apache、nginx、mysql等
容器运行时(容器管理引擎、CRI)有哪些:docker、containerd、podman
- 传统模式是1台物理机跑多个App,但是这样不安全,例如apache首页被劫持后,有可能获取同一物理机上的数据库,造成数据泄露
- 虚拟化模式是将1个物理机分割成多个虚拟机,虚拟机间彼此隔离,每个虚拟机上跑各自的应用,如前端业务放到虚拟机1,后端业务放到虚拟机2,安全性最高
- 由于虚拟化模式中每个虚拟机的操作系统还要占物理机一部分资源,如果是万台虚拟机其操作系统占用的资源将十分庞大,因此出现了容器化部署,只需要一个操作系统即可运行多个容器,并且容器之间也有数据隔离,安全性虽然不如虚拟化模式但也够用,至少优于传统模式
2、Kubernetes的优势
- 服务发现和负载均衡:仅使用kuberctl命令create一个service即可将负载均衡部署至Kubernetes集群
- 存储编排(添加任何本地或云服务器)
- 自动部署和回滚
- 自动分配CPU/内存资源-弹性伸缩
- 自我修复(需要时启动新容器):由于容器启动是秒级的,因此可以轻易的做决定新创一个容器,例如一个容器进程卡住了直接干掉这个容器新创一个新容器去运行业务
- Secret(安全相关信息)和配置管理
- 大型规模的支持(每个节点的Pod数量不超过110;节点数不超过5000;Pod总数不超过150000;容器总数不超过300000)
- 开源
3、Kubernetes架构
- 基础概念
kubectl:命令行工具
scheduler:调度器
replication controller(control manager):控制管理器(集群管家),作用是例如一个容器死了,集群管家会杀死这个容器并启动一个新容器顶替它
etcd:键值对数据库
container:容器
kubelet:节点代理,Pod 管家
kube proxy:节点网络代理,Service 网络组件
- 运作流程
master节点运作流程:例如kubectl发送创建容器请求给api server,api server去审核有无权限等,没问题就将请求的任务保存到etcd中。scheduler会定期的通过api server去获取当前需要运行的任务有没有跟节点绑定,如果有任务未跟节点绑定就把挑选一个最合适的节点绑定这个任务。replication controller定期检查集群运行的状态是不是和预期相符
node节点运作流程:kubelet监听api server,去监听当前节点有没有容器需要创建、删除,如果监听到了创建、删除请求,kubelet会调用容器运行时去创建、删除容器。kube proxy监听api server,去监听当前节点有没有防火墙规则、负载均衡规则需要去创建
真实环境会有多个master节点和node节点
4、Kubernetes组件、插件、附件
- 组件
Kubernetes API Server
Kubernetes Scheduler
Controller Manager
Kube-proxy
- 插件
CoreDNS:给Kubernetes内部提供一个私有的域名解析服务
Ingress Controller:提供七层的负载均衡功能。Kubernetes官方本身有提供四层的负载均衡叫service,如果需要七层的就需要安装这个插件
Docker:容器运行时其中一种,还有containerd、podman等
- 附件
Prometheus:普罗米修斯,提供监控能力
Dashboard:仪表盘组件
Federation:提供多Kubernetes集群跨空间管理能力
5、Pod概念
#Nginx、redis、Pause、php-fpm都是container(容器)。Pause是Pod中的基座容器,其他三个是业务应用的容器(生产环境一般一个Pod只放一个业务应用)
#Pod是K8s中最小执行单元,即容器组
#Nginx、redis、php-fpm容器和Pause容器共享名字空间(Network、PID、IPC)
Pause作用:
1.Pod内部第一个启动的容器
2.初始化网络栈
3.挂载需要的存储卷
4.回收僵尸进程:Pause必须作为1号进程才能有权回收后续的其他进程。例如:1号进程下有个master进程,master下有多个子进程,如果master进程挂了它下面的子进程就成了僵尸进程无所事事,此时就需要1号进程回收它们
6、基于docker模拟一个Pod
6.1、新建虚拟机
1、下载镜像
Rocky-9.8-x86_64-minimal.iso
华为云下载:mirrors.huaweicloud.com/rockylinux/…
百度网盘下载:
2、安装虚拟机
虚拟机配置:2个2核的cpu、4g内存、100g存储、2个网卡
按照下图分区
去掉勾选锁定root,勾选允许root远程登陆
6.2、配置环境
1、配置ipv4网络,将auto(动态网络)改为manual(静态网络),并增加一个IP和子网掩码
vi /etc/NetworkManager/system-connections/ens160.nmconnection
method=manual
address1=192.168.66.11/24
#仅主机网卡的子网也设置为66网段,保xshell可以和192.168.66.11连接
2、重启网络(Rocky Linux 8开始就已经弃用network改用NetworkManager管理网络)
systemctl restart NetworkManager
3、配置YUM仓库
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak \
/etc/yum.repos.d/rocky-*.repo
4、获取YUM仓库缓存(Rocky Linux使用dnf替代了Centos的yum命令)
dnf makecache
5、配置防火墙,卸载firewalld,安装iptables、vim等常用工具
systemctl stop firewalld
systemctl disable firewalld
dnf -y install iptables-services vim unzip wget
systemctl start iptables
6、清空防火墙规则
iptables -F
service iptables save
systemctl enable iptables
7、配置selinux
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
在内核级别更新selinux标记:
grubby --update-kernel ALL --args selinux=0
8、设置系统时区
timedatectl set-timezone Asia/Shanghai
9、将当前状态的虚拟机做一个快照,后面会经常用这个快照创建虚拟机
6.3、安装docker
1、安装epel源、bridge的utils
dnf install -y epel-release
dnf install -y bridge-utils
2、加载模块:所有经过网桥的流量,必须要通过防火墙进行处理
modprobe br_netfilter
3、将这个模块添加到开机自启的文件当中
echo 'br_netfilter' >>/etc/modules-load.d/bridge.conf
4、在IPV4环境下,所有网桥的流量,都必须要被防火墙所回调
echo 'net.bridge.bridge-nf-call-iptables=1' >>/etc/sysctl.conf
5、在IPv6环境下,所有网桥的流量,都必须要被防火墙所回调
echo 'net.bridge.bridge-nf-call-ip6tables=1' >>/etc/sysctl.conf
6、开启路由转发
echo 'net.ipv4.ip_forward=1' >>/etc/sysctl.conf
7、加载 /etc/sysctl.conf 里的内核参数配置,让修改的内核参数立即生效
sysctl -p
8、添加 docker-ce yum源(阿里源)
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
9、切换阿里源
sed -i 's#download.docker.com#mirrors.aliyun.com/docker-ce#g' /etc/yum.repos.d/docker-ce.repo
10、安装 docker-ce
dnf -y install docker-ce
11、配置 Docker(daemon文件),使用时候记得删备注
cat > /etc/docker/daemon.json <<EOF
{
"default-ipc-mode": "shareable", #指定当前的IPC模式是允许共享的
"data-root": "/data/docker", #指定当前的docker的根目录(不指定默认在/var/lib/docker)
"exec-opts": ["native.cgroupdriver=systemd"], #使用systemd作为Cgroup驱动(K8s推荐)
"log-driver": "json-file", #指定日志驱动为json-file,保存为json格式
"log-opts": {
"max-size": "100m", #单个日志文件最大100M
"max-file": "100" #日志最多保留100个
},
"insecure-registries": ["harbor.vorn.com"], #私有仓库(按需修改)
"registry-mirrors": [ #镜像加速源
"https://docker-0.unsee.tech",
"https://docker.1panel.live",
"https://docker.kejilion.pro",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://hub.littlediary.cn",
"https://proxy.1panel.live",
"https://image.cloudlayer.icu",
"https://docker.1panel.top",
"https://docker.anye.in",
"https://docker-0.unsee.tech",
"https://hub.rat.dev",
"https://hub3.nat.tf",
"https://docker.1ms.run",
"https://func.ink",
"https://a.ussh.net",
"https://docker.hlmirror.com",
"https://lispy.org",
"https://docker.yomansunter.com",
"https://docker.xuanyuan.me",
"https://docker.mybacc.com",
"https://dytt.online",
"https://docker.xiaogenban1993.com",
"https://dockerpull.cn",
"https://dockerpull.pw",
"https://docker-mirror.aigc2d.com",
"https://docker.sunzishaokao.com",
"https://docker.melikeme.cn",
"https://docker.m.daocloud.io"]
}
EOF
12、创建docker service管理目录
mkdir -p /etc/systemd/system/docker.service.d
13、重启docker服务并开机自启动
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
6.4、启动pause容器
由于国内访问不了k8s.gcr.io,使用docker load把 tar 包里的镜像解压到本地机器。
#百度网盘下载pause.tar: pan.baidu.com/s/1LvmpjWK8…
[root@localhost ~]# docker load -i pause.tar
Loaded image: k8s.gcr.io/pause:3.1
[root@localhost ~]# docker image list
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
k8s.gcr.io/pause:3.1 0968e31df05b 1.49MB 746kB
启动容器,容器名pause,-d放到后台运行,将容器80端口映射到物理机8080端口,指定镜像为pause镜像
docker run -d --name pause -p 8080:80 k8s.gcr.io/pause:3.1
6.5、启动nginx容器
创建一个nginx配置文件,使用的时候记得删备注
cat<<EOF>>nginx.conf
error_log stderr; #把所有错误日志直接打印到进程的标准错误流,不写入磁盘文件(K8s会统一收集容器标准输出的日志因此容器中部署nginx一般不需要将日志持久化到容器内部)
events {worker_connections 1024;} #最大连接数1024
http{ #定义了一个http的区域
access_log /dev/stdout combined; #日志访问路径
server { #定义了一个主机区域
listen 80 default_server; #监听80端口
server_name example.com www.example.com; #当前的域名为 example.com
location / { #定义根区域
proxy_pass http://127.0.0.1:2368; #反向代理到回环接口的2368端口上
}
}
}
EOF
把当前路径下的nginx.conf文件挂载到容器/etc/nginx/nginx下;跟pause容器共享网络,ipc,pid;使用nginx镜像
docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause nginx
6.6、启动ghost容器
创建数据目录并授权,ghost需要写入权限
mkdir /opt/ghost
chmod -R 777 /opt/ghost
ghost镜像是由php编写的个人博客系统,启动ghost容器,跟pause共享网络、IPC、 PID,挂载数据目录(持久化博客内容),开发模式(默认监听2368端口)
docker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause -v /opt/ghost:/var/lib/ghost/content -e NODE_ENV=development ghost:latest
Tips:如果关机或者重启docker服务会导致以上三个容器停止运行,docker ps -a可以看到已停止的容器,这时候docker start 容器名 即可启动这个容器
在浏览器中访问http://192.168.66.11:8080(主机 IP: 映射端口),看到 ghost 的默认页面,说明 nginx 成功代理到 ghost(通过localhost:2368)
6.7、总结
nginx和ghost都通过共享pause网络、IPC、PID访问的好处有两个:
1、Pause 容器仅做网络共享,几乎不会崩溃;如果用 nginx 作为共享锚点,nginx 故障会导致整个 Pod 网络失效。
2、Pause 作为1号进程,可回收其他容器的僵尸进程;而 nginx 不具备此功能,会导致资源泄露。
7、k8s网络
7.1、基本概述
Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在。但是国内大部分使用的阿里云、自建机房等并不在GCE中运行业务,在私有云里搭建Kubernetes集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的Docker容器之间的互相访问先打通,然后运行Kubernetes。
7.2、k8s网络模型原则
在不使用网络地址转换(NAT)的情况下,集群中的Pod能够与任意其他Pod进行通信
在不使用网络地址转换(NAT)的情况下,在集群节点上运行的程序能与同一节点上的任何Pod进行通信
每个Pod都有自己的IP地址(IP-per-Pod),并且任意其他Pod都可以通过相同的这个地址访问它
7.3、CNI(容器网络接口)
CNI = Container Network Interface,容器网络接口,是 CNCF 制定的一套容器网络标准接口规范(不是具体软件,是协议)。借助CNI标准,Kubernetes可以实现容器网络问题的解决。通过插件化的方式来集成各种网络插件,实现集群内部网络相互通信,只要实现CNI标准中定义的核心接口操作(ADD:将容器添加到网络;DEL:从网络中删除一个容器;CHECK:检查容器的网络是否符合预期等)。CNI插件通常聚焦在容器到容器的网络通信。
Podman、CRI-O、ContainerD都是CRI(容器运行时),它们借助libcni(CNI的库)去描绘一个json文件,这个json文件告诉我们这个网络插件应该如何配置使用,然后调用到对应的Plugin插件库中的某些插件去实现Pod与Pod、容器与容器网络间的通讯。这就是CNI要做的事情,CNI 只是接口标准,本身不实现网络;真正干活的是各个 CNI 插件。
Kubernetes 节点默认的CNI 插件路径为/opt/cni/bin
CNI通过JSON格式的配置文件来描述网络配置,当需要设置容器网络时,由容器运行时负责执行CNI插件,并通过CNI插件的标准输入(stdin)来传递配置文件信息,通过标准输出(stdout)接收插件的执行结果。从网络插件功能区分CNI插件可以分为五类:
- Main 主插件:创建网络接口(网卡)
创建具体网络设备。具体有bridge:网桥设备,连接container(容器)和host(主机);ipvlan:为容器增加 ipvlan网卡;loopback:IO设备:macvlan:为容器创建一个MAC 地址:ptp:创建一对Veth Pair(虚拟以太网对);vlan:分配一个vlan设备;host-device:将已存在的设备移入容器内
- IPAM 地址插件:分配管理 IP 地址
负责分配IP地址,(dhcp:容器向DHCP服务器发起请求,给Pod发放或回收IP地址;host-local:使用预先配置的IP地址段来进行分配;static:为容器分配一个静态IPv4/IPv6地址,主要用于debug)
- Meta 元插件:对已有网卡追加增强功能(限流、端口映射)
其他功能的插件(tuning:通过sysctl 调整网络设备参数;portmap:通过iptables配置端口映射;bandwidth:使用 Token Bucket Filter 来限流;sbr:为网卡设置source based outing;firewall:通过iptables给容器网络的进出流量进行限制)
- Windows插件:专门用于Windows 平台的CNI插件
主要让k8s能够接入windows环境,主流插件有win-bridge:实现windows网桥的创建;win-overlay :实现windows下的扁平化网络
- 第三方完整 CNI 方案插件:Calico/Cilium/Flannel 整套集群网络
第三方开源的网络插件众多,每个组件都有各自的优点及适应的场景,难以形成统一的标准组件,常用有Flannel、Calico、Cilium、OVN网络插件
下图以一个Flannel网络插件为例,展示创建Pod过程中网络插件的创建过程:
步骤①由master节点的scheduler调度
步骤③指在一个沙箱里去完成Pod网络环境的初始化
k8s功能说明:
网络模型:封装或未封装。
路由分发:一种外部网关协议,用于在互联网上交换路由和可达性信息。BGP可以帮助进行跨集群pod之间的网络。此功能对于未封装的CNI网络插件是必须的,并且通常由BGP完成。如果你想构建跨网段拆分的集群,路由分发是一个很好的功能。(通过BGP协议将当前的每一个Pod的地址信息制作成对应的路由表实现跨节点通讯)
网络策略:Kubernetes提供了强制执行规则的功能,这些规则决定了哪些service 可以使用网络策略进行相互通信。这是从Kubernetes1.7起稳定的功能,可以与某些网络插件一起使用。(例如所有Pod之间默认是连通的,但是有些安全场景下不想让aPod和bPod通信就得通过网络策略限制)
网格:允许在不同的Kubernetes集群间进行service之间的网络通信。
外部数据存储:具有此功能的CNI网络插件需要一个外部数据存储来存储数据。
加密:允许加密和安全的网络控制和数据平面。
Ingress/Egress策略:允许你管理Kubernetes 和非Kubernetes通信的路由控制。
underlay network(非封装网络)
现实的物理基础层网络设备
underlay就是数据中心场景的基础物理设施,保证任何两个点路由可达,其中包含了传统的网络技术overlay network(封装网络)
一个基于物理网络之上构建的逻辑网络
overlay是在网络技术领域指的是一种网络架构上叠加的虚拟化技术模式
Overlay网络技术多种多样,一般采用TRILL、VxLan、GRE、NVGRE等隧道技术总结:
非封装网络就是A直接一层一层路由的方式去和B通信
封装网络就是A的数据报文再包一层报文,然后与B通信
封装网络下10.42.0.2与10.42.1.2通过一层一层路由通信
封装网络下10.42.0.2与10.42.1.2通信
7.4、目前最主流的网络插件-calico
Calico是一个纯三层的虚拟网络,它没有复用docker的docker0网桥,而是自己实现的,calico网络可以不对数据包进行额外封装,不需要NAT和端口映射
calico架构:
Felix:
管理网络接口、编写路由、编写ACL(访问控制列表)、报告状态
bird (BGP Client):
BGP Client将通过BGP协议广播告诉剩余calico节点,从而实现网络互通
confd:
通过监听 etcd以了解BGP配置和全局默认值的更改。Confd根据ETCD中数据的更新,动态生成BIRD配置文件。当配置文件更改时,confd触发BIRD重新加载新文件。
7.5、calico网络模式-VXLAN
VXLAN,即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network)
基于三层的”二层“通信,层即vxlan包封装在udp数据包中,要求udp在k8s节点间三层可达;二层即 vxlan封包的源mac 地址和目的mac 地址是自己的 vxlan设备mac 和对端 vxlan设备mac实现通讯。
#负载:原始报文本身,承载了真实数据段
总结:
数据包封包:封包,在vxlan设备上将pod发来的数据包源、目的mac替换为本机 vxlan网卡和对端节点vxlan网卡的mac。外层udp目的ip地址根据路由和对端vxlan的mac查fdb表(mac地址与IP的对应关系表)获取
优势:只要k8s节点间三层互通,可以跨网段,对主机网关路由没有特殊要求。各个node节点通过vxlan设备实现基于三层的”二层”互通,三层即 vxlan包封装在udp数据包中,要求udp在k8s节点间三层可达;二层即vxlan封包的源 mac地址和目的mac地址是自己的vxlan设备mac 和对端 vxlan设备mac
缺点:需要进行vxlan的数据包封包和解包会存在一定的性能损耗
配置参数:
启动参数:
验证是否配置成功:
7.6、calico网络模式-IPIP
Linux原生内核支持
IPIP隧道的工作原理是将源主机的IP数据包封装在一个新的IP数据包中,新的IP数据包的目的地址是隧道的另一端。在隧道的另一端,接收方将解封装原始IP数据包,并将其传递到目标主机。IPIP隧道可以在不同的网络之间建立连接,例如在IPv4网络和IPv6网络之间建立连接。
#tunl0是IPIP隧道,在这里对数据报文封包,然后另一个tunl0解封三层头部放到pod2中
数据包结构:
payload:原始报文
TCP:tcp标记
IP:ip头
New IP Header:新IP头。src是自己的物理网卡ip,dst是对方主机的物理网卡ip。因此这个数据报文就可以在三层的网络里从A到B端,B端收到后把New IP Header拆掉,再把剩余的包进行本机的路由,找到对方的目的。
总结:
数据包封包:封包,在tunl0设备上将pod发来的数据包的mac层去掉,留下ip层封包。外层数据包目的ip地址根据路由得到。
优点:只要k8s节点间三层互通,可以跨网段,对主机网关路由没有特殊要求。
缺点:需要进行IPIP的数据包封包和解包会存在一定的性能损耗
配置参数:
验证是否配置成功:
7.7、calico网络模式-BGP
边界网关协议(Border Gateway Protocol,BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单IP,BGP机房的优点:服务器只需要设置一个IP地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。
总结:
数据包封包:不需要进行数据包封包
优点:不用封包解包,通过BGP协议可实现pod网络在主机间的三层可达
缺点:跨网段时,配置较为复杂网络要求较高,主机网关路由也需要充当BGPSpeaker。
配置参数:
验证是否配置成功:
使用ifconfig去看calico有没有vxlan、ipip,没有就是bgp。还可以通过查询当前bgp同步的信息来确认目前是bgp模式
7.8、三种网络模式如何选择
vxlan借助vxlan这种技术实现二层的三层可达(二层的封包的三层可达),这种特性可以很好的在只需要三层可达的网络中建立关联
IPIP模式通过linux内核IPIP隧道的工作方式去实现的这么一种封包,它是可以跨IPV4 IPV6网络的。VXLAN和IPIP都需要封包,因此相对来说性能较弱
BGP模式是不需要封包的,性能更好,但是如果跨多个广播域的话需要进行复杂的网络配置打通整个BGP网络
如果对性能不敏感可以选择VXLAN、IPIP。如果对性能敏感并且当前环境的路由器是可以进行物理路由器配置的是可以选择BGP的
8、k8s安装
8.1、基础网络结构
首先将RL-1恢复到Justinstall快照状态,再克隆RL-2、RL-3
RL-1:192.168.66.11
RL-2:192.168.66.12
RL-3:192.168.66.13
四个内网网卡在同一个广播域内,是互相连通的,可以用vmware的仅主机模式模拟
外网网卡可以用vmware的NAT模式模拟
一主两从的结构资源分配:
Master节点:CPU >= 2核;MEM >= 4g;NIC >= 1个;DISK = 100g
Node节点:CPU >= 1核;MEM >= 1g;NIC >= 1个;DISK = 100g
8.2、安装k8s
安装k8s有两种方式,本次使用kubeadm:
kubeadm或基于kubeadm的自动化工具:组件通过容器化方式运行
二进制安装:组件变成系统进程的方式运行
1、安装ikuai模拟路由器
下载ikuai镜像:www.ikuai8.com/
本次下载32位的固件(资源占用小),生产环境一般用64位
或者这里下载:pan.baidu.com/s/1AQFhl5yF…
创建ikuai虚拟机:
然后按ESC退出,再按q退出,最后按q锁定控制台
输入http://192.168.66.200进入ikuai路由器配置页面,用户名/密码:admin/admin
2、配置网络、安装docker
RL-1:
#配置仅主机网卡,增加网关和dns
vim /etc/NetworkManager/system-connections/ens160.nmconnection
address1=192.168.66.11/24,192.168.66.200
dns=114.114.114.114;8.8.8.8
RL-2:
#配置仅主机网卡,增加网关和dns
vim /etc/NetworkManager/system-connections/ens160.nmconnection
address1=192.168.66.12/24,192.168.66.200
dns=114.114.114.114;8.8.8.8
RL-3:
#配置仅主机网卡,增加网关和dns
vim /etc/NetworkManager/system-connections/ens160.nmconnection
address1=192.168.66.13/24,192.168.66.200
dns=114.114.114.114;8.8.8.8
RL-1、RL-2、RL-3:
#禁用NAT网卡
vim /etc/NetworkManager/system-connections/ens192.nmconnection
autoconnect=false
#调用nmcli重启设备和连接配置
nmcli d d ens192
nmcli d r ens160
nmcli c r ens160
#关闭swap分区,Kubernetes 要求关闭交换分区,否则会导致容器内存分配不稳定,影响调度决策
swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab
# 验证(swap行均为0)
free -m
RL-1:
#修改主机名
hostnamectl set-hostname k8s-master01
RL-2:
#修改主机名
hostnamectl set-hostname k8s-node01
RL-3:
#修改主机名
hostnamectl set-hostname k8s-node02
RL-1、RL-2、RL-3:
#增加三行域名解析
vim /etc/hosts
192.168.66.11 k8s-master01 m1
192.168.66.12 k8s-node01 n1
192.168.66.13 k8s-node02 n2
#安装ipvsadm(用于Service的负载均衡)
dnf install ipvsadm -y
# 开启IPv4转发(容器跨节点通信需要)
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
sysctl -p #输出net.ipv4.ip_forward = 1即为成功
#安装epel源、bridge的utils(网桥工具)
dnf install -y epel-release
dnf install -y bridge-utils
#加载br_netfilter模块:所有经过网桥的流量,必须要通过防火墙进行处理
modprobe br_netfilter
#将这个模块添加到开机自启的文件当中
echo 'br_netfilter' >>/etc/modules-load.d/bridge.conf
#在IPV4环境下,所有网桥的流量,都必须要被防火墙所回调
echo 'net.bridge.bridge-nf-call-iptables=1' >>/etc/sysctl.conf
#在IPv6环境下,所有网桥的流量,都必须要被防火墙所回调
echo 'net.bridge.bridge-nf-call-ip6tables=1' >>/etc/sysctl.conf
#加载/etc/sysctl.conf里的内核参数配置,让修改的内核参数立即生效
sysctl -p
#添加 docker-ce yum源(阿里源)
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#切换阿里源
sed -i 's#download.docker.com#mirrors.aliyun.com/docker-ce#g' /etc/yum.repos.d/docker-ce.repo
#安装 docker-ce
dnf -y install docker-ce
#配置 Docker(daemon文件),使用时候记得删备注
cat > /etc/docker/daemon.json <<EOF
{
"data-root": "/data/docker", #指定当前的docker的根目录(不指定默认在/var/lib/docker)
"exec-opts": ["native.cgroupdriver=systemd"], #使用systemd作为Cgroup驱动(K8s推荐)
"log-driver": "json-file", #指定日志驱动为json-file,保存为json格式
"log-opts": {
"max-size": "100m", #单个日志文件最大100M
"max-file": "100" #日志最多保留100个
},
"insecure-registries": ["harbor.vorn.com"], #私有仓库(按需修改)
"registry-mirrors": [ #镜像加速源
"https://docker-0.unsee.tech",
"https://docker.1panel.live",
"https://docker.kejilion.pro",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://hub.littlediary.cn",
"https://proxy.1panel.live",
"https://image.cloudlayer.icu",
"https://docker.1panel.top",
"https://docker.anye.in",
"https://docker-0.unsee.tech",
"https://hub.rat.dev",
"https://hub3.nat.tf",
"https://docker.1ms.run",
"https://func.ink",
"https://a.ussh.net",
"https://docker.hlmirror.com",
"https://lispy.org",
"https://docker.yomansunter.com",
"https://docker.xuanyuan.me",
"https://docker.mybacc.com",
"https://dytt.online",
"https://docker.xiaogenban1993.com",
"https://dockerpull.cn",
"https://dockerpull.pw",
"https://docker-mirror.aigc2d.com",
"https://docker.sunzishaokao.com",
"https://docker.melikeme.cn",
"https://docker.m.daocloud.io"]
}
EOF
#创建docker管理目录
mkdir -p /etc/systemd/system/docker.service.d
#重启docker服务并开机自启动
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
在三个节点ping百度,可以在路由器上查询到三台机器流量
3、安装cri-dockerd
RL-1、Rl-2、RL-3:
k8s要想使用Docker创建容器还需要安装cri‑dockerd(外部shim垫片)和Docker通信,k8s 1.24之前是内置这个垫片的,之后不再内置,需要手动安装。像其他的容器运行时如Podman、Containerd、RKT则不需要这个垫片即可直接被k8s调用来创容器。
#下载cri-dockerd
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.9/cri-dockerd-0.3.9.amd64.tgz
或者从这下载:https://pan.baidu.com/s/1X_0RGZ_JG6My9LGUdJfl-w?pwd=dj95
#解压并安装
tar -zxvf cri-dockerd-0.3.9.amd64.tgz
cp cri-dockerd/cri-dockerd /usr/bin/
chmod +x /usr/bin/cri-dockerd # 添加执行权限
#配置 cri-docker 服务
#ExecStart是开机引导,其中定义了使用CNI网络插件,使用的pause版本为3.8
cat <<"EOF" > /usr/lib/systemd/system/cri-docker.service
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.8
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
#添加 cri-docker 套接字
cat <<"EOF" > /usr/lib/systemd/system/cri-docker.socket
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service
[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
#启动 cri-docker 对应服务
systemctl daemon-reload
systemctl enable cri-docker
systemctl start cri-docker
systemctl is-active cri-docker #查看存活状态
4、安装kubeadm、kubelet、kubectl
RL-1、Rl-2、RL-3:
由于无法访问k8s官网,这里不使用添加YUM源的方式安装kubeadm,这里下载好了安装包,手动安装即可:pan.baidu.com/s/1HenSECAZ…
tar -zxvf kubernetes-1.29.2-150500.1.1.tar.gz
cd kubernetes-1.29.2-150500.1.1
ls #从这些安装包可以看到本次安装的k8s版本为1.29.2
conntrack-tools-1.4.7-2.el9.x86_64.rpm
cri-tools-1.29.0-150500.1.1.x86_64.rpm
kubeadm-1.29.2-150500.1.1.x86_64.rpm
kubectl-1.29.2-150500.1.1.x86_64.rpm
kubelet-1.29.2-150500.1.1.x86_64.rpm
kubernetes-cni-1.3.0-150500.1.1.x86_64.rpm
libnetfilter_cthelper-1.0.0-22.el9.x86_64.rpm
libnetfilter_cttimeout-1.0.0-19.el9.x86_64.rpm
libnetfilter_queue-1.0.5-1.el9.x86_64.rpm
socat-1.7.4.1-5.el9.x86_64.rpm
dnf -y install *
systemctl enable kubelet.service #目前还没有编写配置文件,仅设置开机自启
为什么需要以系统进程的方式安装kubelet并设置自启动:kubelet会把k8s的系统组件(api‑server /scheduler/controller‑manager)启动起来并保证持续运行(挂掉也会自动拉起)
RL-1:
#初始化主节点。apiserver:指定主服务器地址,image:指定镜像仓库,从哪里下组件所需的容器镜像,version:指定k8s版本,service-cidr:网络范围,pod-network:pod网络范围,ignore:跳过前置错误检测,cri:指定cri套接字在哪
kubeadm init --apiserver-advertise-address=192.168.66.11 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version 1.29.2 --service-cidr=10.10.0.0/12 --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors=all --cri-socket unix:///var/run/cri-dockerd.sock
[init] Using Kubernetes version: v1.29.2 #k8s版本
[preflight] Running pre-flight checks #前置检查
[preflight] Pulling images required for setting up a Kubernetes cluster #为k8s集群下载镜像
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull' #也可以通过'kubeadm config images pull'命令将镜像提前下载好
W0928 16:04:22.666571 6878 checks.go:835] detected that the sandbox image "registry.aliyuncs.com/google_containers/pause:3.8" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.aliyuncs.com/google_containers/pause:3.9" as the CRI sandbox image. #告诉sandbox指定的pause镜像为阿里云的镜像
[certs] Using certificateDir folder "/etc/kubernetes/pki" #由于各组件通信用的HTTPS,这里是存放证书的目录,(apiserver.crt、apiserver‑kubelet‑client、etcd server/peer、各个 *.conf 里面客户端证书):默认有效期只有 1 年
[certs] Generating "ca" certificate and key #生成证书
[certs] Generating "apiserver" certificate and key #生成证书
[certs] apiserver serving cert is signed for DNS names [k8s-master01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.0.0.1 192.168.66.11] #设置DNS域名
[certs] Generating "apiserver-kubelet-client" certificate and key #生成证书
[certs] Generating "front-proxy-ca" certificate and key #生成证书
[certs] Generating "front-proxy-client" certificate and key #生成证书
[certs] Generating "etcd/ca" certificate and key #生成证书
[certs] Generating "etcd/server" certificate and key #生成证书
[certs] etcd/server serving cert is signed for DNS names [k8s-master01 localhost] and IPs [192.168.66.11 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key #生成证书
[certs] etcd/peer serving cert is signed for DNS names [k8s-master01 localhost] and IPs [192.168.66.11 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key #生成证书
[certs] Generating "apiserver-etcd-client" certificate and key #生成证书
[certs] Generating "sa" key and public key #生成证书
[kubeconfig] Using kubeconfig folder "/etc/kubernetes" #/etc/kubernetes下的admin.conf是当前集群连接的钥匙(管理员)还有超级管理员super-admin.conf。其他的controller-manager.conf、kubelet.conf、scheduler.conf都是各个组件的授权文件,相当于各自的钥匙
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "super-admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" #清单文件目录,从此目录去启动一些静态Pod。检索此目录下有没有yaml文件,并把这些yaml文件启动为对应的组件,这些组件启动之后就形成了k8s集群,这就是开机自启的原理。这底下的文件有:etcd.yaml、kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" #写入kubelet环境变量到这个文件,具体是:kubelet基于kubeadm的一些子选项,如当前cri接口在哪,指定pod的pause容器用的什么镜像
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s #等待控制器端从/etc/kubernetes/manifests目录启动,预计需要4分钟
[apiclient] All control plane components are healthy after 11.005625 seconds #实际使用11秒
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace #创建ConfigMap存储kubeadm-config配置文件参数
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster #创建ConfigMap存储kubelet-config配置文件参数
[upload-certs] Skipping phase. Please see --upload-certs #RBAC授权,安全相关
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers] #RBAC授权,安全相关
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule] #RBAC授权,安全相关
[bootstrap-token] Using token: sfhsur.a1ctioq2jvf1diwf #RBAC授权,安全相关
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles #RBAC授权,安全相关
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes #RBAC授权,安全相关
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials #RBAC授权,安全相关
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token #RBAC授权,安全相关
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster #RBAC授权,安全相关
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace #RBAC授权,安全相关
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key #RBAC授权,安全相关
[addons] Applied essential addon: CoreDNS #添加CoreDNS插件,提供DNS域名解析服务
[addons] Applied essential addon: kube-proxy #添加kube-proxy插件,监听api server、将当前防火墙规则和负载均衡规则在本节点落地
Your Kubernetes control-plane has initialized successfully! #控制器端初始化完成
To start using your cluster, you need to run the following as a regular user: #想要用集群得执行下面操作
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/ #官方对几个常见网络插件(CNI插件)做了一个简单描述
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.66.11:6443 --token sfhsur.a1ctioq2jvf1diwf \
--discovery-token-ca-cert-hash sha256:5c85a79e3e8fc50092ceea8dd3d27c6950fc942107dbc24f262757fd5555d208
#如果work token过期了可以重新申请
kubeadm token create --print-join-command
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master01 kubernetes-1.29.2-150500.1.1]# kubectl get node #查看集群状态,可以看到只有一个节点
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane 7m28s v1.29.2
RL-2:
kubeadm join 192.168.66.11:6443 --token sfhsur.a1ctioq2jvf1diwf \
--discovery-token-ca-cert-hash sha256:5c85a79e3e8fc50092ceea8dd3d27c6950fc942107dbc24f262757fd5555d208 \
--cri-socket unix:///var/run/cri-dockerd.sock
RL-3:
kubeadm join 192.168.66.11:6443 --token sfhsur.a1ctioq2jvf1diwf \
--discovery-token-ca-cert-hash sha256:5c85a79e3e8fc50092ceea8dd3d27c6950fc942107dbc24f262757fd5555d208 \
--cri-socket unix:///var/run/cri-dockerd.sock
RL-1:
[root@k8s-master01 kubernetes-1.29.2-150500.1.1]# kubectl get node #现在可以查到三个节点,由于还没安装网络插件calico,因此都是未就绪状态
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane 20m v1.29.2
k8s-node01 NotReady <none> 13s v1.29.2
k8s-node02 NotReady <none> 3s v1.29.2
5、部署网络插件
RL-1、RL-2、RL-3:
下载calico:
或者在这下载:
unzip calico.zip
cd calico
ls
calicoctl-linux-amd64 #calico命令行可执行文件,本次暂不使用
calicoctl.yaml #命令行配置的部署文件,本次暂不使用
calico-images.tar.gz #calico运行所需要的所有镜像,需解压后使用
calico-typha.yaml #部署文件
tar -zxvf calico-images.tar.gz
cd calico-images
ls
calico-cni-v3.26.3.tar
calico-kube-controllers-v3.26.3.tar
calico-node-v3.26.3.tar
calico-typha-v3.26.3.tar
#将这些镜像导入本地镜像仓库
docker load -i calico-cni-v3.26.3.tar
docker load -i calico-kube-controllers-v3.26.3.tar
docker load -i calico-node-v3.26.3.tar
docker load -i calico-typha-v3.26.3.tar
RL-1:
vim calico-typha.yaml #关闭IPIP,使用BGP网络模式,指定Pod网段,改成和初始化主节点时定义的pod网段一样。解压出的yaml文件已经改好了直接用即可
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
- name: CALICO_IPV4POOL_IPIP
value: "Off"
#把这个部署文件应用到当前的集群上
kubectl apply -f calico-typha.yaml
#查询节点状态都变成了就绪状态
[root@k8s-master01 calico]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane 122m v1.29.2
k8s-node01 Ready <none> 102m v1.29.2
k8s-node02 Ready <none> 101m v1.29.2
#查询所有pod,可以看到calico已经在整个集群网络中了
[root@k8s-master01 calico]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-558d465845-6pt2d 1/1 Running 0 2m33s
kube-system calico-node-gnjwj 1/1 Running 0 2m33s
kube-system calico-node-jr469 1/1 Running 0 2m33s
kube-system calico-node-zm9vn 1/1 Running 0 2m33s
kube-system calico-typha-5b56944f9b-clshm 1/1 Running 0 2m33s
kube-system coredns-857d9ff4c9-7pf86 1/1 Running 0 123m
kube-system coredns-857d9ff4c9-bkv4s 1/1 Running 0 123m
kube-system etcd-k8s-master01 1/1 Running 0 123m
kube-system kube-apiserver-k8s-master01 1/1 Running 0 123m
kube-system kube-controller-manager-k8s-master01 1/1 Running 0 123m
kube-system kube-proxy-45hl2 1/1 Running 0 103m
kube-system kube-proxy-6lkss 1/1 Running 0 103m
kube-system kube-proxy-z6fp8 1/1 Running 0 123m
kube-system kube-scheduler-k8s-master01 1/1 Running 0 123m