k8s 环境规划:
podSubnet(pod 网段) 10.244.0.0/16
serviceSubnet(service 网段): 10.96.0.0/12
实验环境规划:
操作系统:centos7.9
配置: 4Gib 内存/4vCPU/60G 硬盘网络:NAT 模式
K8S 集群角色 | IP | 主机名 | 安装的组件 |
---|---|---|---|
控制节点 | 192.168.100.180 | k8s-master1 | apiserver、controller-manager、schedule、etcd、kube-proxy、容器运行时、keepalived、 nginx |
控制节点 | 192.168.100.181 | k8s-master2 | apiserver、controller-manager、schedule、etcd、kube-proxy、容器运行时、keepalived、 nginx |
控制节点 | 192.168.100.182 | k8s-master3 | apiserver、controller-manager、schedule、etcd、kube-proxy、容器运行时、keepalived、 nginx |
工作节点 | 192.168.100.183 | k8s-node1 | Kube-proxy、calico、coredns、容 器运行时、kubelet |
工作节点 | 192.168.100.184 | k8s-node2 | Kube-proxy、calico、coredns、容 器运行时、kubelet |
VIP | 192.168.100.200 |
vim /etc/sysconfig/network-scripts/ifcfg-ens33 文件
TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no
BOOTPROTO=static IPADDR=192.168.100.180 NETMASK=255.255.255.0 GATEWAY=192.168.100.2 DNS1=192.168.100.2 DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33
DEVICE=ens33 ONBOOT=yes
#修改配置文件之后需要重启网络服务才能使配置生效,重启网络服务命令如下: service network restart
注:/etc/sysconfig/network-scripts/ifcfg-ens33 文件里的配置说明:
NAME=ens33 #网卡名字,跟 DEVICE 名字保持一致即可
DEVICE=ens33 #网卡设备名,大家 ip addr 可看到自己的这个网卡设备名,每个人的机器可能这个名字不一样,需要写自己的
BOOTPROTO=static #static 表示静态 ip 地址
ONBOOT=yes # 开 机 自 启 动 网 络 , 必 须 是 yes IPADDR=192.168.100.180 #ip 地址,需要跟自己电脑所在网段一致NETMASK=255.255.255.0 #子网掩码,需要跟自己电脑所在网段一致
GATEWAY=192.168.100.2 #网关,在自己电脑打开 cmd,输入 ipconfig /all 可看到
DNS1=192.168.100.2 #DNS,在自己电脑打开 cmd,输入 ipconfig /all 可看到
#各个节点执行如下命令更新 yum 源和操作系统: yum update -y
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
#修改 selinux 配置文件之后,重启机器,selinux 配置才能永久生效,重启之后,登录到机器, 执行如下命令:getenforce
#如果显示 Disabled 说明 selinux 已经关闭
在 192.168.100.180 上执行如下:
hostnamectl set-hostname k8s-master1 && bash
在 192.168.100.181 上执行如下:
hostnamectl set-hostname k8s-master2 && bash
在 192.168.100.182 上执行如下:
hostnamectl set-hostname k8s-master3 && bash
在 192.168.100.183 上执行如下:
hostnamectl set-hostname k8s-node1 && bash
在 192.168.100.184 上执行如下:
hostnamectl set-hostname k8s-node2 && bash
修改之后的文件如下:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.180 k8s-master1
192.168.100.181 k8s-master2
192.168.100.182 k8s-master3
192.168.100.183 k8s-node1
192.168.100.184 k8s-node2
#配置 k8s-master1 / k8s-master2 / k8s-master3到其他机器免密登录
[root@k8s-master1 ~]# ssh-keygen #一路回车,不输入密码把本地生成的密钥文件和私钥文件拷贝到远程主机
[root@k8s-master1 ~]# ssh-copy-id k8s-master1
[root@k8s-master1 ~]# ssh-copy-id k8s-master2
[root@k8s-master1 ~]# ssh-copy-id k8s-master3
[root@k8s-master1 ~]# ssh-copy-id k8s-node1
[root@k8s-master1 ~]# ssh-copy-id k8s-node2
#配置 k8s-node1 / k8s-node2到其他机器免密登录
[root@k8s-node1 ~]# ssh-keygen #一路回车,不输入密码把本地生成的密钥文件和私钥文件拷贝到远程主机
[root@k8s-node1 ~]# ssh-copy-id k8s-master1
[root@k8s-node1 ~]# ssh-copy-id k8s-master2
[root@k8s-node1 ~]# ssh-copy-id k8s-master3
[root@k8s-node1 ~]# ssh-copy-id k8s-node1
[root@k8s-node1 ~]# ssh-copy-id k8s-node2
#临时关闭
[root@k8s-master1 ~]# swapoff -a
#永久关闭:注释 swap 挂载,给 swap 这行开头加一下注释
[root@k8s-master1 ~]# vim /etc/fstab
#/dev/mapper/centos-swap swap swap defaults 0 0
#给 swap 这行开头加一下注释#
#/dev/mapper/centos-swap swap swap defaults 0 0
#问题 1:为什么要关闭 swap 交换分区?
Swap 是交换分区,如果机器内存不够,会使用 swap 分区,但是 swap 分区的性能较低,k8s 设计的时候为了能提升性能,默认是不允许使用交换分区的。Kubeadm 初始化的时候会检测 swap 是否关闭,如果没关闭,那就初始化失败。如果不想要关闭交换分区,安装 k8s 的时候可以指定-- ignore-preflight-errors=Swap 来解决。
[root@k8s-master1 ~]# modprobe br_netfilter
[root@k8s-master1 ~]# cat > /etc/sysctl.d/k8s.conf <
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
[root@k8s-master1 ~]# sysctl -p /etc/sysctl.d/k8s.conf
#问题 1:sysctl 是做什么的? 在运行时配置内核参数
-p 从指定的文件加载系统参数,如不指定即从/etc/sysctl.conf 中加载
#问题 2:为什么要执行 modprobe br_netfilter?
修改/etc/sysctl.d/k8s.conf 文件,增加如下三行参数:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
sysctl -p /etc/sysctl.d/k8s.conf 出现报错:
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory
解决方法:
modprobe br_netfilter
问题 3:为什么开启 net.bridge.bridge-nf-call-iptables 内核参数? 在 centos 下 安 装 docker, 执 行 docker info 出 现 如 下 警 告 : WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
解决办法:
vim /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
问题 4:为什么要开启 net.ipv4.ip_forward = 1 参数?
kubeadm 初始化 k8s 如果报错:
就表示没有开启 ip_forward,需要开启。net.ipv4.ip_forward 是数据包转发:
出于安全考虑,Linux 系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时, 其中一块收到数据包,根据数据包的目的 ip 地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
要让 Linux 系统具有路由转发功能,需要配置一个 Linux 的内核参数 net.ipv4.ip_forward。这个参数指定了 Linux 系统当前对路由转发功能的支持情况;其值为 0 时表示禁止进行 IP 转发;如果是 1, 则说明 IP 转发功能已经打开。
[root@k8s-master1 ~]# systemctl stop firewalld ; systemctl disable firewalld
#配置国内安装 docker 和 containerd 的阿里云的repo 源
[root@k8s-master1 ~]#yum install yum-utils -y
[root@k8s-master1 ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@k8s-master1 ~]#cat > /etc/yum.repos.d/kubernetes.repo <
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF
#安装 ntpdate 命令
[root@k8s-master1 ~]# yum install ntpdate -y #跟网络时间做同步
[root@k8s-master1 ~]# ntpdate cn.pool.ntp.org #把时间同步做成计划任务
[root@k8s-master1 ~]# crontab -e
* */1 * * * /usr/sbin/ntpdate cn.pool.ntp.org
#重启 crond 服务
[root@k8s-master1 ~]# service crond restart
[root@k8s-master1 ~]# yum install -y device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl- devel unzip sudo ntp libaio-devel wget vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack telnet ipvsadm
[root@k8s-master1 ~]# yum install containerd.io-1.6.6 -y
接下来生成 containerd 的配置文件:
[root@k8s-master1 ~]# mkdir -p /etc/containerd
[root@k8s-master1 ~]# containerd config default > /etc/containerd/config.toml
修改配置文件:
打开/etc/containerd/config.toml
把 SystemdCgroup = false 修改成 SystemdCgroup = true
把 sandbox_image = "k8s.gcr.io/pause:3.6"修改成sandbox_image="registry.aliyuncs.com/google_containers/pause:3.7"
配置 containerd 开机启动 , 并启动 containerd
[root@k8s-master1 ~]# systemctl enable containerd --now
修改/etc/crictl.yaml 文件,修改/etc/crictl.yaml 文件这部分在视频里没讲,但是大家做实验要按照文档执行:
[root@k8s-master1 ~]# cat > /etc/crictl.yaml <
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
[root@k8s-master1 ~]# systemctl restart containerd
备注:docker 也要安装,docker 跟containerd 不冲突,安装 docker 是为了能基于 dockerfile 构建镜像
[root@k8s-master1 ~]# yum install docker-ce -y
[root@k8s-master1 ~]# systemctl enable docker --now
配置 containerd 镜像加速器,k8s 所有节点均按照以下配置: 编辑 vim /etc/containerd/config.toml 文件
找到 config_path = "",修改成如下目录: config_path = "/etc/containerd/certs.d"
mkdir /etc/containerd/certs.d/docker.io/ -p
vim /etc/containerd/certs.d/docker.io/hosts.toml #写入如下内容:
[host."https://lmy14a53.mirror.aliyuncs.com",host."https://registry.docker-cn.com"] capabilities = ["pull"]
重启 containerd:
systemctl restart containerd
#配置 docker 镜像加速器,k8s 所有节点均按照以下配置
vim /etc/docker/daemon.json
写入如下内容:
{
"registry-mirrors":["https://lmy14a53.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com"]
}
#重启 docker:
systemctl restart docker
[root@k8s-master1 ~]# yum install -y kubelet-1.25.0 kubeadm-1.25.0 kubectl-1.25.0
[root@k8s-master1 ~]# systemctl enable kubelet
注:每个软件包的作用
Kubeadm: kubeadm 是一个工具,用来初始化 k8s 集群的
kubelet: 安装在集群所有节点上,用于启动 Pod 的,kubeadm 安装 k8s,k8s 控制节点和工作节点的组件,都是基于 pod 运行的,只要 pod 启动,就需要 kubelet
kubectl: 通过 kubectl 可以部署和管理应用,查看各种资源,创建、删除和更新各种组件
1、安装 nginx 主备:
在 k8s-master1 和 k8s-master2 上做 nginx 主备安装
[root@k8s-master1 ~]# yum install epel-release -y
[root@k8s-master1 ~]# yum install nginx keepalived nginx-mod-stream -y
2、修改 nginx 配置文件。主备一样
[root@k8s-master1 ~]# vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
# 四层负载均衡,为两台Master apiserver组件提供负载均衡
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.180:6443 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.100.181:6443 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.100.182:6443 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 16443; # 由于nginx与master节点复用,这个监听端口不能是6443,否则会冲突
proxy_pass k8s-apiserver;
}
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 default_server;
server_name _;
location / {
}
}
}
3、keepalive 配置主 keepalived
[root@k8s-master1 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER
interface ens33 # 修改为实际网卡名
virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的
priority 100 # 优先级,备服务器设置 90
advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟 IP
virtual_ipaddress {
192.168.100.199/24
}
track_script {
check_nginx
}
}
#vrrp_script:指定检查 nginx 工作状态脚本(根据 nginx 状态判断是否故障转移)
#virtual_ipaddress:虚拟 IP(VIP)
[root@k8s-master1 ~]# vim /etc/keepalived/check_nginx.sh
#!/bin/bash
#1、判断 Nginx 是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
#2、如果不存活则尝试启动 Nginx
service nginx start
sleep 2
#3、等待 2 秒后再次获取一次 Nginx 状态
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
#4、再次进行判断,如 Nginx 还不存活则停止 Keepalived,让地址进行漂移
if [ $counter -eq 0 ]; then
service keepalived stop
fi
fi
[root@k8s-master1 ~]# chmod +x /etc/keepalived/check_nginx.sh
#备 keepalive
[root@k8s-master2 / k8s-master3 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
[email protected]
[email protected]
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_BACKUP
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.100.199/24
}
track_script {
check_nginx
}
}
[root@k8s-master2 / k8s-master3 ~]# vim /etc/keepalived/check_nginx.sh
#!/bin/bash
#1、判断 Nginx 是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
#2、如果不存活则尝试启动 Nginx
service nginx start
sleep 2
#3、等待 2 秒后再次获取一次 Nginx 状态
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
#4、再次进行判断,如 Nginx 还不存活则停止 Keepalived,让地址进行漂移
if [ $counter -eq 0 ]; then
service keepalived stop
fi
fi
[root@k8s-master2 / k8s-master3 ~]# chmod +x /etc/keepalived/check_nginx.sh
#注:keepalived 根据脚本返回状态码(0 为工作正常,非 0 不正常)判断是否故障转移。
4、启动服务:
[root@k8s-master1 ~]# systemctl daemon-reload
[root@k8s-master1 ~]# systemctl start nginx
[root@k8s-master1 ~]# systemctl start keepalived
[root@k8s-master1 ~]# systemctl enable nginx keepalived
[root@k8s-master1 ~]# systemctl status keepalived
5、测试 vip 是否绑定成功[root@k8s-master1 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:79:9e:36 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.180/24 brd 192.168.100.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet 192.168.100.199/24 scope global secondary ens33
valid_lft forever preferred_lft forever
inet6 fe80::b6ef:8646:1cfc:3e0c/64 scope link noprefixroute
valid_lft forever preferred_lft forever
6、测试 keepalived:
停掉 k8s-master1 上的 keepalived,Vip 会漂移到 k8s-master2
[root@k8s-master1 ~]# service keepalived stop
[root@k8s-master2]# ip addr
#启动 k8s-master1 上的 nginx 和 keepalived,vip 又会漂移回来
[root@k8s-master1 ~]# systemctl daemon-reload
[root@k8s-master1 ~]# systemctl start nginx
[root@k8s-master1 ~]# systemctl start keepalived
[root@k8s-master1]# ip addr
#设置容器运行时
[root@k8s-master1~]# crictl config runtime-endpoint /run/containerd/containerd.sock
#使用 kubeadm 初始化 k8s 集群
[root@k8s-master1 ~]# kubeadm config print init-defaults > kubeadm.yaml
#根据我们自己的需求修改配置,比如修改 imageRepository 的值,kube-proxy 的模式为ipvs,需要注意的是由于我们使用的 containerd 作为运行时,所以在初始化节点的时候需要指定cgroupDriver 为 systemd
kubeadm.yaml 配 置 文 件 如 下 :
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s usages:
- signing
- authentication
kind: InitConfiguration
#localAPIEndpoint #前面加注释
#advertiseAddress #前面加注释
#bindPort #前面加注释
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock #指定 containerd 容器运行时
imagePullPolicy: IfNotPresent
#name: node #前面加注释
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers #指定阿里云镜像仓库
kind: ClusterConfiguration
kubernetesVersion: 1.26.0
#新增加如下内容:
controlPlaneEndpoint: 192.168.100.200:16443
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16 #指定 pod 网段
serviceSubnet: 10.96.0.0/12
scheduler: {}
#追加如下内容
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
#基于 kubeadm.yaml 初始化 k8s 集群
[root@k8s-master1 ~]# ctr -n=k8s.io images import k8s_1.26.0.tar.gz
#备注:k8s_1.26.0.tar.gz 这个文件如何来的?
这个文件把安装 k8s 需要的镜像都继承好了,这个是我第一次安装 1.26.0 这个版本,获取到对应的镜像,通过 ctr images export 这个命令把镜像输出到 k8s_1.26.0.tar.gz 文件,如果大家安装其他版本,那就不需要实现解压镜像,可以默认从网络拉取镜像即可。
ctr 是 containerd 自带的工具,有命名空间的概念,若是 k8s 相关的镜像,都默认在 k8s.io 这个命名空间,所以导入镜像时需要指定命令空间为 k8s.io
#使用 ctr 命令指定命名空间导入镜像
ctr -n=k8s.io images import k8s_1.26.0.tar.gz
#查看镜像,可以看到可以查询到了
crictl images
[root@k8s-master1 ~]# kubeadm init --config=kubeadm.yaml --ignore-preflight-errors=SystemVerification
显示如下,说明安装完成:
特别提醒:--image-repository registry.aliyuncs.com/google_containers 为保证拉取镜像不到国外站点拉取,手动指定仓库地址为 registry.aliyuncs.com/google_containers。kubeadm 默认从 k8s.gcr.io 拉取镜像。 我们本地有导入到的离线镜像,所以会优先使用本地的镜像。
mode: ipvs 表示 kube-proxy 代理模式是 ipvs,如果不指定 ipvs,会默认使用 iptables,但是iptables 效率低,所以我们生产环境建议开启 ipvs,阿里云和华为云托管的 K8s,也提供 ipvs 模式,如下:
#配置 kubectl 的配置文件 config,相当于对 kubectl 进行授权,这样 kubectl 命令可以使用这个证书对 k8s 集群进行管理
[root@k8s-master1 ~]# mkdir -p $HOME/.kube
[root@k8s-master1 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master1 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master1 ~]# kubectl get nodes
#把 k8s-master1 节点的证书拷贝到 k8s-master2 上在 k8s-master2 创建证书存放目录:
[root@k8s-master2 ~]# cd /root && mkdir -p /etc/kubernetes/pki/etcd && mkdir -p ~/.kube/
#把 k8s-master1 节点的证书拷贝到 k8s-master2 上:
scp /etc/kubernetes/pki/ca.crt k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key k8s-master2:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt k8s-master2:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key k8s-master2:/etc/kubernetes/pki/etcd/
#证书拷贝之后在 k8s-master2 上执行如下命令,大家复制自己的,这样就可以把k8s-master2 和加入到集群,成为控制节点:
在 k8s-master1 上查看加入节点的命令:
[root@k8s-master1 ~]# kubeadm token create --print-join-command
显示如下:
kubeadm join 192.168.100.200:16443 --token zwzcks.u4jd8lj56wpckcwv \
--discovery-token-ca-cert-hash sha256:1ba1b274090feecfef58eddc2a6f45590299c1d0624618f1f429b18a064cb728 \
--control-plane
在 k8s-master2 上执行:
[root@k8s-master2 ~]#kubeadm join 192.168.100.200:16443 --token zwzcks.u4jd8lj56wpckcwv \
--discovery-token-ca-cert-hash sha256:1ba1b274090feecfef58eddc2a6f45590299c1d0624618f1f429b18a064cb728 \
--control-plane --ignore-preflight-errors=SystemVerification
[root@k8s-master2 ~]# mkdir -p $HOME/.kube
[root@k8s-master2 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master2 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
在 k8s-master1 上查看集群状况:
[root@k8s-master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane 5m44s v1.26.0
k8s-master2 NotReady control-plane 70s v1.26.0
#上面可以看到 k8s-master2 已经加入到集群了
#把 k8s-master1 节点的证书拷贝到 k8s-master3 上在 k8s-master2 创建证书存放目录:
[root@k8s-master3 ~]# cd /root && mkdir -p /etc/kubernetes/pki/etcd && mkdir -p ~/.kube/
#把 k8s-master1 节点的证书拷贝到 k8s-master2 上:
scp /etc/kubernetes/pki/ca.crt k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key k8s-master3:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt k8s-master3:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key k8s-master3:/etc/kubernetes/pki/etcd/
#证书拷贝之后在 k8s-master3 上执行如下命令,大家复制自己的,这样就可以把k8s-master3 加入到集群,成为控制节点:
在 k8s-master1 上查看加入节点的命令:
[root@k8s-master1 ~]# kubeadm token create --print-join-command
显示如下:
kubeadm join 192.168.100.200:16443 --token zwzcks.u4jd8lj56wpckcwv \
--discovery-token-ca-cert-hash sha256:1ba1b274090feecfef58eddc2a6f45590299c1d0624618f1f429b18a064cb728 \
--control-plane
在 k8s-master3 上执行:
[root@k8s-master3 ~]#kubeadm join 192.168.100.200:16443 --token zwzcks.u4jd8lj56wpckcwv \
--discovery-token-ca-cert-hash sha256:1ba1b274090feecfef58eddc2a6f45590299c1d0624618f1f429b18a064cb728 \
--control-plane --ignore-preflight-errors=SystemVerification
[root@k8s-master3 ~]# mkdir -p $HOME/.kube
[root@k8s-master3 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master3 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
在 k8s-master1 上查看集群状况:
[root@k8s-master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane 9m46s v1.25.0
k8s-master2 NotReady control-plane 5m12s v1.25.0
k8s-master3 NotReady control-plane 15s v1.25.0
上面可以看到 k8s-master3 已经加入到集群了
在 k8s-master1 上查看加入节点的命令:
[root@k8s-master1 ~]# kubeadm token create --print-join-command
显示如下:
kubeadm join 192.168.100.180:6443 --token vulvta.9ns7da3saibv4pg1 --discovery- token-ca-cert-hash sha256:72a0896e27521244850b8f1c3b600087292c2d10f2565adb56381f1f4ba7057a
把 k8s-node1 加入 k8s 集群:
[root@k8s-node1~]# kubeadm join 192.168.100.180:6443 --token vulvta.9ns7da3saibv4pg1 --discovery-token-ca-cert-hash sha256:72a0896e27521244850b8f1c3b600087292c2d10f2565adb56381f1f4ba7057a --ignore-preflight-errors=SystemVerification
#看到上面说明 k8s-node1 节点已经加入到集群了,充当工作节点
#在 k8s-master1 上查看集群节点状况:
[root@k8s-master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane 12m v1.26.0
k8s-master2 NotReady control-plane 8m10s v1.26.0
k8s-master3 NotReady control-plane 3m13s v1.26.0
k8s-node1 NotReady <none> 9s v1.26.0
k8s-node2 NotReady <none> 9s v1.26.0
#可以对 k8s-node1 打个标签,显示 work
[root@k8s-master1 ~]# kubectl label nodes k8s-node1 node-role.kubernetes.io/work=work
[root@k8s-master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 NotReady control-plane 10m v1.26.0
k8s-master2 NotReady control-plane 7m33s v1.26.0
k8s-master3 NotReady control-plane 6m33s v1.26.0
k8s-node1 NotReady work 27s v1.26.0
k8s-node2 NotReady work 27s v1.26.0
把安装 calico 需要的镜像 calico.tar.gz 传到 k8s-master1、k8s-master2、k8s-master3 和 k8s-node1 、 k8s-node2节点,手动解压:
[root@k8s-master1 ~]# ctr -n=k8s.io images import calico.tar.gz
上传 calico.yaml 到 k8s-master1 上,使用 yaml 文件安装 calico 网络插件 。
[root@k8s-master1 ~]# kubectl apply -f calico.yaml
注:在线下载配置文件地址是: https://docs.projectcalico.org/manifests/calico.yaml。
[root@k8s-master1 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-6744f6b6d5-6xlsh 1/1 Running 0 16s
calico-node-4q6pd 1/1 Running 0 16s
calico-node-64l2b 1/1 Running 0 16s
calico-node-krxkc 1/1 Running 0 16s
calico-node-m9r44 1/1 Running 0 16s
coredns-7f8cbcb969-2mp7k 1/1 Running 0 24m
coredns-7f8cbcb969-5lw75 1/1 Running 0 24m
etcd-k8s-master1 1/1 Running 0 24m
etcd-k8s-master2 1/1 Running 0 19m
etcd-k8s-master3 1/1 Running 0 14m
kube-apiserver-k8s-master1 1/1 Running 0 24m
kube-apiserver-k8s-master2 1/1 Running 1 (19m ago) 19m
kube-apiserver-k8s-master3 1/1 Running 0 14m
kube-controller-manager-k8s-master1 1/1 Running 0 24m
kube-controller-manager-k8s-master2 1/1 Running 0 18m
kube-controller-manager-k8s-master3 1/1 Running 0 14m
kube-proxy-bv6tq 1/1 Running 0 19m
kube-proxy-kphd4 1/1 Running 0 14m
kube-proxy-skdgm 1/1 Running 0 11m
kube-proxy-zvnzs 1/1 Running 0 24m
kube-scheduler-k8s-master1 1/1 Running 0 24m
kube-scheduler-k8s-master2 1/1 Running 0 19m
kube-scheduler-k8s-master3 1/1 Running 0 14m
#calico 的 STATUS 状态是 Ready,说明 k8s 集群正常运行了
[root@k8s-master1 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane 36m v1.26.0
k8s-master2 Ready control-plane 25m v1.26.0
k8s-master3 Ready control-plane 24m v1.26.0
k8s-node1 Ready work 21m v1.26.0
k8s-node2 Ready work 21m v1.26.0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rxnop5Lx-1680073363630)(D:/will.wu/images/image-20230217110144873.png)]
Calico 网络模型主要工作组件:
1、Daemonset 配置
……
containers:
# Runs calico-node container on each Kubernetes node. This
# container programs network policy and routes on each
# host.
- name: calico-node
image: docker.io/calico/node:v3.18.0
……
env:
# Use Kubernetes API as the backing datastore.
- name: DATASTORE_TYPE
value: "kubernetes"
# Cluster type to identify the deployment type
- name: CLUSTER_TYPE
value: "k8s,bgp"
# Auto-detect the BGP IP address.
- name: IP
value: "autodetect" #pod 网段
- name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16"
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Always"
calico-node 服务的主要参数如下:
CALICO_IPV4POOL_IPIP:是否启用 IPIP 模式。启用 IPIP 模式时,Calico 将在 Node 上创建一个名为 tunl0 的虚拟隧道。IP Pool 可以使用两种模式:BGP 或 IPIP。使用 IPIP 模式时,设置CALICO_IPV4POOL_IPIP="Always",不使用 IPIP 模式时,设置CALICO_IPV4POOL_IPIP="Off",此时将使用 BGP 模式。
IP_AUTODETECTION_METHOD:获取 Node IP 地址的方式,默认使用第 1 个网络接口的 IP 地址,对于安装了多块网卡的 Node,可以使用正则表达式选择正确的网卡,例如"interface=eth.*"表示选择名称以 eth 开头的网卡的 IP 地址。
- name: IP_AUTODETECTION_METHOD
value: "interface=ens33"
扩展:calico 的 IPIP 模式和 BGP 模式对比分析
1) IPIP
把一个 IP 数据包又套在一个 IP 包里,即把 IP 层封装到 IP 层的一个 tunnel,它的作用其实基本上就相当于一个基于 IP 层的网桥,一般来说,普通的网桥是基于 mac 层的,根本不需要 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来;
calico 以 ipip 模式部署完毕后,node 上会有一个 tunl0 的网卡设备,这是 ipip 做隧道封装用的, 也是一种 overlay 模式的网络。当我们把节点下线,calico 容器都停止后,这个设备依然还在,执行rmmodipip 命令可以将它删除。
2) BGP
BGP 模式直接使用物理机作为虚拟路由路(vRouter),不再创建额外的 tunnel
边界网关协议(BorderGateway Protocol, BGP)是互联网上一个核心的去中心化的自治路由协议。它通过维护 IP 路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP 不使用传统的内部网关协议(IGP)的指标,而是基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议,通俗的说就是将接入到机房的多条线路(如电信、联通、移动
等)融合为一体,实现多线单 IP;
BGP 机房的优点:服务器只需要设置一个 IP 地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统;
官方提供的 calico.yaml 模板里,默认打开了 ip-ip 功能,该功能会在 node 上创建一个设备tunl0,容器的网络数据会经过该设备被封装一个 ip 头再转发。这里,calico.yaml 中通过修改 calico- node 的环境变量:CALICO_IPV4POOL_IPIP 来实现 ipip 功能的开关:默认是 Always,表示开启; Off 表示关闭 ipip。
- name: CLUSTER_TYPE
value: "k8s,bgp"
# Auto-detect the BGP IP address.
- name: IP
value: "autodetect" # Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Always"
总结:
calico BGP 通信是基于 TCP 协议的,所以只要节点间三层互通即可完成,即三层互通的环境 bird 就能生成与邻居有关的路由。但是这些路由和 flannel host-gateway 模式一样,需要二层互通才能访问的通,因此如果在实际环境中配置了 BGP 模式生成了路由但是不同节点间 pod 访问不通,可能需要再确认下节点间是否二层互通。
为了解决节点间二层不通场景下的跨节点通信问题,calico 也有自己的解决方案——IPIP 模式
修改 k8s-master1、k8s-master2、k8s-master3 上的 etcd.yaml 文件
vim /etc/kubernetes/manifests/etcd.yaml
把
- --initial-cluster=k8s-master1=https://192.168.100.180:2380
变成如下:
- --initial- cluster=k8s-master1=https://192.168.100.180:2380,k8s-master2=https://192.168.100.181:2380,k8s-master3=https://192.168.100.183:2380
修改成功之后重启 kubelet:
[root@k8s-master1 ~]# systemctl restart kubelet
[root@k8s-master2 ~]# systemctl restart kubelet
[root@k8s-master3 ~]# systemctl restart kubelet
测试 etcd 集群是否配置成功:
[root@k8s-master1 ~]# docker run --rm -it --net host -v /etc/kubernetes:/etc/kubernetes registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0 etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt member list
Unable to find image 'registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0' locally
3.5.4-0: Pulling from google_containers/etcd
36698cfa5275: Pull complete
218162c73ec6: Pull complete
942a5aeb4815: Pull complete
3ac2be597443: Pull complete
4f1961be28e9: Pull complete
Digest: sha256:6f72b851544986cb0921b53ea655ec04c36131248f16d4ad110cb3ca0c369dc1
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0
257ab5cb19142f4b, started, k8s-master1, https://192.168.100.180:2380, https://192.168.100.180:2379, false
5b85a0d8766ad061, started, k8s-master3, https://192.168.100.182:2380, https://192.168.100.182:2379, false
aed690eda38ffb2f, started, k8s-master2, https://192.168.100.181:2380, https://192.168.100.181:2379, false
[root@k8s-master1 ~]# docker run --rm -it --net host -v /etc/kubernetes:/etc/kubernetes registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0 etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt --endpoints=https://192.168.100.180:2379,https://192.168.100.181:2379,https://192.168.100.182:2379 endpoint health --cluster
显示如下,说明 etcd 集群配置成功:
https://192.168.100.181:2379 is healthy: successfully committed proposal: took = 10.808798ms
https://192.168.100.182:2379 is healthy: successfully committed proposal: took = 11.179877ms
https://192.168.100.180:2379 is healthy: successfully committed proposal: took = 12.32604ms
[root@k8s-master1 ~]# docker run --rm -it --net host -v /etc/kubernetes:/etc/kubernetes registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0 etcdctl -w table --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt --endpoints=https://192.168.100.180:2379,https://192.168.100.181:2379,https://192.168.100.182:2379 endpoint status --cluster
显示如下
+------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.100.180:2379 | 257ab5cb19142f4b | 3.5.4 | 3.6 MB | false | false | 6 | 7287 | 7287 | |
| https://192.168.100.182:2379 | 5b85a0d8766ad061 | 3.5.4 | 3.6 MB | true | false | 6 | 7287 | 7287 | |
| https://192.168.100.181:2379 | aed690eda38ffb2f | 3.5.4 | 3.6 MB | false | false | 6 | 7287 | 7287 | |
+------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
#把 busybox-1-28.tar.gz 上传到 k8s-node1 节点,手动解压
[root@k8s-node1 ~]# ctr images import busybox-1-28.tar.gz
[root@k8s-master1 ~]# kubectl run busybox --image docker.io/library/busybox:1.28 --image-pull-policy=IfNotPresent --restart=Never --rm -it busybox -- sh
/ # ping www.baidu.com
PING www.baidu.com (39.156.66.18): 56 data bytes
64 bytes from 39.156.66.18: seq=0 ttl=127 time=39.3 ms
#通过上面可以看到能访问网络,说明 calico 网络插件已经被正常安装了
/ # nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default.svc.cluster.local Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
/ # exit #退出 pod
10.96.0.10 就是我们 coreDNS 的 clusterIP,说明 coreDNS 配置好了。解析内部 Service 的名称,是通过 coreDNS 去解析的。
#注意:
busybox 要用指定的 1.28 版本,不能用最新版本,最新版本,nslookup 会解析不到 dns 和 ip
背景:在部署 k8s 的过程中,经常要对镜像进行操作(拉取、删除、查看等)
问题:使用过程中会发现 ctr 和 crictl 有很多相同功能,也有些不同,那区别到底在哪里? 说明:
1. ctr 是 containerd 自带的 CLI 命令行工具,crictl 是 k8s 中 CRI(容器运行时接口)的客户端, k8s 使用该客户端和 containerd 进行交互;
[root@k8s-node1 ~]# cat /etc/crictl.yaml runtime-endpoint: "/run/containerd/containerd.sock" image-endpoint: ""
timeout: 0 debug: false
pull-image-on-create: false disable-pull-on-run: false
systemctl restart containerd
2. ctr 和 crictl 命令具体区别如下,也可以--help 查看。crictl 缺少对具体镜像的管理能力,可能是k8s 层面镜像管理可以由用户自行控制,能配置 pod 里面容器的统一镜像仓库,镜像的管理可以有habor 等插件进行处理。
/ # ping www.baidu.com
PING www.baidu.com (39.156.66.18): 56 data bytes
64 bytes from 39.156.66.18: seq=0 ttl=127 time=39.3 ms
#通过上面可以看到能访问网络,说明 calico 网络插件已经被正常安装了
/ # nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default.svc.cluster.local Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
/ # exit #退出 pod
10.96.0.10 就是我们 coreDNS 的 clusterIP,说明 coreDNS 配置好了。解析内部 Service 的名称,是通过 coreDNS 去解析的。
#注意:
busybox 要用指定的 1.28 版本,不能用最新版本,最新版本,nslookup 会解析不到 dns 和 ip
背景:在部署 k8s 的过程中,经常要对镜像进行操作(拉取、删除、查看等)
问题:使用过程中会发现 ctr 和 crictl 有很多相同功能,也有些不同,那区别到底在哪里? 说明:
1. ctr 是 containerd 自带的 CLI 命令行工具,crictl 是 k8s 中 CRI(容器运行时接口)的客户端, k8s 使用该客户端和 containerd 进行交互;
[root@k8s-node1 ~]# cat /etc/crictl.yaml runtime-endpoint: "/run/containerd/containerd.sock" image-endpoint: ""
timeout: 0 debug: false
pull-image-on-create: false disable-pull-on-run: false
systemctl restart containerd
2. ctr 和 crictl 命令具体区别如下,也可以--help 查看。crictl 缺少对具体镜像的管理能力,可能是k8s 层面镜像管理可以由用户自行控制,能配置 pod 里面容器的统一镜像仓库,镜像的管理可以有habor 等插件进行处理。