背景
Docker是一个非常流行的容器化平台,它可以让我们方便构建、打包、发布和运行容器化应用程序。但是,在生产环境中,我们可能需要处理成百上千个容器,需要更好的管理这些容器,这就是Kubernetes(K8S)的用武之地。
K8S是一个开源容器编排系统,它可以管理和部署容器化应用程序,自动化容器部署、扩展和故障恢复。K8S可以让我们更好管理容器与容器相关的资源和服务,同时提供了许多强大的功能,如:负载均衡、自动扩展、滚动更新、健康检查等。
K8S的安装方法有很多,但官方推荐的只包括Kubeadm和二进制安装。因为Kubeadm和二进制安装可以提供更加稳定、更适合生产环境的K8S。本章介绍下如何使用Kubeadm安装K8S集群。
先了解下,两种安装方式(Kubeadm和二进制)的适用场景。Kubeadm是官方提供的开源工具,用于快速搭建K8S集群,也是比较方便和推荐的方式。其中的kubeadm init
和kubeadm join
这两个命令可以快速创建K8S集群。Kubeadm可以初始化K8S,且所有的组件都以Pod形式运行,具有故障自恢复能力。
Kubeadm相当于使用程序脚本帮助我们自动完成集群安装,简化部署操作,证书、组件资源清单文件都是自动创建的。自动部署屏蔽了很多细节,使用者对各个模块的了解较少,遇到问题比较难排错。因此,Kubeadm适合需要经常部署K8S或对自动化要求比较高的场景使用。二进制安装就是手动安装,步骤繁琐,对K8S理解的更加全面。
环境准备
服务器
生产环境的K8S需要在服务器上安装,这样表现会更加稳定,若没有生产环境服务器,可以使用虚拟机方式创建3个CentOS7
的虚拟机,网络使用桥接或NAT模式都可以。
网络规划
K8S网络规划:
-
podSubnet(Pod网段)
10.244.0.0/16
:在K8s中,每个Pod都有一个唯一的IP地址,这个IP地址是在Pod启动时动态分配的。这些Pod IP地址属于一个特定的IP地址段,称为Pod网络。Pod网络是在k8s网络模型中实现的,它允许不同的Pod相互通信,同时允许集群中其他部分与Pod进行通信。 -
serviceSubnet(Service网段)
10.96.0.0/12
:在k8s集群中,Service是一种资源对象,用于提供稳定的服务访问入口。它是一组具有相同标签的Pod的抽象,可以通过一个虚拟IP地址和端口暴露出来。 -
物理机网段
192.168.153.0/24
:表示IP从192.168.153.1
到192.168.153.254
这个范围内的所有地址都可以在该网络内分配使用Tips:Pod和Service的网段不能和物理网段一致,这是因为它们是在集群内部使用的虚拟网络,需要避免和物理机上的网络地址冲突,防止出现不必要的问题。另外,使用不同网段也有助于更好的隔离容器和宿主机之间的网络。因此建议,在部署K8s集群时,将Pod和Service的网段分别设置为独立网段,与物理机网段区分。
K8s集群机器部署组件清单
集群角色 | IP | 主机名 | 组件 |
---|---|---|---|
控制节点 | 192.168.153.180 | xiaolumaster1 | apiserver、controller-manager、schedule、kubelet、etcd、kube-proxy、容器运行时、calico、kubeadm |
工作节点 | 192.168.153.181 | xiaolunode1 | kube-proxy、calico、coredns、容器运行时、kubelet、kubeadm |
工作节点 | 192.168.153.182 | xiaolunode2 | kube-proxy、calico、coredns、容器运行时、kubelet、kubeadm |
安装K8s的机器必须进行相应的初始化设置,否则Kubeadm安装K8s预检查会失败,导致无法继续。下面搞一搞初始化操作。
机器初始化
配置静态IP
服务器或虚拟机的IP地址默认都是DHCP动态分配的,这样重启机器IP地址就会变化,为让IP固定不变,需设置静态IP。
编辑文件:
vim /etc/sysconfig/network-scripts/ifcfg-ens32
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
IPADDR="192.168.153.180"
NETMASK="255.255.255.0"
GATEWAY="192.168.153.2"
DNS1="192.168.153.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="ens32"
UUID="cfcc634b-f183-4e48-a16a-9d3dfd8f8ddb"
DEVICE="ens32"
ONBOOT="yes"
- BOOTPROTO=“static”:使用静态地址
- IPADDR=“192.168.153.180” IP地址,需要和自己计算机所在的网段一致
- NETMASK=“255.255.255.0” 子网掩码,需要和自己计算机所在的网段一致
- GATEWAY=“192.168.153.2” 网关,可以使用
route -n
查看自己电脑网关地址 - ONBOOT=“yes” 开机启动网络,必须yes
修改配置文件之后,需要重启网络才能使配置生效,命令:
service network restart
看下ip地址已经改变了。
另外两台机器(工作节点),同样的方式设置好,同上的机器部署清单中,将ip先设置好。
配置机器主机名
在K8s集群中,每个节点都需要一个唯一的名称标识自己,这个名称需要在加入集群时使用。若设置主机名,管理员可以更轻松管理容器,方便通过主机名识别和访问每个节点。
- 192.168.153.180设置为xiaolumaster1
hostnamectl set-hostname xiaolumaster1 && bash
- 192.168.153.181设置为xiaolunode1
hostnamectl set-hostname xiaolunode1 && bash
- 192.168.153.182设置为xiaolunode2
hostnamectl set-hostname xiaolunode2 && bash
配置hosts文件
配置hosts文件让每个k8s节点通过主机名互相通信,不需要记ip地址了,修改每台机器的/etc/hosts
文件,增加3行
192.168.153.180 xiaolumaster1
192.168.153.181 xiaolunode1
192.168.153.182 xiaolunode2
配置控制节点到工作节点免密登录
在k8s集群中,控制节点需要能通过SSH链接到工作节点中,以执行各种命令和任务,如管理Pod、检查节点状态等。每次都输入密码登录,非常麻烦,建议配置ssh免密登录,提高工作效率。
在控制节点生成ssh密钥
[root@xiaolumaster1 ~]# ssh-keygen
选项直接回车,默认即可。
可以看到密钥文件生成在root目录下的.ssh
目录中。默认情况下,生成一个id_rsa
私钥文件和id_rsa.pub
公钥文件,私钥应该保持安全,只有持有私钥的用户才能对它进行身份验证。公钥文件交给其他计算机上的授权用户,以便将它添加到本地计算机的授权列表,进而允许该用户在本地计算机上进行ssh连接。
接下来执行命令,将公钥文件发送给各个k8s节点服务器:
[root@xiaolumaster1 ~]# ssh-copy-id xiaolumaster1
[root@xiaolumaster1 ~]# ssh-copy-id xiaolunode1
[root@xiaolumaster1 ~]# ssh-copy-id xiaolunode2
以上命令分别将当前用户的公钥文件(默认~/.ssh/id_rsa.pub)复制到三个节点中,便于用户ssh免密登录。
ssh-copy-id
工具会自动使用SSH协议进行连接,在目标计算机建立.ssh
目录(若不存在),并将当前用户的公钥追加到目标计算机的~/.ssh/authorized_keys
文件中。
关闭交换区
Linux中交换分区(Swap)类似于Windows的虚拟内存,就是当内存不足时,把一部分硬盘空间虚拟成内存使用,解决内存容量不足的问题。
在k8s集群中,关闭交换分区可以确保内存不被交换出去,避免内存不足导致应用程序崩溃和节点异常。因为k8s在每个节点部署多个容器,若节点上的应用程序的内存超过了可用内存,操作系统就会将部分的内存换出到硬盘,降低了容器的性能和稳定性。所以在部署k8s集群时,需要关闭交换分区。
两种关闭方式,一种临时,一种永久
1.临时方案
[root@xiaolumaster1 ~]# swapoff -a
[root@xiaolunode1 ~]# swapoff -a
[root@xiaolunode2 ~]# swapoff -a
2.永久性
vim打开/etc/fstab
文件,直接注释掉挂载交换分区即可。三台机器都注释掉。
#/dev/mapper/centos-swap swap swap defaults 0 0
fstab全称(File System Table),系统启动时,会读取这个文件的数据,并根据其中的信息自动挂载文件系统。
所以最好重启下机器,重新读取一下fstab文件,或者再执行下临时方案就行了。
修改内核参数
1.加载br_netfilter模块
br_netfilter叫透明防火墙,又称桥接模式防火墙。就是在网桥设备中增加防火墙功能。开启ip6tables和iptables需要加载透明防火墙。
[root@xiaolumaster1 ~]# modprobe br_netfilter
[root@xiaolunode1 ~]# modprobe br_netfilter
[root@xiaolunode2 ~]# modprobe br_netfilter
2.启动相关内核参数
在安装配置k8s集群时,需要开启一些内核参数以确保网络功能的正常运行。
- net.bridge.bridge-nf-call-ip6tables=1 允许iptables对IPV6数据包进行处理
- net.bridge.bridge-nf-call-iptables=1 允许iptables对桥接数据包进行处理,这是容器间通信必须的
- net.ipv4.ip_forward=1 linux中允许IP转发功能,使得数据包在不同网络间进行路由
三台机器都需执行
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
sysctl -p /etc/sysctl.d/k8s.conf
关闭防火墙
在安装k8s集群时,关闭Firewalld防火墙可以避免由于防火墙造成的k8s集群组件无法正常通信的问题。k8s需要使用大量的网络端口进行通信,包括etcd、kubelet、kube-proxy等组件都需要开放对应的端口才能工作。
在关闭防火墙前,确保已经采取了安全措施,如安全组来保护节点安全问性。
三台机器都执行。
systemctl stop firewalld; systemctl disable firewalld
关闭SELinux
安装k8s集群,通常关闭SELinux,默认情况下,SELinux可能会阻止k8s某些操作,如挂载卷和访问容器日志等。可能使k8s无法正常工作。
1.三台机器关闭SELinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
2.重启服务器
3.验证是否已经关闭
getenforce
显示Disabled,那么说明已经关闭了。
配置安装Docker和Containerd需要的阿里云在线yum源
配置阿里yum源可以提高下载速度,三台机器都执行
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
配置安装k8s组件需要的阿里云yum源
k8s命令包在本地源是不存在的,需要配置阿里云yum源安装k8s命令工具。直接在主节点中配置好,然后通过scp命令拷给其他两个节点即可。
vim /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
通过远程复制发送到其他两个节点上。
scp /etc/yum.repos.d/kubernetes.repo xiaolunode1:/etc/yum.repos.d/
scp /etc/yum.repos.d/kubernetes.repo xiaolunode2:/etc/yum.repos.d/
配置时间同步
在k8s集群中,时间同步很重要,因为k8s各个组件之间需要通过时间戳确定事件的先后顺序,若各个节点的时间不同步,会导致k8s出现各种问题。三台机器都执行。
yum -y install ntpdate # 安装软件
ntpdate cn.pool.ntp.org # 同步网络时间
crontab -e
* * * * * /usr/sbin/ntpdate cn.pool.ntp.org # 定时任务同步时间,每分钟执行一次
重启定时任务
service crond restart
安装Docker-CE和Containerd服务
K8s是一个容器编排和管理系统,它的任务是在集群中部署、运行和管理容器化应用程序。因此,Kubernetes需要一个容器运行时来管理容器,以便能够将容器化的应用程序部署和运行在集群中。Docker和Containerd都是常用的容器运行时,因此在安装Kubernetes前需要安装其一。
从k8s1.20版本开始,k8s官方将默认的容器运行时从Docker改为了Containerd。在1.24版本后,Docker作为容器运行时已经被弃用,Containerd成为唯一推荐的容器运行时,所有节点均安装,安装步骤如下:
1.安装Containerd
yum install -y containerd.io-1.6.6 # 安装containerd
# 生成containerd配置文件
containerd config default > /etc/containerd/config.toml
vim /etc/containerd/config.toml
# 修改/etc/containerd/config.toml,只需改动一下内容
SystemdCgroup = true
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.7"
- SystemdCgroup = true 代表Containerd驱动用Systemd,在k8s中,容器运行时需要与宿主机的Cgroup和Namespace进行交互,管理容器资源。
- sandbox_image = “registry.aliyuncs.com/google_containers/pause:3.7”,设置为阿里云镜像仓库中的pause:3.7。
2.创建/etc/crictl.yaml
文件
cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
这个文件是crictl工具的配置文件,用于指定与Containerd交互的相关设置。
指定unix:///run/containerd/containerd.sock
是为了告诉crictl使用UNIX套接字的方式来连接Containerd的API。Containerd提供了一个Socket文件unix:///run/containerd/containerd.sock
,crictl通过连接这个Socket文件可以与Containerd进行通信,实现管理容器和镜像等操作。
3.配置Containerd镜像加速器
编辑/etc/containerd/config.toml
文件
vim /etc/containerd/config.toml
config_path = "/etc/containerd/certs.d" #指定containerd的证书存放目录
创建证书等目录文件
# 创建目录
mkdir /etc/containerd/certs.d/docker.io/ -p
vim /etc/containerd/certs.d/docker.io/hosts.toml # 创建文件
# 内容如下
[host."https://6yqx5sih.mirror.aliyuncs.com",host."https://registry.docker-cn.com"]
capabilities = ["pull","push"]
4.重启Containerd来使配置生效
systemctl restart containerd
5.安装Docker,配置Docker镜像加速
yum install -y docker-ce
systemctl enable docker
vim /etc/docker/daemon.json
{
"registry-mirrors":[
"https://6yqx5sih.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com"
]
}
systemctl restart docker
安装部署Kubernetes集群
安装Kubernetes集群需要的包
所有节点都需要执行。
yum install -y kubelet-1.27.0 kubeadm-1.27.0 kubectl-1.27.0
- kubelet:k8s的一个核心组件,负责在每个节点上运行Pod并管理声明周期,它通过容器运行时(Docker或Containerd)来运行容器。kubelet负责监控容器状态、资源使用情况和网络连接情况,将这些信息报告给k8s其他组件,以便它们协调容器在集群中的运行。
- Kubeadm:用于启动k8s集群的命令工具。
- Kubectl:k8s的命令行工具,管理k8s集群的各个方面,包括创建、部署、管理和监控应用程序、服务和资源。Kubectl可以和K8s API服务器交互,管理集群。
#开机自启
systemctl enable kubelet
Kubeadm初始化Kubernetes集群
这里只需要controller控制节点来初始化即可,然后其他work节点join进来。
kubeadm config print init-defaults > kubeadm.ymal
kubeadm config print init-defaults
:是Kubeadm的命令,用于打印默认的Kubernetes初始化配置内容,并且输出到一个文件中。之后使用kubeadm init初始化k8s集群,可以使用这个文件作为输入,而不是手动输入。添加并修改相应的配置,如下
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.153.180 # ip地址
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
name: xiaolumaster1 # 主机
taints: null
---
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.27.0
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16 # pod网段
serviceSubnet: 10.96.0.0/12 # service网段
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
kubeadm初始化Kubenetes集群
kubeadm init --config=kubeadm.ymal --ignore-preflight-errors=SystemVerification
如图,说明已经安装完成。
重置k8s集群
我们执行完毕kubeadm init后发现不想把这台机器作为controller来使用了,那么我们可以使用kubeadm reset
命令将k8s集群进行重置。
kubeadm reset
配置Kubectl配置文件config
默认安装K8s后,Kubectl是无权限访问K8s的API的,所以需要一个config文件,相当于是对kubectl进行授权,这样Kubectl命令可以使用config文件中的用户和证书对k8s集群进行管理。
主目录创建一个.kube目录,存放全局config文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config # 将config拷过来更名
sudo chown $(id -u):$(id -g) $HOME/.kube/config # 设置权限
- 查看k8s集群
kubectl get nodes
有一个名为xiaolumaster1
的控制节点名称,集群状态NotReady,因为没有安装网络插件。
扩容Kubernets集群
通过前面的安装步骤,是单节点的Kubernetes,即整个集群只有一个controller控制节点。在k8s中,控制节点是有污点的,不允许Pod调度,控制节点是不希望有业务Pod运行的,所以需要扩容增加工作节点。
在controller(控制节点,以下内容中,控制节点统称controller,工作节点称为work)上,创建加入节点的命令行:
kubeadm token create --print-join-command
kubeadm join 192.168.153.180:6443 --token mqp4fj.6q9n6fglby7d7c1z --discovery-token-ca-cert-hash sha256:2e16927670268b431886daca133777d82072c9b87864dbbe6092de7bbda55a29
work节点需要执行上面的kubeadm join
命令以加入到节点中,执行后,结果如下
可以看到,集群中又增加了两位小伙伴,它们的角色现在都是None,通常来讲我们是将另外两个none角色的节点称之为工作节点,在controller中将它们两个设置为worker即可
kubectl label node xiaolunode1 node-role.kubernetes.io/worker=worker
kubectl label node xiaolunode2 node-role.kubernetes.io/worker=worker
ok了,集群中状态都是NotReady状态,我们安装完网络插件就好了。
安装网络插件Calico
上传calico.yaml文件到controller上,使用ymal文件安装Calico。
kubectl apply -f calico.yaml
使用kubectl部署k8s网络插件calico。
- kubectl apply : 用于通过yml文件来创建或更新Kubernetes资源
- -f calico.yaml 将指定的yml文件应用于当前的k8s环境
安装完毕后,再次查看k8s集群状态。
kubectl get nodes
温馨Tips:若发现经过此步骤一直有节点NotReady,可以将所有机器进行kubeadm reset
,重启kubelet命令systemctl restart kubelet
,然后重新执行一遍上面的初始化集群步骤,然后先安装完毕calico之后,再重新加入两个节点即可。
网络测试&DNS测试
测试网络
测试下k8s中创建的Pod能否正常访问网络。
kubectl run busybox4 --image busybox:1.28 --restart=Never --rm -it busybox -- sh
/ # ping www.baidu.com
在k8s集群上创建了一个名为busybox4的Pod,然后在此Pod内运行了一个BusyBox容器。
最后在/的工作目录中,ping了一下www.baidu.com,然后显示IP地址、数据字节等。可以看到,在k8s中创建的Pod能访问,说明Calico网络插件已经正常安装了,可以访问网络。
测试CoreDNS是否正常
CoreDNS是一个Kubernetes集群中非常重要的DNS服务器,它通过提供命名服务简化服务间 通信和DNS解析的管理和维护。
在K8s中,每个Pod有一个唯一的DNS名称,如pod-name.namespace-name.svc.cluster-domain.tld,其中cluster-domain.tld是集群中使用的域名后缀。每个服务都有一个DNS名称,pod-name.namespace-name.svc.cluster-domain.tld,它将解析为该服务的集群IP地址。
CoreDNS使用插件来支持各种DNS记录类型,例如A、CNAME、SRV等。它可以与k8s的API服务器进行交互,以了解k8s中运行的应用程序和服务状态。
kubectl run busybox4 --image busybox:1.28 --restart=Never --rm -it busybox -- sh
/ # nslookup kubernetes.default.svc.cluster.local
- nslookup kubernetes.default.svc.cluster.local:用于解析k8s中的apiserver这个Pod前面的代理service域名,内部service的名称是通过coreDNS解析的,10.96.0.10就是coreDNS的clusterIP,说明coreDNS已经配置好了。
延长证书
Kubeadm安装的k8s默认证书有效一年,过了一年API Server就会禁止连接,所以需要将证书延长。
查看下证书的有效时间:
openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text | grep Not
Not Before: May 25 08:16:52 2024 GMT
Not After : May 23 08:16:52 2034 GMT
我这里是10年有效期,实现的步骤还是梳理下:
需要将update-kubeadm-cert.sh文件上传到controller节点,然后赋权限,执行即可。
chmod +x update-kubeadm-cert.sh
./update-kubeadm-cert.sh all
执行完毕后,查看下Pod是否正常,若能查询出数据,那么证书签发完成。
kubectl get pods -n kube-system
- 查看证书时长
openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text | grep Not
Not Before: May 25 08:16:52 2024 GMT
Not After : May 23 08:16:52 2034 GMT
- apiserver证书
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep Not
Not Before: May 25 08:16:52 2024 GMT
Not After : May 23 08:16:52 2034 GMT
- etcd证书
openssl x509 -in /etc/kubernetes/pki/apiserver-etcd-client.crt -noout -text | grep Not
Not Before: May 25 08:16:52 2024 GMT
Not After : May 23 08:16:52 2034 GMT
- proxy证书
openssl x509 -in /etc/kubernetes/pki/front-proxy-ca.crt -noout -text | grep Not
Not Before: May 25 08:16:52 2024 GMT
Not After : May 23 08:16:52 2034 GMT