文章目录
- 一, 集群拓扑
- 二,架构图
- 三,前置准备
- 1.环境准备
- 1.1操作系统初始化配置
- (1)关闭防火墙
- (2)关闭selinux
- (3)关闭swap
- (4)根据规划设置主机名
- (5)在master添加hosts
- (6)调整内核参数
- (7)时间同步
- 四,Etcd 集群部署
- 1.etcd简介
- 2.签发证书
- 2.1 master01节点
- (1)准备cfssl证书生成工具
- (2)生成Etcd证书
- (3)创建CA证书、etcd服务器证书以及私钥目录
- (4) 把etcd-v3.4.9-linux-amd64.tar.gz 上传到 /opt/k8s 目录,解压
- (5)创建用于存放 etcd 配置文件,命令文件,证书的目录
- (6)启动etcd.sh
- (5)查看etcd进程
- (6)将etcd证书文件、命令文件和服务管理文件全部拷贝到192.168.88.30 ,192.168.88.40 etcd集群节点
- 2.2 node01节点
- (1)修改etcd相关证书文件、命令文件和服务管理文件
- (2)启动etcd
- 2.3 node02节点
- (1)修改etcd相关证书文件、命令文件和服务管理文件
- (2)启动etcd
- 3.验证查看集群
- 4.etcd 安装步骤
- 五,Master 组件部署
- 1.master01节点
- 1.1master组件签发证书
- (1)上传 master.zip 和 k8s-cert.sh 到 /opt/k8s 目录,解压 master.zip并给所有.sh结尾的文件执行权限
- (2)创建kubernetes工作目录,生成CA证书、相关组件的证书和私钥的目录
- (3)复制CA证书、apiserver相关证书和私钥到 /opt/kubernetes/ssl 目录
- (4)将kubernetes-server-linux-amd64.tar.gz放到到 /opt/k8s/ 目录,并解压
- (5)复制master组件的关键命令文件到 /opt/kubernetes/bin目录,并建软链接
- (6)创建 bootstrap token 认证文件
- (7)开启 apiserver 服务
- (8) 查看进程,端口6443
- (9)启动 scheduler
- (10)启动 controller-manager
- (12)使用kubectl工具查看当前集群组件状态
- (13)master 组件安装步骤
- 六,Node 组件部署
- 1.node01,node02节点
- 1.1创建Kubernetes工作目录
- 1.2上传 node.zip 到 /opt目录并解压,给kubelet服务脚本和kube-proxy服务执行权限
- 2.master01节点
- 2.1把master01节点上的kubelet、kube-proxy发到node01和node02
- 2.2上传生成kubele文件加入集群引导kubeconfig文件和kube-proxy.kubeconfig文件
- 2.3 把bootstrap.kubeconfig、kube-proxy.kubeconfig 发到 node01和node02
- 2.4 RBAC授权
- 2.5kubelet
- 3.node节点
- 3.1启动 kubelet
- (1)node01节点
- 4.master01节点
- 4.1通过csr请求
- (1)node01请求
- (1)node02请求
- 5.node节点
- 5.1加载ipvs模块
- (1)node01节点
- (2)node02节点
- 5.2启动proxy服务
- (1)node01节点
- (2)node02节点
- 七,CNI网络组件部署
- 1.kubernetes三种网络
- 1.1pod之间如何通信
- (1)Pod 内容器与容器之间的通信
- (2)同一个 Node 内 Pod 之间的通信
- (3)不同 Node 上 Pod 之间的通信
- 2.Kubernetes 网络的基本要求
- 2.1Overlay Network
- 3.Flannel
- 3.1Flannel UDP 模式的工作原理
- 3.2ETCD 与Flannel
- 3.2Flannel VXLAN 模式
- 3.3Flannel VXLAN 模式跨主机的工作原理:
- 3.4flannel
- 4.部署
- 4.1上传 cni-plugins-linux-amd64-v0.8.6.tgz 和 flannel.tar 到 /opt 目录
- (1)node01节点
- (2)node02节点
- 4.2上传 kube-flannel.yml 文件到 /opt/k8s 目录中,部署 CNI 网络
- (1)master01节点
- 八,Calico网络组件部署
- 1.flannel方案和calico方案区别
- 1.1flannel方案
- 1.2calico方案
- 2.calico的主要组成
- 3.Calico 工作原理
- 4.配置
- 4.1删除之前的fannel
- 4.1部署 CNI 网络
- (1)上传 calico.yaml 文件到 /opt/k8s 目录
- (2)启动kubelet服务
- (3)通过 CSR 请求
- (4)加载 ipvs 模块
- (5)启动proxy服务
- (6)查看群集中的节点状态
- 九,coredns部署
- 1.node节点
- 1.1存出镜像coredns
- 1.2部署 CoreDNS
- (1)上传 coredns.yaml 文件到 /opt/k8s 目录
- (2)DNS 解析测试
一, 集群拓扑
- Master 节点:
- IP: 192.168.88.20
- Components: kube-apiserver, kube-controller-manager, kube-scheduler, etcd
- Node01 节点:
- IP: 192.168.88.30
- Components: kubelet, kube-proxy, docker, etcd
- Node02 节点:
- IP: 192.168.88.40
- Components: kubelet, kube-proxy, docker, etcd
- Etcd 集群:
- 3 个节点的 etcd 集群分别部署在 Master 和 Node 上:
- etcd 节点1: 192.168.88.20(Master 节点)
- etcd 节点2: 192.168.88.30(Node01)
- etcd 节点3: 192.168.88.40(Node02)
- 3 个节点的 etcd 集群分别部署在 Master 和 Node 上:
二,架构图
三,前置准备
1.环境准备
- 操作系统:CentOS 7
- 禁用防火墙、SELinux、Swap
- 设置主机名解析、配置时间同步(NTP 或 Chrony)
- 修改内核参数,调整网络配置以支持 Kubernetes
- 安装
1.1操作系统初始化配置
(1)关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
(2)关闭selinux
setenforce 0 #临时关闭
sed -i 's/enforcing/disabled/' /etc/selinux/config #永久禁用
(3)关闭swap
swapoff -a #临时关闭
sed -ri 's/.*swap.*/#&/' /etc/fstab #永久禁用
(4)根据规划设置主机名
hostnamectl set-hostname master01
hostnamectl set-hostname node01
hostnamectl set-hostname node02
(5)在master添加hosts
cat >> /etc/hosts << EOF
192.168.88.20 master01
192.168.88.30 node01
192.168.88.40 node02
EOF
(6)调整内核参数
cat > /etc/sysctl.d/k8s.conf << EOF
#开启网桥模式,可将网桥的流量传递给iptables链
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
#关闭ipv6协议
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF
sysctl --system
(7)时间同步
yum install ntpdate -y
ntpdate ntp.aliyun.com
四,Etcd 集群部署
1.etcd简介
etcd 是一个分布式的键值存储系统,专门设计用于提供高可用性和一致性,广泛用于分布式系统中作为配置共享和服务发现的组件。etcd 是由 CoreOS 开发的,使用了 Raft 一致性算法,确保集群中数据的强一致性和可靠性。
etcd作为服务发现系统,有以下优点:
- 简单:安装配置简单,而且提供了HTTP·API进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:单实例支持每秒2k+读操作
- 可靠:采用raft算法,实现分布式系统数据的可用性和一致性
etcd 默认使用2379端口(外)提供HTTP·API服务,2380(内)端口和peer通信(两个端口已经被IANA互联网数字分配机构预留给etcd)。·etcd默认使用2379端口对外为客户端提供通讯,使用端口2380来进行服务器间内部通讯。etcd 在生产环境中一般推荐集群方式部署。由于etcd 的leader选举机制,要求至少为3台或以上的奇数台。
2.签发证书
CFSSL是CloudFlare·公司开源的一款·PKI/TLS工具。CFSSL包含一个命令行工具和一个用于签名、验证和捆绑TLS证书的HTTPAPI服务。使用Go语言编写。CFSSL使用配置文件生成证书,因此自签之前,需要生成它识别的json格式的配置文件,CFSSL 提供了方便的命令行生成配置文件。
CFSSL为etcd 提供TLS证书,支持三种类型证书:
- lient证书,服务端连接客户端时携带的证书,用于客户端验证服务端身份,如kube-apiserver访问etcd。
- server证书,客户端连接服务端时携带的证书,用于服务端验证客户端身份,如etcd 对外提供服务。
- peer证书,相互之间连接时使用的证书,如etcd节点之间进行验证和通信。
2.1 master01节点
(1)准备cfssl证书生成工具
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo
chmod +x /usr/local/bin/cfssl*
cfssl:证书签发的工具命令
cfssljson:将cfssl·生成的证书(json格式)变为文件承载式证书
cfssl-certinfo:验证证书的信息
cfssl-certinfo ·- cert ·< 证书名称>>->->#查看证书的信息
(2)生成Etcd证书
上传证书生成工具 etcd服务到/opt/k8s/目录,给执行权限
mkdir /opt/k8s
cd /opt/k8s/
chmod +x etcd-cert.sh etcd.sh
证书生成工具etcd-cert.sh
etcd服务etcd.sh
(3)创建CA证书、etcd服务器证书以及私钥目录
mkdir /opt/k8s/etcd-cert
mv etcd-cert.sh etcd-cert/
cd /opt/k8s/etcd-cert/
vim etcd-cert.sh
#!/bin/bash
cat > ca-config.json <<EOF
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
}
}
}
}
EOF
#后续在签名证书时会使用某个 profile;此实例只有一个 www 模板。
#signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;
#key encipherment:表示使用非对称密钥加密,如 RSA 加密;
#server auth:表示client可以用该 CA 对 server 提供的证书进行验证;
#client auth:表示server可以用该 CA 对 client 提供的证书进行验证;
#注意标点符号,最后一个字段一般是没有逗号的。
#生成CA证书和私钥(根证书和私钥)
cat > ca-csr.json <<EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
#key:指定了加密算法,一般使用rsa(size:2048)
#C:Country,国家
#ST:State,州,省
#L:Locality,地区,城市
#O: Organization Name,组织名称,公司名称
#OU: Organization Unit Name,组织单位名称,公司部门
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
#生成的文件:
#ca-key.pem:根证书私钥
#ca.pem:根证书
#ca.csr:根证书签发请求文件
#-----------------------
{
"192.168.88.20",
"192.168.88.30",
"192.168.88.40"
],
"key": {
"algo": "rsa",
"size": 2048
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
EOF
#hosts:将所有 etcd 集群节点添加到 host 列表,需要指定所有 etcd 集群的
节点 ip 或主机名不能使用网段,新增 etcd 服务器需要重新签发证书。
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
#生成的文件:
#server.csr:服务器的证书请求文件
#server-key.pem:服务器的私钥
#server.pem:服务器的数字签名证书
#-config:引用证书生成策略文件 ca-config.json
#-profile:指定证书生成策略文件中的的使用场景,比如 ca-config.json 中>的 www
./etcd-cert.sh
有个警告说证书缺少 “hosts” 字段,不适用 HTTPS 网站,但对于 etcd 集群内部通信来说并不影响,除非需要该证书用于外部客户端访问。
(4) 把etcd-v3.4.9-linux-amd64.tar.gz 上传到 /opt/k8s 目录,解压
cd /opt/k8s/
tar xf etcd-v3.4.9-linux-amd64.tar.gz
(5)创建用于存放 etcd 配置文件,命令文件,证书的目录
mkdir -p /opt/etcd/{cfg,bin,ssl}
cd /opt/k8s/etcd-v3.4.9-linux-amd64/
mv etcd etcdctl /opt/etcd/bin/
cp /opt/k8s/etcd-cert/*.pem /opt/etcd/ssl/
(6)启动etcd.sh
vim /opt/k8s/etcd.sh
#!/bin/bash
#example: ./etcd.sh etcd01 192.168.88.20 etcd02=https://192.168.88.30:2380,etcd03=https://192.168.88.40:2380
#创建etcd配置文件/opt/etcd/cfg/etcd
ETCD_NAME=$1
ETCD_IP=$2
ETCD_CLUSTER=$3
WORK_DIR=/opt/etcd
cat > $WORK_DIR/cfg/etcd <<EOF
#[Member]
ETCD_NAME="${ETCD_NAME}"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://${ETCD_IP}:2380"
ETCD_LISTEN_CLIENT_URLS="https://${ETCD_IP}:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://${ETCD_IP}:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://${ETCD_IP}:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://${ETCD_IP}:2380,${ETCD_CLUSTER}"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
#Member:成员配置
#ETCD_NAME:节点名称,集群中唯一。成员名字,集群中必须具备唯一性,如etcd01
#ETCD_DATA_DIR:数据目录。指定节点的数据存储目录,这些数据包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未指定-wal-dir,还会存储WAL文件;如果不指定会用缺省目录
#ETCD_LISTEN_PEER_URLS:集群通信监听地址。用于监听其他member发送信息的地址。ip为全0代表监听本机所有接口
#ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址。用于监听etcd客户发送信息的地址。ip为全0代表监听本机所有接口
#Clustering:集群配置
#ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址。其他member使用,其他member通过该地址与本member交互信息。一定要保证从其他member能可访问该地址。静态配置方式下,该参数的value一定要同时在--initial-cluster参数中存在
#ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址。etcd客户端使用,客户端通过该地址与本member交互信息。一定要保证从客户侧能可访问该地址
#ETCD_INITIAL_CLUSTER:集群节点地址。本member使用。描述集群中所有节点的信息,本member根据此信息去联系其他member
#ETCD_INITIAL_CLUSTER_TOKEN:集群Token。用于区分不同集群。本地如有多个集群要设为不同
#ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new是新集群,existing表示加入已有集群。
#创建etcd.service服务管理文件
cat > /usr/lib/systemd/system/etcd.service <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=${WORK_DIR}/cfg/etcd
ExecStart=${WORK_DIR}/bin/etcd \
--cert-file=${WORK_DIR}/ssl/server.pem \
--key-file=${WORK_DIR}/ssl/server-key.pem \
--trusted-ca-file=${WORK_DIR}/ssl/ca.pem \
--peer-cert-file=${WORK_DIR}/ssl/server.pem \
--peer-key-file=${WORK_DIR}/ssl/server-key.pem \
--peer-trusted-ca-file=${WORK_DIR}/ssl/ca.pem \
--logger=zap \
--enable-v2
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
#--enable-v2:开启 etcd v2 API 接口。当前 flannel 版本不支持 etcd v3 通信
#--logger=zap:使用 zap 日志框架。zap.Logger 是go语言中相对日志库中性能最高的
#--peer开头的配置项用于指定集群内部TLS相关证书(peer 证书),这里全部都使用同一套证书认证
#不带--peer开头的的参数是指定 etcd 服务器TLS相关证书(server 证书),这里全部都使用同一套证书认证
systemctl daemon-reload
systemctl enable etcd
systemctl restart etcd
./etcd.sh etcd01 192.168.88.20 etcd02=https://192.168.88.30:2380,etcd03=https://192.168.88.40:2380
(5)查看etcd进程
ps -ef | grep ectd
(6)将etcd证书文件、命令文件和服务管理文件全部拷贝到192.168.88.30 ,192.168.88.40 etcd集群节点
scp -r /opt/etcd/ root@192.168.88.30:/opt/
scp -r /opt/etcd/ root@192.168.88.40:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.88.30:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.88.40:/opt/
2.2 node01节点
(1)修改etcd相关证书文件、命令文件和服务管理文件
vim /opt/etcd/cfg/etcd
#[Member]
ETCD_NAME="etcd02"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.88.30:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.88.30:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.88.30:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.88.30:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.88.20:2380,etcd02=https://192.168.88.30:2380,etcd03=https://192.168.88.40:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
(2)启动etcd
mv /opt/etcd.service /usr/lib/systemd/system/
systemctl start etcd
systemctl enable etcd
2.3 node02节点
(1)修改etcd相关证书文件、命令文件和服务管理文件
vim /opt/etcd/cfg/etcd
#[Member]
ETCD_NAME="etcd02"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.88.40:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.88.40:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.88.40:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.88.40:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.88.20:2380,etcd02=https://192.168.88.30:2380,etcd03=https://192.168.88.40:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
(2)启动etcd
mv /opt/etcd.service /usr/lib/systemd/system/
systemctl start etcd
systemctl enable etcd
3.验证查看集群
master01节点
ETCDCTL_API=3 /opt/etcd/bin/etcdctl \
--cacert=/opt/etcd/ssl/ca.pem \
--cert=/opt/etcd/ssl/server.pem \
--key=/opt/etcd/ssl/server-key.pem \
--endpoints="https://192.168.88.20:2379,https://192.168.88.30:2379,https://192.168.88.40:2379" endpoint health \
--write-out=table
ETCDCTL_API=3 /opt/etcd/bin/etcdctl \
--cacert=/opt/etcd/ssl/ca.pem \
--cert=/opt/etcd/ssl/server.pem \
--key=/opt/etcd/ssl/server-key.pem \
--endpoints="https://192.168.88.20:2379,https://192.168.88.30:2379,https://192.168.88.40:2379" endpoint status \
--write-out=table
4.etcd 安装步骤
- 准备ca证书和私钥文件,是ca证书签发服务端证书和私有文件(cfssl证书)
- 使用ca证书,服务端证书和私钥文件加上etcd集群的配置文件去启动etcd服务
- 复制etcd 工作目录和管理文件·到node节点上·,修改etcd集群配置文件并且启动etcd 服务
- 使用V3版本·接口·执行etcdctl·+证书选项·(endpoints·healh) |endpoint·status·|member list查看etcd集群和节点状态
五,Master 组件部署
1.master01节点
1.1master组件签发证书
(1)上传 master.zip 和 k8s-cert.sh 到 /opt/k8s 目录,解压 master.zip并给所有.sh结尾的文件执行权限
cd /opt/k8s/
unzip master.zip
cd master
chmod +x *.sh
chmod +x /opt/k8s-cert.sh
(2)创建kubernetes工作目录,生成CA证书、相关组件的证书和私钥的目录
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
vim /opt/k8s-cert.sh
#!/bin/bash
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
}
}
}
EOF
#生成CA证书和私钥(根证书和私钥)
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 -
#-----------------------
#生成 apiserver 的证书和私钥(apiserver和其它k8s组件通信使用)
cat > apiserver-csr.json <<EOF
"hosts": [
"10.0.0.1",
"127.0.0.1",
"192.168.88.20", #master01
#"192.168.88.80", #master02
"192.168.88.100", #vip,后面 keepalived 使用
#"192.168.10.21", #load balancer01(master)
#"192.168.10.22", #load balancer02(backup)
"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",
]
}
EOF
#-----------------------
#生成 kubectl 连接集群的证书和私钥,具有admin权限
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "system:masters",
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
#-----------------------
#生成 kube-proxy 的证书和私钥
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
mkdir /opt/k8s/k8s-cert
mv /opt/k8s/k8s-cert.sh /opt/k8s/k8s-cert
cd /opt/k8s/k8s-cert/
./k8s-cert.sh #生成CA证书、相关组件的证书和私钥
(3)复制CA证书、apiserver相关证书和私钥到 /opt/kubernetes/ssl 目录
cd /opt/k8s/k8s-cert
cp ca*pem apiserver*pem /opt/kubernetes/ssl/
(4)将kubernetes-server-linux-amd64.tar.gz放到到 /opt/k8s/ 目录,并解压
cd /opt/k8s/
tar zxvf kubernetes-server-linux-amd64.tar.gz
(5)复制master组件的关键命令文件到 /opt/kubernetes/bin目录,并建软链接
cd /opt/k8s/kubernetes/server/bin
cp kube-apiserver kubectl kube-controller-manager kube-scheduler /opt/kubernetes/bin/
ln -s /opt/kubernetes/bin/* /usr/local/bin/
(6)创建 bootstrap token 认证文件
piserver 启动时会调用,相当于在集群内创建了一个这个用户,接下来就可以用 RBAC 给他授权
cd /opt/k8s/
vim token.sh
#!/bin/bash
#获取随机数前16个字节内容,以十六进制格式输出,并删除其中空格
BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
#生成 token.csv 文件,按照 Token序列号,用户名,UID,用户组 的格式生成
cat > /opt/kubernetes/cfg/token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
chmod +x token.sh
./token.sh
cat /opt/kubernetes/cfg/token.csv
(7)开启 apiserver 服务
cd /opt/k8s/master
./apiserver.sh 192.168.88.20 https://192.168.88.20:2379,https://192.168.88.30:2379,https://192.168.88.40:2379
(8) 查看进程,端口6443
ps aux | grep kube-apiserver
netstat -natp | grep 6443
(9)启动 scheduler
cd /opt/k8s/master
vim scheduler.sh
#!/bin/bash
##创建 kube-scheduler 启动参数配置文件
MASTER_ADDRESS=$1
cat >/opt/kubernetes/cfg/kube-scheduler <<EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-scheduler.kubeconfig \\
--bind-address=127.0.0.1"
EOF
##生成kube-scheduler证书
cd /opt/k8s/k8s-cert/
#创建证书请求文件
cat > kube-scheduler-csr.json << EOF
{
"CN": "system:kube-scheduler",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
#生成证书
#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-scheduler.kubeconfig"
KUBE_APISERVER="https://192.168.88.20:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-scheduler \
--client-certificate=./kube-scheduler.pem \
--client-key=./kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-scheduler \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
##创建 kube-scheduler.service 服务管理文件
cat >/usr/lib/systemd/system/kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-scheduler
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable kube-scheduler
systemctl restart kube-scheduler
./scheduler.sh
ps aux | grep kube-scheduler
(10)启动 controller-manager
cd /opt/k8s/master
vim /controller-manager.sh
#!/bin/bash
##创建 kube-controller-manager 启动参数配置文件
MASTER_ADDRESS=$1
cat >/opt/kubernetes/cfg/kube-controller-manager <<EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-controller-manager.kubeconfig \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--cluster-signing-duration=87600h0m0s"
EOF
#-–kubeconfig:连接 apiserver 用的配置文件,用于识别 k8s 集群
##生成kube-controller-manager证书
cd /opt/k8s/k8s-cert/
#创建证书请求文件
cat > kube-controller-manager-csr.json << EOF
{
"CN": "system:kube-controller-manager",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "system:masters",
"OU": "System"
}
EOF
#生成证书
#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-controller-manager.kubeconfig"
KUBE_APISERVER="https://192.168.88.20:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-controller-manager \
--client-certificate=./kube-controller-manager.pem \
--client-key=./kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-controller-manager \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
##创建 kube-controller-manager.service 服务管理文件
cat >/usr/lib/systemd/system/kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-controller-manager
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl restart kube-controller-manager
./controller-manager.sh
ps aux | grep kube-controller-manager
(11)生成kubectl连接集群的kubeconfig文件
cd /opt/k8s/master
vim admin.sh
#!/bin/bash
mkdir /root/.kube
KUBE_CONFIG="/root/.kube/config"
KUBE_APISERVER="https://192.168.88.20:6443"
cd /opt/k8s/k8s-cert/
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials cluster-admin \
--client-certificate=./admin.pem \
--client-key=./admin-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=cluster-admin \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
./admin.sh
(12)使用kubectl工具查看当前集群组件状态
kubectl get cs
(13)master 组件安装步骤
- 先安装APiserver
准备组件的相关证书和私钥文件
准备bootstarp token认证文件(kubectl启动时签发的证书时使用)
准备启动配置文件
启动APiserver 服务端口6443 https
- 启动controller-manager和scheduler
准备启动配置文件
准备证书和私钥文件生成kubeconfig 文件(用于指定对接哪个apiserver,使用什么证书认证·启动服务)
- 检查集群组件状态
需要准备kubeconfig 文件把kubect1·加入的集群中·(指定对接哪个APiserver,使用什么证书认证)kubectl get cs
六,Node 组件部署
1.node01,node02节点
1.1创建Kubernetes工作目录
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
1.2上传 node.zip 到 /opt目录并解压,给kubelet服务脚本和kube-proxy服务执行权限
cd /opt/
unzip node.zip
chmod +x kubelet.sh proxy.sh
2.master01节点
2.1把master01节点上的kubelet、kube-proxy发到node01和node02
cd /opt/k8s/kubernetes/server/bin
scp kubelet kube-proxy root@192.168.88.30:/opt/kubernetes/bin/
scp kubelet kube-proxy root@192.168.88.40:/opt/kubernetes/bin/
2.2上传生成kubele文件加入集群引导kubeconfig文件和kube-proxy.kubeconfig文件
kubeconfig 文件包含:
- 集群参数(CA 证书、API Server 地址)。
- 客户端参数(上面生成的证书和私钥)。
- 集群 context 上下文参数(集群名称、用户名)。
Kubenetes 组件(如 kubelet、kube-proxy)通过启动时指定不同的 kubeconfig 文件可以切换到不同的集群,连接到 apiserver。
mkdir /opt/k8s/kubeconfig
cd /opt/k8s/kubeconfig
chmod +x kubeconfig.sh
vim kubeconfig.sh
#!/bin/bash
#example: kubeconfig 192.168.88.20 /opt/k8s/k8s-cert/
#创建bootstrap.kubeconfig文件
BOOTSTRAP_TOKEN=$(awk -F ',' '{print $1}' /opt/kubernetes/cfg/token.csv)
APISERVER=$1
SSL_DIR=$2
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
#--embed-certs=true:表示将ca.pem证书写入到生成的bootstrap.kubeconfig文件中
# 设置客户端认证参数,kubelet 使用 bootstrap token 认证
kubectl config set-credentials kubelet-bootstrap \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=bootstrap.kubeconfig
# 设置上下文参数
kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=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
# 设置客户端认证参数,kube-proxy 使用 TLS 证书认证
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
# 使用上下文参数生成 kube-proxy.kubeconfig 文件
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
./kubeconfig.sh 192.168.88.20 /opt/k8s/k8s-cert/
2.3 把bootstrap.kubeconfig、kube-proxy.kubeconfig 发到 node01和node02
cd /opt/k8s/kubeconfig
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.88.30:/opt/kubernetes/cfg/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.88.40:/opt/kubernetes/cfg/
2.4 RBAC授权
目的是为了用户 kubelet-bootstrap 有权限发起 CSR 请求证书
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap
如果失败,给kubectl绑定默认cluster-admin管理员集群角色,授权集群操作权限
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous
2.5kubelet
kubelet 采用 TLS Bootstrapping 机制,自动完成到 kube-apiserver 的注册,在 node 节点量较大或者后期自动扩容时非常有用。
Master apiserver 启用 TLS 认证后,node 节点 kubelet 组件想要加入集群,必须使用CA签发的有效证书才能与 apiserver 通信,当 node 节点很多时,签署证书是一件很繁琐的事情。因此 Kubernetes 引入了 TLS bootstraping 机制来自动颁发客户端证书,kubelet 会以一个低权限用户自动向 apiserver 申请证书,kubelet 的证书由 apiserver 动态签署。
kubelet 首次启动通过加载 bootstrap.kubeconfig 中的用户 Token 和 apiserver CA 证书发起首次 CSR 请求,这个 Token 被预先内置在 apiserver 节点的 token.csv 中,其身份为 kubelet-bootstrap 用户和 system:kubelet-bootstrap 用户组;想要首次 CSR 请求能成功(即不会被 apiserver 401 拒绝),则需要先创建一个 ClusterRoleBinding,将 kubelet-bootstrap 用户和 system:node-bootstrapper 内置 ClusterRole 绑定(通过 kubectl get clusterroles 可查询),使其能够发起 CSR 认证请求。
TLS bootstrapping 时的证书实际是由 kube-controller-manager 组件来签署的,也就是说证书有效期是 kube-controller-manager 组件控制的;kube-controller-manager 组件提供了一个 --experimental-cluster-signing-duration 参数来设置签署的证书有效时间;默认为 8760h0m0s,将其改为 87600h0m0s,即 10 年后再进行 TLS bootstrapping 签署证书即可。
也就是说 kubelet 首次访问 API Server 时,是使用 token 做认证,通过后,Controller Manager 会为 kubelet 生成一个证书,以后的访问都是用证书做认证了。
3.node节点
3.1启动 kubelet
(1)node01节点
#!/bin/bash
NODE_ADDRESS=$1
DNS_SERVER_IP=${2:-"10.0.0.2"}
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--cert-dir=/opt/kubernetes/ssl \\
#--network-plugin:启用CNI
#--cert-dir:指定master颁发的kubelet证书生成目录
#----------------------
cat >/opt/kubernetes/cfg/kubelet.config <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: ${NODE_ADDRESS}
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS:
failSwapOn: false
authentication:
anonymous:
enabled: true
EOF
#----------------------
#创建 kubelet.service 服务管理文件
cat >/usr/lib/systemd/system/kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable kubelet
systemctl restart kubelet
./kubelet.sh 192.168.88.30
ps aux | grep kubelet
(2)node02节点
cd /opt/
./kubelet.sh 192.168.88.40
ps aux | grep kubelet
4.master01节点
4.1通过csr请求
(1)node01请求
kubectl get csr
检查到 node01 节点的 kubelet 发起的 CSR 请求,Pending 表示等待集群给该节点签发证书
kubectl certificate approve node-csr-onVgyQcwjg8MB-pYdavH-L6gHMnSqNwC6AWemqeo7dY
手动通过
kubectl get csr
查看得知通过了
kubectl get node
查看节点,由于网络插件还没有部署,节点会没有准备就绪 NotReady
1.检查到 node01 节点的 kubelet 发起的 CSR 请求,Pending 表示等待集群给该节点签发证书
2.通过请求
3.通过
4.查看节点,由于网络插件还没有部署,节点会没有准备就绪 NotReady
(1)node02请求
kubectl get csr
检查到 node02 节点的 kubelet 发起的 CSR 请求,Pending 表示等待集群给该节点签发证书
kubectl certificate approve node-csr-rxziWv1LF6Z7Vz1zO5dEOYqf3adhbtg_ZH1jYIgcxV8
手动通过
kubectl get csr
查看得知通过了
kubectl get node
查看节点,由于网络插件还没有部署,节点会没有准备就绪 NotReady
1.检查到 node02 节点的 kubelet 发起的 CSR 请求,Pending 表示等待集群给该节点签发证书
2.通过请求
3.通过
4.查看节点,由于网络插件还没有部署,节点会没有准备就绪 NotReady
5.node节点
5.1加载ipvs模块
(1)node01节点
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
(2)node02节点
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
5.2启动proxy服务
(1)node01节点
cd /opt/
vim /opt/proxy.sh
#!/bin/bash
NODE_ADDRESS=$1
#创建 kube-proxy 启动参数配置文件
cat >/opt/kubernetes/cfg/kube-proxy <<EOF
KUBE_PROXY_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=${NODE_ADDRESS} \\
--cluster-cidr=10.244.0.0/16 \\
--proxy-mode=ipvs \\
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
EOF
#--kubeconfig: 指定连接 apiserver 的 kubeconfig 文件
#--proxy-mode:指定流量调度模式为ipvs模式,可添加--ipvs-scheduler选项指定ipvs调度算法(rr|lc|dh|sh|sed|nq)
#rr: round-robin,轮询。
#lc: least connection,最小连接数。
#dh: destination hashing,目的地址哈希。
#sh: source hashing ,原地址哈希。
#sed: shortest expected delay,最短期望延时。
#nq: never queue ,永不排队。
#----------------------
#创建 kube-proxy.service 服务管理文件
cat >/usr/lib/systemd/system/kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-proxy
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy
./proxy.sh 192.168.88.30
ps aux | grep kube-proxy
(2)node02节点
cd /opt
./proxy.sh 192.168.88.40
ps aux | grep kube-proxy
七,CNI网络组件部署
1.kubernetes三种网络
service网络service ip地址 虚拟IP地址给·clusterIP在四层负载均衡
pod·网络pod的IP地址·docker容器的IP为虚拟IP直白点直接给应用或者中间件
节点(物理)网络·服务器物理网卡IP
1.1pod之间如何通信
(1)Pod 内容器与容器之间的通信
同一个 Pod 内的容器(Pod 内的容器不能跨宿主机的)共享同一个网络命名空间,在同一台机器上一样,可以用 localhost 地址互相通信。
(2)同一个 Node 内 Pod 之间的通信
每个 Pod 都有一个真实的全局 IP 地址,同一个 Node 内的不同 Pod 之间可以直接采用对方 Pod 的 IP 地址进行通信,Pod1 与 Pod2 都是通过 Veth 连接到同一个 docker0/cni0 网桥,网段相同,所以它们之间可以直接通信。
(3)不同 Node 上 Pod 之间的通信
Pod 地址与 docker0 在同一网段,docker0 网段与宿主机网卡是两个不同的网段,且不同 Node 之间的通信只能通过宿主机的物理网卡进行。
不同 Node 上 Pod 之间的通信,就要通过主机的物理网卡 IP 地址进行寻址和通信。因此要满足两个条件:Pod 的 IP 不能冲突;将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让不同 Node 上 Pod 之间直接通过内网 IP 地址通信。
2.Kubernetes 网络的基本要求
- 每个 Pod 都需要拥有一个独立的 IP 地址。
- 不同节点上的 Pod 之间必须能够互相通信,无论它们是否在同一物理或逻辑子网中。
- 不需要 NAT,即节点之间传递的数据包不应经过地址转换。
由于这些要求并不是所有物理网络都能直接满足,所以 Kubernetes 需要通过 Overlay Network 等方案来实现跨节点 Pod 的通信。
2.1Overlay Network
Overlay Network(覆盖网络)是一种网络虚拟化技术,它在底层物理网络( 如以太网、IP 网络 )之上创建一个逻辑网络。通过这种方式,不同物理位置的节点可以像在同一局域网内一样通信,隐藏底层网络的复杂性。
通过Overlay技术(类似隧道技术),在原始报文外再包一层四层协议(UDP协议),在通过主机网络进行路由转发。这种方式性能有一定损耗,主要体现在对原始报文的修改。目前Overlay主要采用VXLAN协议。
Overlay Network 的工作原理
- 封装和隧道传输:
Overlay Network 通过将原始数据包封装在其他协议的数据包内进行传输(例如使用 VXLAN 封装 IP 数据包),并在目标节点上解封装。这就像在不同主机之间开辟一条虚拟隧道。 - 跨子网通信:
即使底层网络中的主机不在同一子网或 VLAN 中,Overlay Network 也能让它们像在同一局域网中通信。 - 隔离性:
可以为不同的服务或租户创建多个 Overlay Network,实现逻辑上的网络隔离。
(1) VXLAN
VXLAN 是一种强大的网络虚拟化技术,通过在三层网络上创建虚拟二层网络,解决了大规模云计算环境中网络隔离和扩展的问题。它在 Kubernetes 等容器平台中广泛应用,支持跨节点的 Pod 网络通信。通过 VTEP 封装与解封装的机制,VXLAN 实现了不同节点之间的数据传输,简化了集群的网络管理和部署。
优点:
- 大规模网络扩展:支持多达 1600 万个虚拟网络,远超 VLAN 的 4096 个限制。
- 跨子网通信:无需改变物理网络拓扑,即可实现跨子网、跨数据中心的通信。
- 多租户隔离:支持多租户隔离,通过 VNI 实现逻辑网络的分离。
缺点:
- 性能开销:封装和解封装会增加 CPU 的负担,尤其是在流量高峰时。
- 故障排查复杂:由于封装隐藏了底层网络的信息,网络排障会更困难。
- 额外的 MTU 要求:封装增加了数据包大小,可能需要增大 MTU(Maximum Transmission Unit)。
(2)VXLAN 的作用
- 跨主机创建二层网络:
- 即使两个设备在不同的物理网络或子网中,它们也可以像在同一个二层网络中一样通信。
- 网络隔离:
- 支持多租户环境,为不同租户创建独立的虚拟网络,通过 VXLAN ID 进行逻辑隔离。
- 扩展 VLAN 的数量限制:
- VLAN 只能支持 4096 个(12 位 VLAN ID),而 VXLAN 的 24 位 VNI(VXLAN Network Identifier) 支持多达 1600 万个虚拟网络。
- 与现有 IP 网络兼容:
- VXLAN 工作在三层网络上,不需要对物理网络进行大规模改动。
**(3) VXLAN 的工作原理 **
VXLAN 的核心思想是 将二层以太网帧封装在 UDP 数据包中,并通过三层网络进行传输。这样,原始的以太网帧会像“货物”一样被包裹在一个 UDP 包中,在不同的物理网络之间传输。
VXLAN 通信流程
- Pod 或虚拟机发送数据包:
- 在源节点(Node 01)上的 Pod 发送一个以太网数据包,目标为另一个节点(Node B)上的 Pod。
- 源节点 VTEP 封装数据包:
- VTEP 在 Node 01 上将数据包封装为 VXLAN 包,添加 VNI 和 UDP/IP 头。
- 数据包通过物理网络传输:
- 封装后的数据包通过 IP 网络(如互联网或数据中心网络)发送到目标节点。
- 目标节点 VTEP 解封装数据包:
- Node 02 上的 VTEP 收到 VXLAN 包,去除外层的 UDP/IP 头,还原原始以太网帧。
- 将数据包转发给目标 Pod:
- 解封装后的数据包被传递给目标 Pod,实现跨节点通信。
3.Flannel
作用是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。Flannel:使用 VXLAN 作为 Overlay 封装协议(默认模式)。
flannel配置简单,适合开发环境和中小型集群。支持多种网络模式,灵活选择 VXLAN、Host-GW(不用了)、IP-in-IP 等封装方式。
3.1Flannel UDP 模式的工作原理
数据从node01上的pod的源容器发出,经过宿主机的docker0/cni网口转发到flannel0的端口上,flanneld服务监听flannel0端口(8285)虚拟网卡的对端。Flannel 通过 Etcd 服务维护了一张节点间的路由表。源主机 A 的 flanneld 服务将原本的数据内容封装到 UDP 报文中, 根据自己的路由表通过物理网卡投递给目的节点主机 B 的 flanneld 服务,数据到达以后被解包,然后直接进入目的节点的 flannel0 接口, 之后被转发到目的主机的 docker0/cni0 网桥,最后就像本机容器通信一样由 docker0/cni0 转发到目标容器。
3.2ETCD 与Flannel
存储管理Flannel可分配的IP地址段资源。监控 ETCD 中每个 Pod 的实际地址,并在内存中建立维护 Pod 节点路由表。由于 UDP 模式是在用户态做转发,会多一次报文隧道封装,因此性能上会比在内核态做转发的 VXLAN 模式差。
3.2Flannel VXLAN 模式
VXLAN 模式使用比较简单,flannel 会在各节点生成一个 flannel.1 的 VXLAN 网卡(VTEP设备,负责 VXLAN 封装和解封装)。VXLAN 模式下作是由内核进行的。flannel 不转发数据,仅动态设置 ARP 表和 MAC 表项。UDP 模式的 flannel0 网卡是三层转发,使用 flannel0 时在物理网络之上构建三层网络,属于 ip in udp ;VXLAN封包与解包的工 模式是二层实现,overlay 是数据帧,属于 mac in udp 。
3.3Flannel VXLAN 模式跨主机的工作原理:
1、数据帧从主机 A 上 Pod 的源容器中发出后,经由所在主机的 docker0/cni0 网络接口转发到 flannel.1 接口
2、flannel.1 收到数据帧后添加 VXLAN 头部,封装在 UDP 报文中
3、主机 A 通过物理网卡发送封包到主机 B 的物理网卡中
4、主机 B 的物理网卡再通过 VXLAN 默认端口 4789 转发到 flannel.1 接口进行解封装
5、解封装以后,内核将数据帧发送到 cni0,最后由 cni0 发送到桥接到此接口的容器 B 中。
3.4flannel
配置方便功能简单,配置是基于overrelay叠加网络,由于进行封装和解封装的过程性能会一定的影响,同时不具备网络策略的配置能力。flannel的三种网络是UDP ,VXLAN,HOST-GW默认网段是10.244.0.0/16
1.UDP:
在用户态实现封装和解封装·,由于性能较差已经不怎么使用,通常用于bug
使用场景:早期的时候简单封装,性能不如以下两种,但是依然可以为简单集群使用
2.VXLAN:
默认设置·李勇内核·级别的VXLAN来封装HOST之间传送的包,便于使用
使用场景:适合大多数生产环境,尤其是再节点间需要网络通信时非常适合·
3.HOST-GW :
二层网络配置·,不支持云环境,通过在主机·host的路由表中直接创建其他主机网段·subnet·路由条目·来的·性能好·配置麻烦
使用场景:性能好,但适合网络环境简单的情况来使用
4.部署
4.1上传 cni-plugins-linux-amd64-v0.8.6.tgz 和 flannel.tar 到 /opt 目录
(1)node01节点
cd /opt/
docker load -i flannel.tar
mkdir -p /opt/cni/bin
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
(2)node02节点
cd /opt/
docker load -i flannel.tar
mkdir -p /opt/cni/bin
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
4.2上传 kube-flannel.yml 文件到 /opt/k8s 目录中,部署 CNI 网络
(1)master01节点
cd /opt/k8s
vim kube-flannel.yml
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp.flannel.unprivileged
annotations:
spec:
privileged: false
volumes:
- configMap
- secret
- emptyDir
- hostPath
allowedHostPaths:
- pathPrefix: "/etc/cni/net.d"
- pathPrefix: "/etc/kube-flannel"
- pathPrefix: "/run/flannel"
readOnlyRootFilesystem: false
# Users and groups
runAsUser:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
fsGroup:
rule: RunAsAny
# Privilege Escalation
allowPrivilegeEscalation: false
defaultAllowPrivilegeEscalation: false
# Capabilities
allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
defaultAddCapabilities: []
requiredDropCapabilities: []
# Host namespaces
hostPID: false
hostIPC: false
hostNetwork: true
hostPorts:
- min: 0
max: 65535
# SELinux
seLinux:
# SELinux is unused in CaaSP
rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
rules:
- apiGroups: ['extensions']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['psp.flannel.unprivileged']
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-system
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-system
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.14.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-system
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-system
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.14.0
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
kubectl apply -f kube-flannel.yml
kubectl get pods -n kube-system
kubectl get nodes
稍等一会就好
等node02操作完后在来一遍
八,Calico网络组件部署
1.flannel方案和calico方案区别
1.1flannel方案
需要在每个节点上把发向容器的数据包进行封装后,再用隧道将封装后的数据包发送到运行着目标Pod的node节点上。目标node节点再负责去掉封装,将去除封装的数据包发送到目标Pod上。数据通信性能则大受影响。
1.2calico方案
Calico不使用隧道或NAT来实现转发,而是把Host当作Internet中的路由器,使用BGP同步路由,并使用iptables来做安全访问策略,完成跨Host转发。
采用直接路由的方式,这种方式性能损耗最低,不需要修改报文数据,但是如果网络比较复杂场景下,路由表会很复杂,对运维同事提出了较高的要求。
2.calico的主要组成
Calico CNI插件:主要负责与kubernetes对接,供kubelet调用使用。
Felix:负责维护宿主机上的路由规则、FIB转发信息库等。
BIRD:负责分发路由规则,类似路由器。
Confd:配置管理组件。
3.Calico 工作原理
Calico 利用路由表来管理每个 Pod 的通信。其 CNI 插件为每个容器配置一个 veth pair 设备,一端接入容器,另一端接入宿主机网络。由于没有使用网桥,CNI 插件还需在宿主机上为每个 veth pair 设备设置路由规则,以确保 IP 包的正确接收与转发。
容器发出的 IP 包通过 veth pair 传输至宿主机,宿主机则根据路由规则将包转发至正确的网关,进而到达目标宿主机及容器。这些路由规则由 Calico 的 Felix 组件维护,而路由信息则通过 Calico 的 BIRD 组件基于 BGP 协议分发。
在 Calico 中,集群的所有节点均被视为边界路由器(BGP Peer),它们共同构成一个全互联网络,通过 BGP 协议交换路由信息。
4.配置
4.1删除之前的fannel
master01节点
cd /opt/k8s
kubectl delete -f kube-flannel.yml
kubectl get node #因为缓存原因还是ready状态
kubectl get pods -n kube-system #只要没有发现这个命令就行
4.1部署 CNI 网络
(1)上传 calico.yaml 文件到 /opt/k8s 目录
master01 节点
cd /opt/k8s
vim calico.yaml
修改里面定义 Pod 的网络(CALICO_IPV4POOL_CIDR),需与之前 kube-controller-manager 配置文件指定的 cluster-cidr 网段一样
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16" #Calico 默认使用的网段为 192.168.0.0/16
kubectl apply -f calico.yaml
kubectl run -it --rm
(2)启动kubelet服务
node01节点, node02节点
cd /opt/
chmod +x kubelet.sh
./kubelet.sh 192.168.88.30
cd /opt/
chmod +x kubelet.sh
./kubelet.sh 192.168.88.40
(3)通过 CSR 请求
master01节点
kubectl get csr
kubectl certificate approve node-csr-证书签名请求的唯一标识符
(4)加载 ipvs 模块
node01节点 node02节点
加载 ipvs 模块
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
(5)启动proxy服务
cd /opt/
chmod +x proxy.sh
./proxy.sh 192.168.88.30
cd /opt/
chmod +x proxy.sh
./proxy.sh 192.168.88.40
(6)查看群集中的节点状态
master01节点
kubectl get nodes
九,coredns部署
oreDNS:可以为集群中的 service 资源创建一个域名 与 IP 的对应关系解析
1.node节点
node01节点 node02节点都要操作
1.1存出镜像coredns
上传镜像coredns.tar 到/opt目录
cd /opt
docker load -i coredns.tar
1.2部署 CoreDNS
master01节点
(1)上传 coredns.yaml 文件到 /opt/k8s 目录
cd /opt/k8s
kubectl apply -f coredns.yaml
kubectl get pods -n kube-system
(2)DNS 解析测试
kubectl run -it --rm dns-test --image=busybox:1.28.4 sh
nslookup kubernetes
如遇下图,说明需要添加 rbac的权限 直接使用kubectl绑定 clusteradmin 管理员集群角色 授权操作权限
添加rbac权限
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous