1. 准备部署Kubernetes集群
Kubernetes项目目前仍然处于快速迭代阶段,演示过程中使用的配置对于其后续版本可能存在某些变动,因此,版本不同时,对具体特性支持的变动请读者参考Kubernetes的ChangeLog或其他相关文档中的说明.
1.1 部署目标
图1.1 给出了要部署的目标集群的基本环境,它拥有一个Master主机和三个Node主机。各Node主机的配置方式基本相同。
有本篇博文内容太长,后面章节介绍再来介绍 安装dashboard、部署ingress。
各主机上采用的容器运行时环境为Docker,为Pod提供网络功能的CNI是flannel,它运行为托管于Kubernetes之上的Pod对象,另外,基础附件还包括KubeDNS(或CoreDNS)用于名称解析和服务发现。
1.2 系统环境及部署准备
Kubernetes当前仍处于快速迭代的周期中,其版本变化频繁、跨版本的特性变化较大,文章使用如下基础环境。
1.2.1 各相关组件及主机环境
操作系统、容器引擎、etcd及Kubernetes的相关版本分别如下:
- OS:CentOS Linux release 7.8.2003 (Core)
- Container runtime:Docker 20.10.7
- Kubernetes:1.21.2
各主机角色分配及IP地址如表所示:
IP地址 | 主机名 | 角色 |
---|---|---|
192.168.2.12 | master.k8s.cn | master |
192.168.2.13 | node1.k8s.cn | node |
192.168.2.14 | node2.k8s.cn | node |
192.168.2.15 | node3.k8s.cn | node |
相关组件版本说明:
组件 | 版本 | 说明 |
---|---|---|
kubernetes | v1.21.2 | 主程序 |
docker | 20.10.7 | 主容器 |
flannel | v0.11.0-amd64 | 网络插件 |
flannel | v0.11.0-amd64 | 网络插件 |
etcd | 3.4.13-0 | 数据库 |
coredns | v1.8.0 | dns组件 |
kubernetes-dashboard | web界面 | |
ingress-nginx | ingress提供外部访问kubernetes内部应用的入口 |
1.2.2 基础环境设置
Kubernetes的正确运行依赖于一些基础环境的设定,如各节点时间通过网络时间服务保持同步和主机名称解析等,集群规模较大的实践场景中,主机名称解析通常由DNS服务器完成。
每台机器执行都执行以下步骤:
1.2.2.1 修改IP及MAC
vi /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
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"
UUID="da20e5e2-0aac-4554-bcfe-c7833be75217"
DEVICE="ens33"
ONBOOT="yes"
IPADDR=192.168.2.12
GATEWAY=192.168.2.2
NETMASK=255.255.255.0
DNS1=114.114.114.114
1.2.2.2 配置hostname
vi /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=master.k8s.cn
GATEWAY=192.168.2.2
每台机器执行命令:
hostnamectl set-hostname master.k8s.cn
hostnamectl set-hostname node2.k8s.cn
hostnamectl set-hostname node3.k8s.cn
hostnamectl set-hostname node4.k8s.cn
1.2.2.3 重启网络
service network restrt
1.2.2.4 关闭防火墙
systemctl stop firewalld.service
systemctl disable firewalld.service
firewall-cmd --state #查看状态
systemctl is-enabled firewalld.service #查看服务是否开机启动
1.2.2.5 设置hosts
设置所有机器的IP和hostname映射
#命令
vi /etc/hosts
#内容如下(不要删除hosts文件中原来的内容)
192.168.2.12 master.k8s.cn master
192.168.2.13 node1.k8s.cn node1
192.168.2.14 node2.k8s.cn node2
192.168.2.15 node3.k8s.cn node3
1.2.2.6 禁用SELinux(所有机器)
主要就是把SELINUX改为disabled
#修改安全设置
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
1.2.2.7 主机时间同步
Centos使用chrony做时间同步
参考:https://www.cnblogs.com/lizhaoxian/p/11260041.html
Chrony是一个开源的自由软件,在RHEL 7操作系统,已经是默认服务,默认配置文件在 /etc/chrony.conf
它能保持系统时间与时间服务器(NTP)同步,让时间始终保持同步。相对NTP时间同步软件,速度更快、配置和依赖都更简单
Chrony有两个核心组件,分别是:chronyd:是守护进程,主要用于调整内核中运行的系统时间和时间服务器同步。它确定计算机增减时间的比率,并对此进行调整补偿。chronyc:提供一个用户界面,用于监控性能并进行多样化的配置。它可以在chronyd实例控制的计算机上工作,也可以在一台不同的远程计算机上工作。
配置的时候,需要首先配置chrony的服务器端,然后配置客户端与服务器端进行同步。
如果基于外网的时钟服务器,那可以不用配置服务器器端
1.chrony工具安装
- 1系统版本检查,使用cat /etc/system-release
- 2使用rpm -qa |grep chrony查看系统是否已安装chrony,可看到默认已安装chrony的包。
- 3如果没有安装环境可使用yum install chrony命令安装或者离线下载rpm包安装,下载地址:http://rpm.pbone.net/index.php3?stat=3&limit=2&srodzaj=3&dl=40&search=chrony,找到对应版本下载即可。
- 4下载完后使用rpm -ivh chrony-2.1.1-4.el7.centos.x86_64.rpm安装即可
#查看系统是否已安装chrony
rpm -qa |grep chrony
#chrony命令安装
yum install chrony -y
#服务状态
systemctl start chronyd.service 启动chrony服务
systemctl enable chronyd.service 设置开机同步时间
systemctl status chronyd.service 查看服务状态
2.服务端和客户端chrony配置
####### 2.1 服务端配置
配置文件修改
vi /etc/chrony.conf
重启下服务端chrony服务,使用systemctl restart chronyd.service重启即可
systemctl restart chronyd.service
####### 2.2 客户端配置
配置文件修改
vim /etc/chrony.conf
重启下客户端chrony服务,使用systemctl restart chronyd.service重启即可。
systemctl restart chronyd.service
客户端使用chronyc sources -v命令完成同步即可
chronyc sources -v
用命令
查看时间同步源:
$ chronyc sources -v
立即手工同步
$chronyc -a makestep
查看时间同步源状态:
$ chronyc sourcestats -v
设置硬件时间
硬件时间默认为UTC:
$ timedatectl set-local-rtc 1
启用NTP时间同步:
$ timedatectl set-ntp yes
校准时间服务器:
$ chronyc tracking
最后需要注意的是,配置完/etc/chrony.conf后,需重启chrony服务,否则可能会不生效。
以上步骤所有node节点同步配置。
1.2.2.8 禁用Swap设备
kubeadm默认会预先检查当前主机是否禁用了Swap设备,并在未禁用时强制终止部署过程。因此,在主机内存资源充裕的条件下,需要禁用所有的Swap设备。关闭Swap设备,需要分两步完成。首先是关闭当前已启用的所有Swap设备:
[root@localhost /]# swapoff -a
1.2.2.9 启用ipvs内核模块
Kubernetes 1.11之后的版本默认支持使用ipvs代理模式的Service资源,但它依赖于ipvs相关的内核模块,而这些模块默认不会自动载入。
创建脚本ipvs.modules
#! /bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for i in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do
/sbin/modinfo -F filename $i &>/dev/null
if [ $? -eq 0 ]; then
/sbin/modprobe $i
fi
done
而后,修改文件权限,并手动为当前系统环境加载内核模块
cd /etc/sysconfig/modules
chmod +x /etc/sysconfig/modules/ipvs.modules
到此准备工作全部完成。
2.部署Kubernetes集群
kubeadm是用于快速构建Kubernetes集群的工具,随着Kubernetes的发行版本而提供,使用它构建集群时,大致可分为如下几步。
- 在Master及各Node安装Docker、kubelet及kubeadm,并以系统守护进程的方式启动Docker和kubelet服务。
- 在Master节点上通过kubeadm init命令进行集群初始化。
- 各Node通过kubeadm join命令加入初始化完成的集群中。
- 在集群上部署网络附件,如flannel或Calico等以提供Service网络及Pod网络
为了简化部署过程,kubeadm使用一组固定的目录及文件路径存储相关的配置及数据文件,其中/etc/kubernetes目录是所有文件或目录的统一存储目录。它使用/etc/kubernetes/manifests目录存储各静态Pod资源的配置清单,用到的文件有etcd.yaml、kube-apiserver. yaml、kube-controller-manager.yaml和kube-scheduler.yaml四个,它们的作用基本能够见名知义。另外,/etc/kubernetes/目录中还会为Kubernetes的多个组件存储专用的kubeconfig文件,如kubelet.conf、controller-manager.conf、scheduler.conf和admin.conf等,它们分别为相关的组件提供接入API Server的认证信息等。此外,它还会在/etc/kubernetes/pki目录中存储若干私钥和证书文件。
2.0 设定容器运行环境
Kubernetes支持多种容器运行时环境,例如Docker、RKT和Frakti等,本书将采用其中目前最为流行的、接受程度最为广泛的Docker。
Docker需要安装于Master及各Node主机之上,安装方式相同,其步骤如下:
安装docker :https://blog.csdn.net/u012637358/article/details/106789482
或
wget https://download.docker.com/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
#安装docker
yum install -y docker-ce
2.1 设定Kubernetes集群节点
kubelet是运行于集群中每个节点之上的Kubernetes代理程序,它的核心功能在于通过API Server获取调度至自身运行的Pod资源的PodSpec并依之运行Pod对象。事实上,以自托管方式部署的Kubernetes集群,除了kubelet和Docker之外的所有组件均以Pod对象的形式运行。
2.1.1 安装kubelet及kubeadm
提示:
对于rpm方式的安装来说,kubelet、kubeadm和kubectl等是各自独立的程序包,Master及各Node至少应该安装kubelet和kubeadm,而kubectl则只需要安装于客户端主机即可,不过,由于依赖关系它通常也会被自动安装。另外,Google提供的kubelet rpm包的yum仓库托管于Google站点的服务器主机之上,目前访问起来略有不便。幸运的是,目前国内的阿里云等镜像(http://mirrors.aliyun.com)对此项目也有镜像提供
首先设定用于安装kubelet、kubeadm和kubectl等组件的yum仓库,编辑配置文件/etc/yum.repos.d/kubernetes.repo,内容如下:
cat <<EOF > kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
sudo mv kubernetes.repo /etc/yum.repos.d/
而后执行如下命令即可安装相关的程序包:
yum install -y kubelet kubeadm kubectl
2.1.2 配置kubelet
Kubernetes自1.8版本起强制要求关闭系统上的交换分区(Swap),否则kubelet将无法启动。当然,用户也可以通过将kubelet的启动参数“–fail-swap-on”设置为“false”忽略此限制,尤其是系统上运行有其他重要进程且系统内存资源稍嫌不足时建议保留交换分区。
编辑kubelet的配置文件/etc/sysconfig/kubelet,设置其配置参数如下,以忽略禁止使用Swap的限制:
vi /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--fail-swap-on=false"
待配置文件修改完成后,需要设定kubelet服务开机自动启动,这也是kubeadm的强制要求:
systemctl enable kubelet.service
2.2 集群初始化
一旦Master和各Node的Docker及kubelet设置完成后,接着便可以在Master节点上执行“kubeadm init”命令进行集群初始化。kubeadm init命令支持两种初始化方式,一是通过命令行选项传递关键的参数设定,另一个是基于yaml格式的专用配置文件设定更详细的配置参数。建议读者采用第二种方式。
提示更多的参数请参考kubeadm的文档,链接地址为https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/。
Master初始化方式二:kubeadm init也可通过配置文件加载配置,以定制更丰富的部署选项。以下是使用示例,不过,它明确定义了kubeProxy的模式为ipvs,并支持通过修改imageRepository的值来修改获取系统镜像时使用的镜像仓库。
2.2.1 配置kubeadm-config.yaml
通过如下指令创建默认的kubeadm-config.yaml文件:
kubeadm config print init-defaults > kubeadm-config.yaml
kubeadm-config.yaml组成部署说明:
InitConfiguration: 用于定义一些初始化配置,如初始化使用的token以及apiserver地址等
ClusterConfiguration:用于定义apiserver、etcd、network、scheduler、controller-manager等master组件相关配置项
KubeletConfiguration:用于定义kubelet组件相关的配置项
KubeProxyConfiguration:用于定义kube-proxy组件相关的配置项
可以看到,在默认的kubeadm-config.yaml文件中只有InitConfiguration、ClusterConfiguration 两部分。我们可以通过如下操作生成另外两部分的示例文件:
# 生成KubeletConfiguration示例文件
kubeadm config print init-defaults --component-configs KubeletConfiguration
# 生成KubeProxyConfiguration示例文件
kubeadm config print init-defaults --component-configs KubeProxyConfiguration
将上面的内容保存于配置文件中,如kubeadm-config.yaml,而后执行相应的命令即可完成Master初始化:
最终修改kubeadm-config.yaml文件如下:
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.2.12
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: node
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.21.0
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: cgroupfs
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: ""
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
安装master节点:
#查看kubeadm需要镜像,并修改名称
kubeadm config images list --config kubeadm-config.yaml
registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.0
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.21.0
registry.aliyuncs.com/google_containers/kube-scheduler:v1.21.0
registry.aliyuncs.com/google_containers/kube-proxy:v1.21.0
registry.aliyuncs.com/google_containers/pause:3.4.1
registry.aliyuncs.com/google_containers/etcd:3.4.13-0
registry.aliyuncs.com/google_containers/coredns:v1.8.0
kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap
解决方案:https://blog.51cto.com/8999a/2784605
命令执行的结果如下所示:
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.2.12:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:5bab898d50d0a2ea0acee2fb9b5ad024860ac4e6e527c6e47ff0a2a7e440fb6c
根据上述输出信息的提示,完成集群部署还需要执行三类操作:设定kubectl的配置文件、部署网络附件以及将各Node加入集群。下面就来讲解如何进行这三步操作。
2.3 设定kubectl的配置文
kubectl是执行Kubernetes集群管理的核心工具。默认情况下,kubectl会从当前用户主目录(保存于环境变量HOME中的值)中的隐藏目录.kube下名为config的配置文件中读取配置信息,包括要接入Kubernetes集群、以及用于集群认证的证书或令牌等信息。集群初始化时,kubeadm会自动生成一个用于此类功能的配置文件/etc/kubernetes/admin.conf,将它复制为用户的$HOME/.kube/config文件即可直接使用。这里以Master节点上的root用户为例进行操作,不过,在实践中应该以普通用户的身份进行:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
至此为止,一个Kubernetes Master节点已经基本配置完成。接下来即可通过APIServer来验证其各组件的运行是否正常。kubectl有着众多子命令,其中“getcompontsstatuses”即能显示出集群组件当前的状态,也可使用其简写格式“getcs”:
出现这种情况,是/etc/kubernetes/manifests/下的kube-controller-manager.yaml和kube-scheduler.yaml设置的默认端口是0导致的,解决方式是注释掉对应的port即可,操作如下:
cd /etc/kubernetes/manifests/
vim kube-controller-manager.yaml #注释掉第26行#--port=0
vim kube-scheduler.yaml #注释掉第19行# --port=0
然后在master节点上重启kubelet,systemctl restart kubelet.service,然后重新查看就正常了
systemctl restart kubelet.service
若上面命令结果的STATUS字段为“Healthy”,则表示组件处于健康运行状态,否则需要检查其错误所在,必要时可使用“kubeadm reset”命令重置之后重新进行集群初始化。
kubeadm reset
另外,使用“kubectl get nodes”命令能够获取集群节点的相关状态信息,如下命令结果显示了Master节点的状态为“NotReady”(未就绪),这是因为集群中尚未安装网络插件所致,执行完后面的其他步骤后它即自行转为“Ready”:
kubectl get nodes
解决方案:https://www.cnblogs.com/potato-chip/p/13973760.html
2.4 部署网络插件
为Kubernetes提供Pod网络的插件有很多,目前最为流行的是flannel和Calico。相比较来说,flannel以其简单、易部署、易用等特性广受用户欢迎。基于kubeadm部署时,flannel同样运行为Kubernetes集群的附件,以Pod的形式部署运行于每个集群节点上以接受Kubernetes集群管理。事实上,也可以直接将flannel程序包安装并以守护进程的方式运行于集群节点上,即以非托管的方式运行。部署方式既可以是获取其资源配置清单于本地而后部署于集群中,也可以直接在线进行应用部署。部署命令是“kubectl apply”或“kubectl create”,例如,下面的命令安装flannel网络插件:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
sed -i 's@quay.io/coreos@quay.azk8s.cn/coreos@g' kube-flannel.yml
kubectl apply -f kube-flannel.yml
但是 raw.githubusercontent.com已经被墙了,如果可以科学上网,上面可以直接搞定,如果不能科学上网,这里放上kube-flannel.yml文件的源码
cat <<EOF > kube-flannel.yml
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp.flannel.unprivileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
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']
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/v1beta1
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/v1beta1
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": [
{
"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-amd64
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: beta.kubernetes.io/os
operator: In
values:
- linux
- key: beta.kubernetes.io/arch
operator: In
values:
- amd64
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.11.0-amd64
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.11.0-amd64
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"]
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
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds-arm64
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: beta.kubernetes.io/os
operator: In
values:
- linux
- key: beta.kubernetes.io/arch
operator: In
values:
- arm64
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.11.0-arm64
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.11.0-arm64
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"]
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
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds-arm
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: beta.kubernetes.io/os
operator: In
values:
- linux
- key: beta.kubernetes.io/arch
operator: In
values:
- arm
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.11.0-arm
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.11.0-arm
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"]
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
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds-ppc64le
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: beta.kubernetes.io/os
operator: In
values:
- linux
- key: beta.kubernetes.io/arch
operator: In
values:
- ppc64le
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.11.0-ppc64le
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.11.0-ppc64le
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"]
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
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds-s390x
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: beta.kubernetes.io/os
operator: In
values:
- linux
- key: beta.kubernetes.io/arch
operator: In
values:
- s390x
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.11.0-s390x
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.11.0-s390x
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"]
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
EOF
kubectl可根据定义资源对象的清单文件将其提交给API Server以管理资源对象,如使用“kubectl apply -f /PATH/TO/MANIFEST”命令即可根据清单设置资源的目标状态。kubectl的具体使用会在后面的章节进行详细介绍。
配置flannel网络插件时,Master节点上的Docker首先会去获取flannel的镜像文件,而后根据镜像文件启动相应的Pod对象。待其运行完成后再次查看集群中的节点状态可以看出Master已经变为“Ready”状态
kubectl get nodes
提示“kubectl get pods -n kube-system | grep flannel”命令的结果显示Pod的状态为Running时即表示网络插件flannel部署完成。
2.6 添加Node至集群中
Master各组件运行正常后即可将各Node添加至集群中。
即在每个Node节点主机上执行以下步骤:
- 每个节点生成kubeadm-config.yaml配置文件
- 添加节点kubeadm join --config kubeadm-config.yaml
2.6.1 生成用于添加节点的kubeadm-config.yaml文件
kubeadm config print join-defaults > kubeadm-config.yaml
# kubeadm-config.yaml内容如下:
apiVersion: kubeadm.k8s.io/v1beta2
caCertPath: /etc/kubernetes/pki/ca.crt
discovery:
bootstrapToken:
apiServerEndpoint: 192.168.2.12:6443
token: abcdef.0123456789abcdef
unsafeSkipCAVerification: true
timeout: 5m0s
tlsBootstrapToken: abcdef.0123456789abcdef
kind: JoinConfiguration
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: node1.k8s.cn
taints: null
这里需要修改三个地方:
apiServerEndpoint:连接apiserver的地址,即master的api地址,这里可以改为192.168.2.12:6443,如果master集群部署的话,这里需要改为集群vip地址
token及tlsBootstrapToken:连接master使用的token,这里需要与master上的InitConfiguration中的token配置一致
name:node节点的名称,如果使用主机名,需要确保master节点可以解析该主机名。否则的话可直接使用ip地址。
2.6.2 添加节点
在每个Node主机上使用“kubeadm join”命令将其加入集群中
kubeadm join --config kubeadm-config.yaml
#输出内容
[preflight] Running pre-flight checks
[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
在master节点获取nodes状态
kubectl get nodes
到此为止,使用kubeadm构建Kubernetes集群已经完成。后续若有Node需要加入,其方式均可使用此节介绍的方式来进行。
2.7 获取集群状态信息
Kubernetes集群以及部署的插件提供了多种不同的服务,如此前部署过的APIServer、kube-dns等。API客户端访问集群时需要事先知道API Server的通告地址,管理员可使用“kubectl cluster-info”命令了解到这些信息:
[root@localhost opt]# kubectl cluster-info
Kubernetes control plane is running at https://192.168.2.12:6443
CoreDNS is running at https://192.168.2.12:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
2.8 从集群中移除节点
运行过程中,若有节点需要从正常运行的集群中移除,则可使用如下步骤来进行
1)在Master上使用如下命令“排干”(迁移至集群中的其他节点)当前节点之上的Pod资源并移除Node节点
kudectl drain NODE_ID --delete-local-data --force --ignore-daemonsets
kudect delete node NODE_ID
2)而后在要删除的Node上执行如下命令重置系统状态便可完成移除操作
kubeadm reset
3. 重新生成用于节点加入集群的认证命令
如果忘记了记录Master主机的kubeadm init命令执行结果中用于让节点加入集群的kubeadm join命令及其认证信息,则需要分别通过kubectl获取认证令牌及验证CA公钥的哈希值。
“kubeadm token list”能够获取到集群上存在认证令牌,定位到其中DESCRIPTION字段中标识为由“kubeadm init”命令生成的行,其第一字段TOKEN中的令牌即为认证令牌。而验证CA公钥的哈希值(discovery-token-ca-cert-hash)的获取命令则略微复杂,其完成格式如下所示
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256-hex |sed 's/^.*//'
而后,将上述两个命令生成的结果合成为如下格式的kubeadm join命令即可用于让Node加入集群中,其中的TOKEN可替换为上面第一个命令的生成结果,HASH可替换为第二个命令的生成结果:
kubadm join 192.168.2.12:6443 --token TOKEN --discover-token-ca-cert-hash HASH
恭喜!整个k8s集群依据设想架构搭建完成!
参考鸣谢:
kubeadm安装kubernetes 1.16.2
https://www.cnblogs.com/breezey/p/11770780.html
Kubernetes 安装flannel组件
https://blog.csdn.net/qq_22409661/article/details/113371921
自学k8s-kubeadm部署过程中遇到的dial tcp 127.0.0.1:10251: connect: connection refused错误
https://www.cnblogs.com/potato-chip/p/13973760.html
解决kubernetes v1.21.1 从 k8s.gcr.io 拉取镜像失败的问题
https://blog.51cto.com/8999a/2784605