kubeadm构建多master多node的K8S集群
(版本:1.24.1、Containerd运行时)
作者:NAT老师(张岩峰)
一、前言
2020年12月份,当Kubernetes社区宣布1.20版本之后会逐步弃用dockershim,当时也有很多自媒体在宣传Kubernetes弃用Docker。其实,我觉得这是一种误导,也许仅仅是为了蹭热度。
dockershim是Kubernetes的一个组件,其作用是为了操作Docker。Docker是在2013年面世的,而Kubernetes是在2016年,所以Docker刚开始并没有想到编排,也不会知道会出现Kubernetes这个庞然大物(它要是知道,也不会败的那么快...)。但是Kubernetes在创建的时候就是以Docker作为容器运行时,很多操作逻辑都是针对的Docker,随着社区越来越健壮,为了兼容更多的容器运行时,才将Docker的相关逻辑独立出来组成了dockershim。
正因为这样,只要Kubernetes的任何变动或者Docker的任何变动,都必须维护dockershim,这样才能保证足够的支持,但是通过dockershim操作Docker,其本质还是操作Docker的底层运行时Containerd,而且Containerd自身也是支持CRI(Container Runtime Interface),那为什么还要绕一层Docker呢?是不是可以直接通过CRI和Containerd进行交互?这也是社区希望启动dockershim的原因之一吧。
再来看看启动dockershim究竟对用户、对维护者有多少影响。
对上层用户来说,其实并没有影响,因为上层已经屏蔽调了这些细节,只管用就可以了。更多的影响只是针对我们这些YAML工程师,因为我们主要是考虑用哪个容器运行时,如果继续用Docker,以后版本升级有没有影响?如果不用Docker,维护的成本、复杂度、学习成本会不会增加?其实我们是想多了,事情也远没那么复杂,喜欢用docker的依旧可以用docker,想用containerd的就用containerd,改动也不大,后面也有相关的部署文档。而且也只是kubernetes社区不再维护dockershim而已,Mirantis 和 Docker 已经决定之后共同合作维护 dockershim 组件,也就是说dockershim依然可以作为连接docker的桥梁,只是从kubernetes内置携带改成独立的而已。
那什么是containerd呢?
Containerd是从Docker中分离的一个项目,旨在为Kubernetes提供容器运行时,负责管理镜像和容器的生命周期。不过Containerd是可以抛开Docker独立工作的。它的特性如下:
● 支持OCI镜像规范,也就是runc
● 支持OCI运行时规范
● 支持镜像的pull
● 支持容器网络管理
● 存储支持多租户
● 支持容器运行时和容器的生命周期管理
● 支持管理网络名称空间
Containerd和Docker在命令使用上的一些区别主要如下:
功能 | Docker | Containerd |
显示本地镜像列表 | docker images | crictl images |
下载镜像 | docker pull | crictl pull |
上传镜像 | docker push | 无 |
删除本地镜像 | docker rmi | crictl rmi |
查看镜像详情 | docker inspect IMAGE-ID | crictl inspecti IMAGE-ID |
显示容器列表 | docker pscrictl ps | crictl ps |
创建容器 | docker create | crictl create |
启动容器 | docker start | crictl start |
停止容器 | docker stop | crictl stop |
删除容器 | docker rm | crictl rm |
查看容器详情 | docker inspect | crictl inspect |
attach | docker attach | crictl attach |
exec | docker exec | crictl exec |
logs | docker logs | crictl logs |
stats | docker stats | crictl stats |
可以看到使用方式大同小异。
下面介绍一下使用kubeadm安装K8S集群,并使用containerd作为容器运行时的具体安装步骤。
二、环境规划
实验环境规划:
podSubnet(pod网段):10.244.0.0/16
serviceSubnet(service网段):10.10.0.0/16
VIP:192.168.43.100
系统版本:CentOS 7.9操作系统版本
角色 | IP | 主机名 | 组件 | 硬件 |
控制节点 | 192.168.43.101 | k8s-master01 | apiserver controller-manager scheduler etcd containerd keepalived+nginx | CPU:4vCPU 硬盘:100G 内存:2GB 开启虚拟化 |
控制节点 | 192.168.43.102 | k8s-master02 | apiserver controller-manager scheduler etcd containerd keepalived+nginx | CPU:4vCPU 硬盘:100G 内存:2GB 开启虚拟化 |
工作节点 | 192.168.43.201 | k8s-node01 | kubelet kube-proxy containerd calico coredns | CPU:6vCPU 硬盘:100G 内存:4GB 开启虚拟化 |
工作节点 | 192.168.43.202 | k8s-node02 | kubelet kube-proxy containerd calico coredns | CPU:6vCPU 硬盘:100G 内存:4GB 开启虚拟化 |
拓扑图:
三、初始化系统环境
1、配置机器主机名
43.101节点执行:
[root@192 ~]# hostnamectl set-hostname k8s-master01 && bash
43.102节点执行:
[root@192 ~]# hostnamectl set-hostname k8s-master02 && bash
43.201节点执行:
[root@192 ~]# hostnamectl set-hostname k8s-node01 && bash
43.202节点执行:
[root@192 ~]# hostnamectl set-hostname k8s-node02 && bash
2、配置hosts解析
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# vi /etc/hosts
192.168.43.101 k8s-master01
192.168.43.102 k8s-master02
192.168.43.201 k8s-node01
3、配置主机之间无密码登录
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# ssh-keygen
[root@k8s-master01 ~]# ssh-copy-id k8s-master01
[root@k8s-master01 ~]# ssh-copy-id k8s-master02
[root@k8s-master01 ~]# ssh-copy-id k8s-node01
[root@k8s-master01 ~]# ssh-copy-id k8s-node02
4、关闭交换分区swap,提升性能
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# swapoff -a
永久关闭:注释swap挂载,给swap这行开头加一下注释
[root@k8s-master01 ~]# vi /etc/fstab
#/dev/mapper/centos-swap swap swap defaults 0 0
为什么要关闭swap交换分区?
Swap是交换分区,如果机器内存不够,会使用swap分区,但是swap分区的性能较低,k8s设计的时候为了能提升性能,默认是不允许使用swap分区的。Kubeadm初始化的时候会检测swap是否关闭,如果没关闭,那就初始化失败。如果不想要关闭交换分区,安装k8s的时候可以指定--ignore-preflight-errors=swap来解决。
5、修改机器内核参数
43.101、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# modprobe br_netfilter
[root@k8s-master01 ~]# echo "modprobe br_netfilter" >> /etc/profile
[root@k8s-master01 ~]# cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
[root@k8s-master01 ~]# sysctl -p /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.conf文件中加载。
● 为什么要执行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
● 为什么开启net.bridge.bridge-nf-call-iptables内核参数?
在centos下安装docker,执行docker info出现如下警告:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
解决办法:
vi /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
● 为什么要开启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转发功能已经打开。
6、关闭firewalld防火墙
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# systemctl stop firewalld;systemctl disable firewalld
7、关闭selinux
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
[root@k8s-master01 ~]# setenforce 0
8、配置阿里云repo源
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# yum -y install wget
[root@k8s-master01 ~]# cd /etc/yum.repos.d/
[root@k8s-master01 ~]# wget http://mirrors.aliyun.com/repo/epel-7.repo
[root@k8s-master01 ~]# wget http://mirrors.163.com/.help/CentOS7-Base-163.repo
[root@k8s-master01 ~]# yum clean all
[root@k8s-master01 ~]# yum makecache
9、配置时间同步
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# yum -y install ntpdate
[root@k8s-master01 ~]# ntpdate cn.pool.ntp.org
[root@k8s-master01 ~]# crontab -e
* */1 * * * /usr/sbin/ntpdate cn.pool.ntp.org>/dev/null
[root@k8s-master01 ~]# systemctl restart crond
10、开启ipvs
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# vi /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"
for kernel_module in ${ipvs_modules}; do
/sbin/modinfo -F filename ${kernel_module} > /dev/null 2>&1
if [ 0 -eq 0 ]; then
/sbin/modprobe ${kernel_module}
fi
done
[root@k8s-master01 ~]# chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs
问题:
● ipvs是什么?
ipvs(IP Virtual Server)实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为Linux内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个IP地址上显示为虚拟服务。
● ipvs和iptable对比分析
kube-proxy支持iptables和ipvs两种模式,在kubernetes v1.8中引入了ipvs模式,在v1.9中处于beta阶段,在v1.11中已经正式可用了。iptables 模式在v1.1中就添加支持了,从v1.2版本开始iptables就是kube-proxy默认的操作模式,ipvs和iptables都是基于netfilter的,但是ipvs采用的是hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。那么ipvs模式和iptables模式之间有哪些差异呢?
1、ipvs为大型集群提供了更好的可扩展性和性能
2、ipvs支持比iptables更复杂的复制均衡算法(最小负载、最少连接、加权等等)
3、ipvs支持服务器健康检查和连接重试等功能
11、安装基础软件包
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# yum install -y yum-utils 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 ntpdate telnet ipvsadm
12、安装iptables
43.101、43.102、43.201、43.202节点执行如下:(可省略)
[root@k8s-master01 ~]# yum install iptables-services -y
[root@k8s-master01 ~]# service iptables stop && systemctl disable iptables
[root@k8s-master01 ~]# iptables -F
四、构建K8S集群
1、安装k8s repo源
43.101、43.102、43.201、43.202节点执行如下:
# 下面是阿里云的yum源
[root@k8s-master01 ~]# vi /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
[root@k8s-master01 ~]# yum makecache
[root@k8s-master01 ~]# yum clean all
2、部署containerd容器
43.101、43.102、43.201、43.202节点执行如下:
安装docker-ce源:
[root@k8s-master01 ~]#yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装、配置、启动containerd容器:
# 安装
[root@k8s-master01 ~]#yum -y install containerd
# 配置
[root@k8s-master01 ~]#containerd config default > /etc/containerd/config.toml
修改cgroup Driver为systemd
在配置文件中如下位置添加SystemdCgroup = true
[root@k8s-master01 ~]# sed -i '/runc.options/a\ SystemdCgroup = true' \
/etc/containerd/config.toml && \
grep 'SystemdCgroup = true' -B 7 /etc/containerd/config.toml
镜像加速
endpoint位置添加阿里云的镜像源
[root@k8s-master01 ~]# vi /etc/containerd/config.toml
"https://q2gr04ke.mirror.aliyuncs.com"
更改sandbox_image
[root@k8s-master01 ~]# vi /etc/containerd/config.toml
"registry.aliyuncs.com/google_containers/pause:3.2"
# 启动
[root@k8s-node01 ~]#systemctl restart containerd && systemctl enable containerd && systemctl status containerd
3、安装初始化k8s需要的软件包
43.101、43.102、43.201、43.202节点执行如下:
[root@k8s-master01 ~]# yum install -y kubelet-1.24.1 kubeadm-1.24.1 kubectl-1.24.1
# 设置运行时
[root@k8s-node01 ~]# crictl config runtime-endpoint /run/containerd/containerd.sock
# 启动kubelet
[root@k8s-master01 ~]# systemctl enable kubelet && systemctl restart kubelet && systemctl status kubelet
提示:每个软件包的作用
Kubeadm:kubeadm是一个工具,用来初始化k8s集群的
Kubelet:安装在集群所有节点上,用于启动Pod的
Kubectl:通过kubectl可以部署和管理应用,查看各种资源,创建、删除和更新各种组件。
4、keepalive+nginx实现k8s apiserver节点高可用
43.101、43.102节点执行如下:
# 安装
[root@k8s-master01 ~]# yum install -ykeepalived nginx nginx-mod-stream
# 配置nginx代理,43.101、43.102节点配置都一样
[root@k8s-master01 ~]# vi /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;
}
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.43.101:6443;
server 192.168.43.102:6443;
}
server {
listen 16443;
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 / {
}
}
}
# 43.101 keepalived配置:
[root@k8s-master01 ~]# vi /etc/keepalived/keepalived.conf
global_defs {
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
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.43.100/24
}
track_script {
check_nginx
}
}
解释如下:
[root@k8s-master01 ~]# vi /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
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
}
virtual_ipaddress {
192.168.43.100/24
}
track_script {
check_nginx
}
}
# 43.101 keepalived故障检测脚本
[root@k8s-master01 ~]# vi /etc/keepalived/check_nginx.sh
#!/bin/bash
count=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$")
if [ "$count" -eq 0 ];then
systemctl stop keepalived
fi
[root@k8s-master01 ~]# chmod +x /etc/keepalived/check_nginx.sh
# 43.102 keepalived配置文件:
[root@k8s-master02 ~]# vi /etc/keepalived/keepalived.conf
global_defs {
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
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.43.100/24
}
track_script {
check_nginx
}
}
# 43.102 keepalived故障检测脚本
[root@k8s-master02 ~]# vi /etc/keepalived/check_nginx.sh
#!/bin/bash
count=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$")
if [ "$count" -eq 0 ];then
systemctl stop keepalived
fi
[root@k8s-master02 ~]# chmod +x /etc/keepalived/check_nginx.sh
# 43.101、43.102启动nginx、keepalived服务
[root@k8s-master01 ~]# systemctl restart nginx && systemctl enable nginx && systemctl status nginx
[root@k8s-master01 ~]# systemctl restart keepalived && systemctl enable keepalived && systemctl status keepalived
# 测试VIP
在k8s-master01节点停止nginx测试:
[root@k8s-master01 ~]# systemctl stop nginx
5、kubeadm初始化k8s集群
在k8s-master01创建初始化yaml文件:
[root@k8s-master01 ~]# cat kubeadm-config.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: 192.168.43.101
bindPort: 6443
nodeRegistration:
criSocket: /run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
name: k8s-master01
taints: null
---
apiServer:
certSANs:
- 192.168.43.100
- 192.168.43.101
- 192.168.43.102
- 192.168.43.201
- 192.168.43.202
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.24.1
controlPlaneEndpoint: 192.168.43.100:16443
networking:
dnsDomain: cluster.local
serviceSubnet: 10.10.0.0/16
podSubnet: 10.244.0.0/16
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
# 参数解释:
[root@k8s-master01 ~]# cat kubeadm-config.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: 192.168.43.101#master节点IP
bindPort: 6443#
nodeRegistration:
criSocket: /run/containerd/containerd.sock#containerdcri sock位置
imagePullPolicy: IfNotPresent
name: k8s-master01#主机名
taints: null
---
apiServer:
certSANs:#将master和node节点放入,等下签发证书要用
- 192.168.43.100
- 192.168.43.101
- 192.168.43.102
- 192.168.43.201
- 192.168.43.202
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers#阿里云镜像源
kind: ClusterConfiguration
kubernetesVersion: 1.24.1#k8s版本号
controlPlaneEndpoint: 192.168.43.100:16443#vip集群入口
networking:
dnsDomain: cluster.local
serviceSubnet: 10.10.0.0/16#svc网段
podSubnet: 10.244.0.0/16#pod网段
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
使用kubeadm初始化k8s集群
[root@k8s-master01 ~]# kubeadm init --config kubeadm-config.yaml
显示如下:就说明安装成功:
#如下命令是把node节点加入集群,需要保存下来,每个人的都不一样
kubeadm join 192.168.43.100:16443 --token 4kqxwe.c93hksteyv7zl7w3 \
--discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b \
--control-plane
#创建.kube目录
[root@k8s-master01 ~]# mkdir -p $HOME/.kube
[root@k8s-master01 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master01 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
#查看集群状态
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane,master 2m57s v1.24.1
6、扩展K8S集群-添加master节点
把k8s-master01节点的证书拷贝到k8s-master02上
# 在k8s-master02创建证书存放目录:
[root@k8s-master02 ~]# cd /root && mkdir -p /etc/kubernetes/pki/etcd && mkdir -p ~/.kube/
# 把k8s-master01节点的证书拷贝到k8s-master02上:
在k8s-master01节点执行:
scp /etc/kubernetes/pki/ca.crt k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/ca.key k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.key k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/sa.pub k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.crt k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/front-proxy-ca.key k8s-master02:/etc/kubernetes/pki/
scp /etc/kubernetes/pki/etcd/ca.crt k8s-master02:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/pki/etcd/ca.key k8s-master02:/etc/kubernetes/pki/etcd/
证书拷贝之后在k8s-master02上执行如下命令,大家复制自己的,这样就可以把k8s-master02和加入到集群,成为控制节点:
# 在k8s-master01上查看加入节点的命令:
[root@k8s-master01 ~]# kubeadm token create --print-join-command
kubeadm join 192.168.43.100:16443 --token 6amtpd.xq78514c5hu5cmjg --discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b
# 在k8s-master02上加入k8s-master01节点:
[root@k8s-master02 ~]# kubeadm join 192.168.43.100:16443 --token 6amtpd.xq78514c5hu5cmjg --discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b --control-plane
# 创建.kube目录
[root@k8s-master02 ~]# mkdir -p $HOME/.kube
[root@k8s-master02 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master02 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 查看集群节点状态
[root@k8s-master02 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane,master 23m v1.24.1
k8s-master02 NotReady control-plane,master 53s v1.24.1
7、扩展K8S集群-添加node节点
在任意master节点上查看加入节点的命令:
[root@k8s-master02 ~]# kubeadm token create --print-join-command
kubeadm join 192.168.43.100:16443 --token p4ts04.deou5jiplq7z6k6b --discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b
把k8s-node01和k8s-node02加入k8s集群:
[root@k8s-node01 ~]# kubeadm join 192.168.43.100:16443 --token p4ts04.deou5jiplq7z6k6b --discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b
[root@k8s-node02 ~]# kubeadm join 192.168.43.100:16443 --token p4ts04.deou5jiplq7z6k6b --discovery-token-ca-cert-hash sha256:36b6f0bc7ca427dde11e01cc9d276ec9655ef2e324199d4297b6a038d4190c5b
在任意master节点上查看集群节点状况:
[root@k8s-master01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane,master 22h v1.24.1
k8s-master02 NotReady control-plane,master 22h v1.24.1
k8s-node01 NotReady <none> 62s v1.24.1
k8s-node02 NotReady <none> 57s v1.24.1
设置role,任意master节点执行
[root@k8s-master01 ~]# kubectl label node k8s-master01 node-role.kubernetes.io/control-plane-
node/k8s-master01 labeled
[root@k8s-master01 ~]# kubectl label node k8s-master02 node-role.kubernetes.io/control-plane-
node/k8s-master02 labeled
[root@k8s-master01 ~]# kubectl label node k8s-node01 node-role.kubernetes.io/work=
node/k8s-node01 labeled
[root@k8s-master01 ~]# kubectl label node k8s-node02 node-role.kubernetes.io/work=
# 查看集群状态
[root@k8s-master01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady master 23h v1.24.1
k8s-master02 NotReady master 22h v1.24.1
k8s-node01 NotReady work 3m10s v1.24.1
k8s-node02 NotReady work 3m5s v1.24.1
8、安装kubernetes网络组件-Calico
Master节点部署calico组件
[root@k8s-master01 ~]# kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
再次查看集群状态:
[root@k8s-master01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready master 30m v1.24.1
k8s-master02 Ready master 30m v1.24.1
k8s-node01 Ready worker 22m v1.24.1
k8s-node02 Ready worker 18m v1.24.1
# 检查pod状态
[root@k8s-master01 ~]# kubectl get pods -n kube-system
STATUS状态是Ready,说明k8s集群正常运行了
9、测试在k8s创建pod是否可以正常访问网络
在master执行启动pod:
[root@k8s-master01 ~]# kubectl run busybox --image busybox:latest --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # 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=49 time=37.353 ms
# 通过上面可以看到能访问网络,说明calico网络插件已经被正常安装了
10、测试k8s集群中部署tomcat服务
在k8s-master节点执行:
创建pod:
[root@k8s-master01 ~]# vi tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
namespace: default
labels:
app: myapp
env: dev
spec:
containers:
- name: tomcat-pod-java
ports:
- containerPort: 8080
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
解释如下:
apiVersion: v1 #pod属于k8s核心组v1
kind: Pod #创建的是一个Pod资源
metadata: #元数据
name: demo-pod #pod名字
namespace: default #pod所属的名称空间
labels:
app: myapp #pod具有的标签
env: dev #pod具有的标签
spec:
containers: #定义一个容器,容器是对象列表,下面可以有多个name
- name: tomcat-pod-java #容器的名字
ports:
- containerPort: 8080
image: tomcat:8.5-jre8-alpine #容器使用的镜像
imagePullPolicy: IfNotPresent
[root@k8s-master01 ~]# kubectl apply -f tomcat.yaml
[root@k8s-master01 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-pod 1/1 Running 0 2m5s
创建svc:
[root@k8s-master01 ~]# vi tomcat-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30080
selector:
app: myapp
env: dev
[root@k8s-master01 ~]# kubectl apply -f tomcat-svc.yaml
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9h
tomcat NodePort 10.103.122.178 <none> 8080:30080/TCP 5s
在浏览器上测试访问:
11、测试coredns是否正常
操作如下:
[root@k8s-master01 ~]# kubectl run dig --rm -it --image=docker.io/azukiapp/dig /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup kubernetes.default.svc.cluster.local
Server: 10.10.0.10
Address: 10.10.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.10.0.1
/ # nslookup www.baidu.com
Server: 10.10.0.10
Address: 10.10.0.10#53
Non-authoritative answer:
Name: www.baidu.com
Address: 180.101.49.12
Name: www.baidu.com
Address: 180.101.49.11
10.96.0.10就是我们coreDNS的clusterIP,说明coreDNS配置好了。
解析内部Service的名称,是通过coreDNS去解析的。
注意:busybox自带的nslookup实现的不是很完全,会导致测试DNS失败。所以这里使用的是带nslookup的alphine。