k8s–多master高可用集群环境搭建

k8s学习

  1. 介绍

Kubernetes 是一个可移植的、可扩展的 开源平台 ,用于 管理容器化的工作负载和服务,可促进声明式配置和自动化 。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。

 **优势**:
  - 自动装箱,水平扩展,自我修复
  - 服务发现和负载均衡
  - 自动发布和回滚
  - 集中化配置管理和密钥管理
  - 存储编排
  - 批处理:提供一次性任务,定时任务;满足批量数据处理和分析的场景

  **特点:**
  -  可移植 : 支持公有云,私有云,混合云,多重云(multi-cloud)
 - 可扩展 : 可根据业务流量情况快速扩展kubernetes集群的节点数量。
 - 自愈 : 自动发布,自动重启,自动复制,自动扩展
 - 进程协同 :利用复合应用保证应用和容器一对一的模型。
  1. 核心概念

●Pod/Pod控制器

Pod是K8S里能够被运行的最小的逻辑单元(原子单元)
1个Pod里面可以运行多个容器,它们共享UTS+NET+IPC名称空间
可以把Pod理解成豌豆荚,而同一Pod内的每个容器是一颗颗豌豆
一个Pod里运行多个容器,又叫:边车(SideCar)模式

Pod控制器是Pod启动的一种模式,用来保证在K8S里启动的Pod应始终按照人们的预期运行(副本数,生命周期,健康状态检查…)
K8S内提供了众多的Pod控制器,常用的有以下几种:
Deployment、DaemonSet、ReplicaSet、StatefulSet、Job、Cronjob

●Name/Namespace

Name
由于K8S内部,使用“资源”来定义每一 种逻辑概念(功能)故每种”资源”,都应该有自己的 ”名称”。
资源”有api版本( apiVersion )类别( kind )、元数据( metadata )、定义清单( spec)、状态( status )等配置信息。
"名称”通常定义在“资源”的"元数据”信息里。

Namespace
随着项目增多、人员增加、集群规模的扩大,需要一种能够隔离K8S内各种“资源”的方法,这就是名称空间名称空间可以理解为K8S内部的虚拟集群组。
不同名称空间内的“资源” ,名称可以相同,相同名称空间内的同种"资源”、"名称” 不能相同。
合理的使用K8S的名称空间,使得集群管理员能够更好的对交付到K8S里的服务进行分类管理和浏览
K8S里默认存在的名称空间有: default、 kube-system、 kube-public
查询K8S里特定“资源”要带上相应的名称空间

●Label/Label选择器

Label
标签是k8s特色的管理方式 ,便于分类管理资源对象。
一个标签可以对应多个资源,一个资源也可以有多个标签,它们是多对多的关系。
一个资源拥有多个标签,可以实现不同维度的管理。
标签的组成: key=value与标签类似的,还有一种"注解”( annotations )

Label选择器
给资源打上标签后,可以使用标签选择器过滤指定的标签
标签选择器目前有两个:基于等值关系(等于、不等于)和基于集合关系(属于、不属于、存在)
许多资源支持内嵌标签选择器字段
matchLabels
matchExpressions

●Service/Ingress

Service
在K8S的世界里,虽然每个Pod都会被分配一个单独的IP地址 ,但这个IP地址会随着Pod的销毁而消失
Service (服务)就是用来解决这个问题的核心概念
一个Service可以看作一 组提供相同服务的Pod的对外访问接口
Service作用于哪些Pod是通过标签选择器来定义的
Service实现类型:
ClusterIP:提供一个集群内部的虚拟IP地址以供Pod访问(默认模式)
NodePort:在Node上打开一个端口以供外部访问
LoadBalancer:通过外部的负载均衡器来访问
ClusterIP是默认模式,LoadBalancer需要额外的模组来提供负载均衡

Ingress
Ingress是K8S集群里 工作在OSI网络参考模型下,第7层的应用 ,对外暴露的接口
Service只能进行L 4流量调度,表现形式是ip+port
Ingress则可以调度不同业务域、不同URL访问路径的业务流量

注(访问顺序):Ingress --> service–>pod–>docker

  1. 核心组件

Master 主控节点

ETCD(配置存储中心)

etcd服务是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划。

kube-apiserver(k8s集群的大脑)

kube-apiserver用于暴露Kubernetes API。任何的资源请求/调用操作都是通过kube-apiserver提供的接口进行。
提供了集群管理的RESTAPI接口(包括鉴权、数据校验及集群状态变更)
负责其他模块之间的数据交互,承担通信枢纽功能
是资源配额控制的入口
提供完备的集群安全机制

kube-controller-manager(控制器管理器)

运行管理控制器,是集群中处理常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成单个二进制文件,并在单个进程中运行。
由一系列控制器组成,通过apiserver监控整个集群的状态,并确保集群处于预期的工作状态
● Node Controller
● Deployment Controller
● Service Controller
● Volume Controller
● Endpoint Controller
● Garbage Controller
● Namespace Controller
● Job Controller
● Resource quta Controller

Scheduler(调度程序,监控node资源的状况)

主要功能是接收调度pod到适合的运算节点上
● 预算策略( predict )
● 优选策略( priorities )

node节点

Kubelet(容器的守护进程)

容器的搭起,销毁等动作,负责pod的生命周期,运行node上
简单地说, kubelet的主要功能就是定时从某个地方获取节点上pod的期望状态(运行什么容器、运行的副本数量网络或者存储如何配置等等) ,并调用对应的容器平台接口达到这个状态
定时汇报当前节点的状态给apiserver,以供调度的时候使用
镜像和容器的清理工作保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源

kube-proxy(网络代理和负载均衡器)

运行在node上,最先用iptables做隔离,现在流行用ipvs,更方便
kube-proxy是K8S在每个节点上运行网络代理, service资源的载体
●建立了pod网络和集群网络的关系( clusterip- >podip )
●常用三种流量调度模式
●Userspace (废弃)
●Iptables (废弃)
●Ipvs(推荐)
●负责建立和删除包括更新调度规则、通知apiserver自己的更新,或者从apiserver哪里获取其他kube-proxy的调度规则变化来更新自己的Endpoint Controller 负责维护Service和Pod的对应关系
Kube-proxy负责service的实现,即实现了K8s内部从pod到Service和外部从node port到service的访问

注:Pod网络是kube-kubelet提供,不是直接由Kube-proxy提供

各组件的工作流程:

User(采用命令kubectl)—> API server(响应,调度不同的Schedule)—> Schedule(调度)—> Controller Manager(创建不同的资源)—> etcd(写入状态)—> 查找集群(node哪个有资源,通过Schedule,到对应的node上创建pod)

其他概念

RC(ReplicationController)

Kubelet需要管理大量的pod,而显而易见的是通常情况下一个应用不会以单独一个pod完成,比较常见的是使用大量的Pod组成一个简单应用,管理这些大量的pod的一个方案RC
RC可以指定pod的副本数量,并且在其中有Pod故障时可以自动拉起新的pod,大大简化了维护难度
目前建议采用ReplicaSet和Deployment代替RC

ReplicaSet副本控制器

确保pod的一定数量的分数(replica)在运行,如果超过这个数量,制器会杀死一些,如果少了,控制器会启动一些。
用来解决pod的扩容和缩容问题。
新一代的RS,主要功能和RC一样,维持pod的数量稳定,指定pod的运行位置,使用方法也相似,主要区别是更新了api,支持更多功能
RS不建议直接使用,而是用更上层的概念Deployment调用ReplicaSet
通常用于无状态应用,与Deployments配置使用

Deployments(无状态)

用于更新Pod和ReplicaSet的方法,Deployments用来定义您预期的应用状态。
Deployments集成了上线部署,滚动升级,创建副本,暂停上线任务,恢复上线任务,回滚到以前某一版本(成功/稳定)的Deployments等功能
目前最常用的控制器就是Deployment,创建Deployment时也会创ReplicaSet
Deployment可以管理一个或多个RS,并且通过RS来管理pod
一个完整的应用一般都是多个Deployment构成

StatefulSets(有状态)

有状态应用,用于解决各个pod实例独立生命周期管理,提供各个实例的启动顺序和唯一性。特点:
稳定,有唯一的网络标识符,可持久存储
有序,可优雅的部署、扩展、删除和终止、自动滚动更新。

DaemonSet(守护)

能够让所有的node节点运行同一个Pod。(一般用来部署代理,如果收集日志的代理,可以通过DaemonSet快速的在node上部署同一个pod)
副本数的控制是通过RS去控制的

Service

相当于锁定器,不会因为pod被销毁而找不到后端资源,pod销毁Ip等信息会改变, 定义了pods的逻辑集合和访问这个集合的策略,pods集合是通过定义service时提供的label选择器完成的

Node管理机制

Container Runtime(容器) 归Kubelet进程管理
Kubelet发现机制,如果发现容器挂了,Kubelet会通过API server 监控容器状态,如果本身状态为1,变成了0,它就会去把容器再拉起来

addons(插件 )

addon是实现集群pod和Services功能的 。Pod由Deployments,ReplicationController等进行管理。Namespace 插件对象是在kube-system Namespace中创建。

DNS

虽然不严格要求使用插件,但Kubernetes集群都应该具有集群 DNS。群集 DNS是一个DNS服务器,能够为 Kubernetes services提供 DNS记录。由Kubernetes启动的容器自动将这个DNS服务器包含在他们的DNS searches中。

网络

存储

nfc : nfc存储系统

原生方式挂载静态值,创建pv池,pvc申请相近的存储空间。

​ pv: 持久卷

​ pvc: 持久卷声明

动态pv池

常用命令

基本命令

格式:Kubectl command -type name(名称) flags
常用 Command:
--基础命令--
create:(创建资源)通过文件名或标准输入创建资源。
apply:(应用资源的配置变更,也可以代替create创建新的资源)
get:(查看资源)显示一个或多个资源。
expose :将一个资源公开为一个新的Kubernetes服务。
run:创建并运行一个特定的镜像,可能是副本。
set: 配置应用资源。修改现有应用程序资源。
edit :使用默认的编辑器编辑一个资源。
explain: 文档参考资料
describe:(查看资源的详细描述)
delete:(删除资源)通过文件名、标准输入、资源名称或标签选择器来删除资源。
--部署命令--
rollout :管理资源的发布。
rolling-update: 执行指定复制控制的滚动更新。
scale :扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job。
autoscale :创建一个自动选择扩容或缩容并设置Pod数量。
--集群管理命令--
certificate: 修改证书资源。
cluster-info: 显示集群信息。
top :显示资源(CPU/Memory/Storage)使用。需要Heapster运行。
cordon: 标记节点不可调度。
uncordon :标记节点可调度。
drain: 维护期间排除节点。
...

常用的-type有:
node/nodes:   ##查询集群节点
pod/pods:
svc:(service简写)
deploy:(Deployments)
rc:(ReplicationController简写)
rs:(ReplicaSet)
ns:(namespace)  ##查看命名空间
cs:    ##查询组件健康状态
...
常用的flags包含-n=namespace,-o=wide(能看到宿主机)
默认namespace(default,kube-system)
Examples:
  # List all pods in ps output format.
  kubectl get pods
  
  # List all pods in ps output format with more information (such as node name).
  kubectl get pods -o wide
  
  # List a single replication controller with specified NAME in ps output format.
  kubectl get replicationcontroller web
  
  # List deployments in JSON output format, in the "v1" version of the "apps" API group:
  kubectl get deployments.v1.apps -o json
  
  # List a single pod in JSON output format.
  kubectl get -o json pod web-pod-13je7
  
  # List a pod identified by type and name specified in "pod.yaml" in JSON output format.
  kubectl get -f pod.yaml -o json
  
  # List resources from a directory with kustomization.yaml - e.g. dir/kustomization.yaml.
  kubectl get -k dir/
  
  # Return only the phase value of the specified pod.
  kubectl get -o template pod/web-pod-13je7 --template={{.status.phase}}
  
  # List resource information in custom columns.
  kubectl get pod test-pod -o custom-columns=CONTAINER:.spec.containers[0].name,IMAGE:.spec.containers[0].image
  
  # List all replication controllers and services together in ps output format.
  kubectl get rc,services
  
  # List one or more resources by their type and names.
  kubectl get rc/web service/frontend pods/web-pod-13je7

Options:
  -A, --all-namespaces=false: If present, list the requested object(s) across all namespaces. Namespace in current
context is ignored even if specified with --namespace.
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
      --chunk-size=500: Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and
may change in the future.
      --field-selector='': Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector
key1=value1,key2=value2). The server only supports a limited number of field queries per type.
  -f, --filename=[]: Filename, directory, or URL to files identifying the resource to get from a server.
      --ignore-not-found=false: If the requested object does not exist the command will return exit code 0.
  -k, --kustomize='': Process the kustomization directory. This flag can't be used together with -f or -R.
  -L, --label-columns=[]: Accepts a comma separated list of labels that are going to be presented as columns. Names are
case-sensitive. You can also use multiple flag options like -L label1 -L label2...
      --no-headers=false: When using the default or custom-column output format, don't print headers (default print
headers).
  -o, --output='': Output format. One of:
json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...
See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template
[http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template
[http://kubernetes.io/docs/user-guide/jsonpath].
      --output-watch-events=false: Output watch event objects when --watch or --watch-only is used. Existing objects are
output as initial ADDED events.
      --raw='': Raw URI to request from the server.  Uses the transport specified by the kubeconfig file.
  -R, --recursive=false: Process the directory used in -f, --filename recursively. Useful when you want to manage
related manifests organized within the same directory.
  -l, --selector='': Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
      --server-print=true: If true, have the server return the appropriate table output. Supports extension APIs and
CRDs.
      --show-kind=false: If present, list the resource type for the requested object(s).
      --show-labels=false: When printing, show all labels as the last column (default hide labels column)
      --sort-by='': If non-empty, sort list types using this field specification.  The field specification is expressed
as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression
must be an integer or a string.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
  -w, --watch=false: After listing/getting the requested object, watch for changes. Uninitialized objects are excluded
if no object name is provided.
      --watch-only=false: Watch for changes to the requested object(s), without listing/getting first.

查看kubelet日志:journalctl -xeu kubelet
docker daemon 文件:vim /etc/docker/daemon.json
kubelet 配置文件:/etc/systemd/system/kubelet.service.d/10-kubeadm.conf

搭建高可用集群

  1. 基础环境

环境搭建基础操作所有节点都要执行

   # 关闭防火墙
   systemctl stop firewalld
   systemctl disable firewalld
   
   # 关闭selinux
   sed -i 's/enforcing/disabled/' /etc/selinux/config
   # 永久
   setenforce 0  # 临时
   
   # 临时
   swapoff -a
   # 永久
   vi /etc/fstab
   //注释或删除swap的行 
   #/dev/mapper/cs-swap     none                    swap    defaults        0 0
   # 查看是否关闭
   free -h
   
   Swap 是交换分区,如果机器内存不够,会使用 swap 分区,但是 swap 分区的性能较低,k8s 设计的
   时候为了能提升性能,默认是不允许使用姜欢分区的。Kubeadm 初始化的时候会检测 swap 是否关闭,如果没关闭,那就初始化失败。如果不想要关闭交换分区,安装 k8s 的时候可以指定--ignorepreflight-errors=Swap 来解决。
   
   # 根据规划设置主机名
   hostnamectl set-hostname <hostname>
   # 在主机添加hosts
   cat >> /etc/hosts << EOF
   192.168.121.84    master01.k8s.io k8smaster01
   192.168.121.85    master02.k8s.io k8smaster02
   192.168.121.87    master03.k8s.io k8smaster03
   192.168.121.81   node01.k8s.io   k8snode01
   192.168.121.82   node02.k8s.io   k8snode02
   192.168.121.200   master.k8s.io   k8s-vip
   EOF
   
   # 时间同步
   yum install ntpdate -y
   ntpdate time.windows.com
   
   # 修改机器内核参数
   modprobe br_netfilter
   echo "modprobe br_netfilter" >> /etc/profile
   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
   
   #查看内核版本
   grubby --default-kernel 或 uname -a
   安装epel源
   rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
   yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
   # 查看内核版本并安装最新版本--可忽略
   yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
   # 安装最新lt内核版本
   yum --disablerepo='*' --enablerepo=elrepo-kernel install kernel-lt -y
   # 查看系统grub内核的启动列表,这里编号0的5.4.103的lt版本是我们新安装的
   awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
    [root@k8smaster02 ~]# awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
	0 : CentOS Linux (5.4.225-1.el7.elrepo.x86_64) 7 (Core)
	1 : CentOS Linux (3.10.0-693.el7.x86_64) 7 (Core)
	2 : CentOS Linux (0-rescue-026be61877af48e4824bbc6441eb83fc) 7 (Core)
	[root@k8smaster02 ~]# 
  # 指定以新安装的编号0的内核版本为默认启动内核
  grub2-set-default 0
  # 卸载旧内核版本
  yum remove kernel -y
  # 重启机器,以新内核版本加载启动  
  reboot

   # 配置阿里云yum仓库
   rm -f /etc/yum.repos.d/*.repo
   curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
   curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
   sed -i "/mirrors.aliyuncs.com/d" /etc/yum.repos.d/CentOS-Base.repo
   sed -i "/mirrors.cloud.aliyuncs.com/d" /etc/yum.repos.d/CentOS-Base.repo
   yum clean all
   
   # 配置docker组件需要的阿里云的 repo 源
   cat >/etc/yum.repos.d/docker-ce.repo<<\EOF
   [docker-ce-stable]
   name=Docker CE Stable - $basearch
   baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable
   enabled=1
   gpgcheck=0
   gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
   EOF
   yum repolist
   
   # 配置安装 k8s 组件需要的阿里云的 repo 源
   cat <<EOF >/etc/yum.repos.d/kubernetes.repo
   [kubernetes]
   name=Kubernetes
   baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
   enabled=1
   gpgcheck=0
   repo_gpgcheck=0
   gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
   EOF
   yum repolist
   
   # 开启 ipvs功能
   cat >/etc/sysconfig/modules/ipvs.modules<<\EOF
   #!/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
   EOF
   chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs
   
   # 安装基本工具包
   yum -y install ipvsadm conntrack ntpdate telnet vim
   
   # 安装docker
   yum install docker-ce-20.10.6 docker-ce-cli-20.10.6 containerd.io -y
   #启动 docker-ce
   systemctl start docker && systemctl enable docker; systemctl status docker
   #设置Docker镜像源和Cgroup驱动
   cat >/etc/docker/daemon.json<<\EOF
   {
    "registry-mirrors":["https://rsbud4vc.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com","http://qtid6917.mirror.aliyuncs.com", "https://rncxm540.mirror.aliyuncs.com"],
     "exec-opts": ["native.cgroupdriver=systemd"]
   } 
   EOF
   systemctl daemon-reload
   systemctl restart docker
   systemctl status docker
   
   # 安装master
   yum install -y kubelet-1.20.6 kubeadm-1.20.6 kubectl-1.20.6
   # Kubeadm: kubeadm 是一个工具,用来初始化 k8s 集群的
   # kubelet: 安装在集群所有节点上,用于启动 Pod 的
   # kubectl: 通过 kubectl 可以部署和管理应用,查看各种资源,创建、删除和更新各种组件
   
   # 启动 kubelet,并设置自启动
   systemctl enable kubelet
   systemctl start kubelet
  1. 初始化集群

   cat > /root/kubeadm-config.yaml << EOF
   apiVersion: kubeadm.k8s.io/v1beta2
   kind: ClusterConfiguration
   kubernetesVersion: v1.20.6
   controlPlaneEndpoint: 192.168.121.84:6443
   imageRepository: registry.aliyuncs.com/google_containers
   apiServer:
     certSANs:
     - 192.168.121.100 # vip地址
   networking:
     podSubnet: 10.244.0.0/16  # pod 容器网段
     serviceSubnet: 10.10.0.0/16  # service 网段范围  这三个地址的网段不可重复、重叠
   ---
   apiVersion: kubeproxy.config.k8s.io/v1alpha1
   kind: KubeProxyConfiguration
   mode: ipvs
   EOF

执行初始化

kubeadm init --config kubeadm-config.yaml  --upload-certs

查看配置文件:kubectl -n kube-system get cm kubeadm-config -o yaml

# 如果初始化过程出现问题,使用如下命令重置
$ kubeadm reset
$ rm -rf /var/lib/cni/
$ rm -f $HOME/.kube/config
$ systemctl daemon-reload && systemctl restart kubelet

初始化成功输出面板

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/

  You can now join any number of control-plane nodes by copying certificate authorities
  and service account keys on each node and then running the following as root:

    kubeadm join 192.168.121.84:6443 --token 4d9pdj.qkd0i3yhqfz0nawg \
      --discovery-token-ca-cert-hash sha256:162fd7e8aa721f85528a9bf601af45e7b7cce39338756a0a7cbfefe9c7471a6f \
      --control-plane 

  Then you can join any number of worker nodes by running the following on each as root:

  kubeadm join 192.168.121.84:6443 --token 4d9pdj.qkd0i3yhqfz0nawg \
      --discovery-token-ca-cert-hash sha256:162fd7e8aa721f85528a9bf601af45e7b7cce39338756a0a7cbfefe9c7471a6f 

根据如上提升信息,普通用户则配置 kubectl 的配置文件 config,相当于对 kubectl 进行授权,这样 kubectl 命令可以使用这个证书对 k8s 集群进行管理

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

而root用户则执行:

export KUBECONFIG=/etc/kubernetes/admin.conf
  1. 查看集群信息

   kubectl get nodes

如果集群状态还是 NotReady 状态,因为没有安装网络插件。

  NAME          STATUS     ROLES                  AGE   VERSION
  k8smaster01   NotReady   control-plane,master   13m   v1.20.6

执行以下命令,然后检查集群状态为 Ready 则表示部署成功

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

如果执行后提示拒绝访问

The connection to the server raw.githubusercontent.com was refused - did you specify the right host or port?

则根据域名查询IP,在/etc/hosts里填写如下内容,ip最好用网站上查询到的最新的

vim /etc/hosts
185.199.111.133 raw.githubusercontent.com

再次执行网络插件安装语句

 namespace/kube-flannel created
 clusterrole.rbac.authorization.k8s.io/flannel created
 clusterrolebinding.rbac.authorization.k8s.io/flannel created
 serviceaccount/flannel created
 configmap/kube-flannel-cfg created
 daemonset.apps/kube-flannel-ds created
 #出现如上信息则表示安装成功,hosts文件的IP域名映射就可以删除了。
  1. 将证书分配至其它 master 节点

设置部署节点到其它所有节点的SSH免密码登录

 在 k8smaster01 节点执行
 [root@k8smaster01 ~]# ssh-keygen -t rsa
 Generating public/private rsa key pair.
 Enter file in which to save the key (/root/.ssh/id_rsa): 
 /root/.ssh/id_rsa already exists.
 Overwrite (y/n)? y
 Enter passphrase (empty for no passphrase): 
 Enter same passphrase again: 
 Your identification has been saved in /root/.ssh/id_rsa.
 Your public key has been saved in /root/.ssh/id_rsa.pub.
 The key fingerprint is:
 SHA256:QL3aapM8r8kv0pKabhogqUh/Rx9VwiZlwYbnNcLTUTU root@k8s-master01
 The key's randomart image is:
 +---[RSA 2048]----+
 |      ..  *=oooEo|
 |     .  .o.Xo+  .|
 |      .  .*.+ .  |
 | .     .. ..     |
 |+.     +S.       |
 |* .   o o .      |
 |+  . = + .       |
 | ...=.@.         |
 |.++. ++Bo        |
 +----[SHA256]-----+
 [root@k8smaster01 ~]# 

把生成的密钥拷贝到其他节点服务器,多节点执行如下脚本命令:

  for i in k8smaster02 k8smaster03 k8snode01 k8snode02;
  do ssh-copy-id -i .ssh/id_rsa.pub $i;
  done
  # 单节点拷贝
  scp -p ~/.ssh/id_rsa.pub root@k8smaster02:/root/.ssh/authorized_keys
     
  [root@k8smaster01 ~]# 
  
  # 检验测试 k8smaster01 节点是否可以免密登录所有集群
  ssh k8smaster02

把k8smaster01 节点的证书拷贝到 k8smaster02 、03上

  ssh k8smaster02 "cd /root && mkdir -p /etc/kubernetes/pki/etcd &&mkdir -p ~/.kube/"
  scp /etc/kubernetes/pki/ca.crt k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/ca.key k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/sa.key k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/sa.pub k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/front-proxy-ca.crt k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/front-proxy-ca.key k8smaster02:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/etcd/ca.crt k8smaster02:/etc/kubernetes/pki/etcd/
  scp /etc/kubernetes/pki/etcd/ca.key k8smaster02:/etc/kubernetes/pki/etcd/
  
  ssh k8smaster03 "cd /root && mkdir -p /etc/kubernetes/pki/etcd &&mkdir -p ~/.kube/"
  scp /etc/kubernetes/pki/ca.crt k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/ca.key k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/sa.key k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/sa.pub k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/front-proxy-ca.crt k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/front-proxy-ca.key k8smaster03:/etc/kubernetes/pki/
  scp /etc/kubernetes/pki/etcd/ca.crt k8smaster03:/etc/kubernetes/pki/etcd/
  scp /etc/kubernetes/pki/etcd/ca.key k8smaster03:/etc/kubernetes/pki/etcd/
  1. master节点扩容集群

在 master02及master03 节点上开始扩容 master

   kubeadm join 192.168.121.84:6443 --token cq0xnv.jqob82ecn7xio21q     --discovery-token-ca-cert-hash sha256:162fd7e8aa721f85528a9bf601af45e7b7cce39338756a0a7cbfefe9c7471a6f --control-plane

默认的 token 有效期为 24 小时,当过期之后,该 token 就不能用了,如果token过期则可以在master01上查看加入节点的命令

[root@k8s-master01 srv]# kubeadm token create --print-join-command

kubeadm join 192.168.2.124:6443 --token 0nlw6z.oxjj0igkmyowqxcu     --discovery-token-ca-cert-hash sha256:c28890784e52f5720669d2d750c81b9c3ba603d8fce07d76b8213a0599a98a31 
# 创建一个永不过期的 token
kubeadm token create --ttl 0

出现如下信息则表示扩容成功

  To start administering your cluster from this node, 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
  
  Run 'kubectl get nodes' to see this node join the cluster.
  

分别在k8smaster02及k8smaster03上执行上面提示授权命令

 mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 sudo chown $(id -u):$(id -g) $HOME/.kube/config
  1. 添加node工作节点

k8snode01及k8smaster02节点执行如下命令:

   kubeadm join 192.168.121.84:6443 --token cq0xnv.jqob82ecn7xio21q     --discovery-token-ca-cert-hash sha256:162fd7e8aa721f85528a9bf601af45e7b7cce39338756a0a7cbfefe9c7471a6f
   # 注意 node节点加入无 --control-plane 命令  

在master01上查看集群节点状态

 [root@k8smaster01 ~]# kubectl get nodes
 NAME          STATUS     ROLES                  AGE     VERSION
 k8smaster01   Ready      control-plane,master   3h18m   v1.20.6
 k8smaster02   Ready      control-plane,master   26m     v1.20.6
 k8smaster03   Ready      control-plane,master   12m     v1.20.6
 k8snode01     NotReady   <none>                 2m19s   v1.20.6
 k8snode02     NotReady   <none>                 2m10s   v1.20.6
 [root@k8smaster01 ~]# 

刚执行完节点加入命令后查看状态如上所示,node节点还是NotReady,等待节点状态变成Ready即可。

卸载重装流程

1、停止服务  kubeadm reset 
2、删除残余文件
rm -rf /etc/kubernetes
rm -rf /var/lib/etcd/
rm -rf $HOME/.kube
备注:无需其他操作,只需要执行这三条命令就可以了。若多删除其他文件,
可能出现重装后kubectl命令无法使用的情况(提示信息为存在残留文件未删除)
# rm /etc/cni/net.d/* -f
# systemctl daemon-reload
# systemctl restart kubelet
# iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
3重新初始化即可
  1. 通过keepalive+nginx实现k8s apiserver结点高可用

    由于服务器资源有限,这里我们在master节点搭建 Nginx + Keepalive的高可用集群

    地址主机名称
    192.168.121.84k8smaster01
    192.168.121.85k8smaster02
    192.168.121.87k8smaster03
    1. 搭建 Nginx 负载均衡

      建立本地yum官方Nginx源

     cat > /etc/yum.repos.d/nginx.repo << 'EOF'
     [nginx]
     name=nginx repo
     baseurl=http://nginx.org/packages/centos/7/$basearch/
     gpgcheck=0
     EOF
     # 安装nginx
     yum install nginx -y
    

    接下来在配置文件设置 Nginx 的四层负载均衡

    vi /etc/nginx/nginx.conf
    

    指定 k8s 群集 3 台 master 的节点 ip 和 16443 端口,由于 nginx 与 master 节点复用,监听端口不能是 6443,否则会冲突。

    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;
        # master 调度资源池
        upstream k8s-apiserver {
            server 192.168.121.84:6443; # Master1 APISERVER IP:PORT 
            server 192.168.121.85:6443; # Master2 APISERVER IP:PORT 
            server 192.168.121.87:6443; # Master3 APISERVER IP:PORT 
        }
        server {
            listen 16443; # 由于 nginx 与 master 节点复用,这个监听端口不能是 6443,否则会冲突 
            proxy_pass k8s-apiserver; # 做反向代理到资源池
        }
    }
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        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;
    
        #gzip  on;
        server { 
            listen 80 default_server; 
            server_name _; 
    
            location / { 
            } 
        } 
    
        include /etc/nginx/conf.d/*.conf;
    }
    
    

    检查配置文件语法,启动nginx服务,查看已监听16443端口

    [root@k8smaster01 ~]# nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    [root@k8smaster01 ~]# systemctl start nginx 
    [root@k8smaster01 ~]# netstat -natp | grep nginx  
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1581/nginx: master  
    tcp        0      0 0.0.0.0:16443           0.0.0.0:*               LISTEN      1581/nginx: master  
    
    1. 搭建 keepalived 高可用服务

    yum 安装 keepalived 软件

    yum install keepalived -y

    修改各自服务的keepalived配置文件

    vi /etc/keepalived/keepalived.conf

    k8smaster01作为keepalived的主配置,02、03为备份配置。删除配置文件全部内容,添加以下内容:

    ! Configuration File for keepalived
    
    global_defs {
       # 接收邮件地址
       notification_email {
         acassen@firewall.loc
         failover@firewall.loc
         sysadmin@firewall.loc
       }
       # 邮件发送地址
       notification_email_from Alexandre.Cassen@firewall.loc
       smtp_server 127.0.0.1
       smtp_connect_timeout 30
       router_id NGINX_MASTER	
    }
    
    #添加一个周期性执行的脚本
    vrrp_script check_nginx {
        script "/etc/nginx/check_nginx.sh"	#指定检查nginx存活的脚本路径
    }
    
    vrrp_instance VI_1 {
        state MASTER			#k8smaster01节点的为 MASTER,k8smaster02、03节点的为 BACKUP
        interface ens192			#指定网卡名称 ens192 ,修改为实际网卡名
        virtual_router_id 51	#指定vrid,两个节点要一致,VRRP路由ID实例,每个实例是唯一的 
        priority 100			#优先级,备服务器设置90 指定k8smaster01节点的为100,k8smaster02为90
        advert_int 1
        authentication {
            auth_type PASS
            auth_pass 1111
        }
        # 虚拟 IP  可以配置多个
        virtual_ipaddress {
            192.168.121.100	#指定 VIP
        }
        track_script {
            check_nginx			#指定vrrp_script配置的脚本
        }
        #vrrp_script:指定检查 nginx 工作状态脚本(根据 nginx 状态判断是否故障转移) 
        #virtual_ipaddress:虚拟 IP(VIP)
    }
    # 在keepalived配置文件中写入监听nginx脚本,这里是加载声明脚本
    vrrp_script check_nginx {
      script "/etc/nginx/check_nginx.sh"  # 脚本位置
      interval 2 # 每隔两秒运行上一行脚本
      weight -20 # 如果脚本运行失败,则权重-20
    }
    

    keepalived 配置文件属性说明:

      vrrp_instance VI_1 {
      	# 状态只有MASTER和BACKUP两种,并且要大写,MASTER为工作状态,BACKUP是备用状态。
          state BACKUP
      	# 工作模式,nopreempt表示工作在非抢占模式,默认是抢占模式 preempt
          nopreempt
      	# 对外提供服务的网卡接口,即VIP绑定的网卡接口。如:eth0,eth1。当前主流的服务器都有2个或2个以上的接口(分别对应外网和内网),在选择网卡接口时,一定要核实清楚。
          interface ens32
      	# 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个,
      	# 而且这个虚拟ID还是虚拟MAC最后一段地址的信息,取值范围0-255
      	# 同一个vrrp_instance的MASTER和BACKUP的vitrual_router_id 是一致的。
          virtual_router_id 80
      	# 优先级,同一个vrrp_instance的MASTER优先级必须比BACKUP高。
          priority 100
      	# MASTER 与BACKUP 负载均衡器之间同步检查的时间间隔,单位为秒。
          advert_int 1
      	# 验证authentication。包含验证类型和验证密码。类型主要有PASS、AH 两种,通常使用的类型为PASS.
      	# auth_pass 1111   验证密码为明文,同一vrrp 实例MASTER 与BACKUP 使用相同的密码才能正常通信。
          authentication {
              auth_type PASS
              auth_pass 1111
          }
      	# 虚拟VIP地址,可以有多个地址,每个地址占一行,不需要子网掩码
      	# 同时这个ip 必须与我们在lvs 客户端设定的vip 相一致!
          virtual_ipaddress {
      		# IP/掩码 dev 配置在哪个网卡
              192.168.121.100
          }
      }
    

    查看网卡信息: ens192

    [root@k8smaster02 ~]# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
            inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
            ether 02:42:69:7c:48:7a  txqueuelen 0  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.121.85  netmask 255.255.255.0  broadcast 192.168.121.255
            inet6 fe80::5c9d:d449:10ec:4a93  prefixlen 64  scopeid 0x20<link>
            ether 00:0c:29:80:f2:d2  txqueuelen 1000  (Ethernet)
            RX packets 5082611  bytes 1001842403 (955.4 MiB)
            RX errors 0  dropped 214969  overruns 0  frame 0
            TX packets 3506027  bytes 625335836 (596.3 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
            inet 10.244.1.0  netmask 255.255.255.255  broadcast 0.0.0.0
            inet6 fe80::742a:76ff:fee0:6bf5  prefixlen 64  scopeid 0x20<link>
            ether 76:2a:76:e0:6b:f5  txqueuelen 0  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 8 overruns 0  carrier 0  collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10<host>
            loop  txqueuelen 1  (Local Loopback)
            RX packets 1063669  bytes 199712666 (190.4 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 1063669  bytes 199712666 (190.4 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    [root@k8smaster02 ~]# 
    

    创建 nginx 状态检查脚本

     vi /etc/nginx/check_nginx.sh
     
     ## 复制如下脚本
     #!/bin/bash
     #egrep -cv "grep|$$" 用于过滤掉包含grep 或者 $$ 表示的当前Shell进程ID
     count=$(ps -ef | grep nginx | egrep -cv "grep|$$")
     
     if [ "$count" -eq 0 ];then
         systemctl stop keepalived
     fi
    

    nginx 检查脚本授权

     chmod +x /etc/nginx/check_nginx.sh 
    

    启动 keepalived 服务

     # 这里一定要先启动 nginx 服务,再启动 keepalived 服务
     systemctl start keepalived
     # systemctl start keepalived && systemctl enable nginx keepalived && systemctl status keepalived
     # 注意:keepalived无法启动的时候,查看keepalived.conf配置权限
     chmod 644 keepalived.conf
    

    查看 VIP 是否生成

    # vip 出现在 k8smaster01 上面,说明 keepalived 启动成功
    ip a	
    
    [root@k8smaster01 ~]# ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        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: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
        link/ether 00:0c:29:e8:47:17 brd ff:ff:ff:ff:ff:ff
        inet 192.168.121.84/24 brd 192.168.121.255 scope global ens192
           valid_lft forever preferred_lft forever
        inet 192.168.121.100/24 scope global secondary ens192  #vip
           valid_lft forever preferred_lft forever
        inet6 fe80::1797:4c42:2164:6773/64 scope link 
           valid_lft forever preferred_lft forever
    3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
        link/ether 02:42:4a:42:45:3e brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
    4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
        link/ether 46:17:82:bf:20:e1 brd ff:ff:ff:ff:ff:ff
    5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN 
        link/ether 62:06:88:86:57:a7 brd ff:ff:ff:ff:ff:ff
        inet 10.10.0.10/32 scope global kube-ipvs0
           valid_lft forever preferred_lft forever
        inet 10.10.0.1/32 scope global kube-ipvs0
           valid_lft forever preferred_lft forever
    6: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
        link/ether 62:d4:90:46:b6:86 brd ff:ff:ff:ff:ff:ff
        inet 10.244.0.0/32 scope global flannel.1
           valid_lft forever preferred_lft forever
        inet6 fe80::60d4:90ff:fe46:b686/64 scope link 
           valid_lft forever preferred_lft forever
    7: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP qlen 1000
        link/ether 12:fb:78:9c:46:1a brd ff:ff:ff:ff:ff:ff
        inet 10.244.0.1/24 brd 10.244.0.255 scope global cni0
    
    

    验证高可用功能,此时虚拟 ip 在 k8smaster01 上,我们在k8smaster01 中使用 pkill nginx 停止 nginx 服务,再在k8smaster02 上使用 ip a 命令查看地址是否进行了漂移。

    [root@k8smaster02 ~]# ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        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: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
        link/ether 00:0c:29:80:f2:d2 brd ff:ff:ff:ff:ff:ff
        inet 192.168.121.85/24 brd 192.168.121.255 scope global ens192
           valid_lft forever preferred_lft forever
        inet 192.168.121.100/24 scope global secondary ens192 #vip 漂移
           valid_lft forever preferred_lft forever
        inet6 fe80::5c9d:d449:10ec:4a93/64 scope link 
           valid_lft forever preferred_lft forever
    3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
        link/ether 02:42:c1:ae:c6:62 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
    4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
        link/ether 2e:33:79:c7:38:3b brd ff:ff:ff:ff:ff:ff
    5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN 
        link/ether 42:24:72:d0:31:d4 brd ff:ff:ff:ff:ff:ff
        inet 10.10.0.1/32 scope global kube-ipvs0
           valid_lft forever preferred_lft forever
        inet 10.10.0.10/32 scope global kube-ipvs0
           valid_lft forever preferred_lft forever
    6: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
        link/ether 76:02:37:09:b3:e8 brd ff:ff:ff:ff:ff:ff
        inet 10.244.1.0/32 scope global flannel.1
           valid_lft forever preferred_lft forever
        inet6 fe80::7402:37ff:fe09:b3e8/64 scope link 
           valid_lft forever preferred_lft forever
    [root@k8smaster02 ~]# 
    ~~~
    
    k8smaster01重启 nginx 在重启 keepalived,查看ip a vip已经回到k8smaster01。而 k8smaster02 上面是没有的,说明 keepalived + nginx 高可用配置正常。
    
    
    
    访问负载均衡器测试,找到 k8s 集群中任意一个节点,使用 curl +vip的ip+端口(16433)服务,即curl 请求地址为:https:*//192.168.121.100:16443*
    
    ```shell
    [root@k8smaster03 ~]# curl https://192.168.121.100:16443
    curl: (60) Peer's Certificate issuer is not recognized.
    More details here: http://curl.haxx.se/docs/sslcerts.html
    
    curl performs SSL certificate verification by default, using a "bundle"
     of Certificate Authority (CA) public keys (CA certs). If the default
     bundle file isn't adequate, you can specify an alternate file
     using the --cacert option.
    If this HTTPS server uses a certificate signed by a CA represented in
     the bundle, the certificate verification probably failed due to a
     problem with the certificate (it might be expired, or the name might
     not match the domain name in the URL).
    If you'd like to turn off curl's verification of the certificate, use
     the -k (or --insecure) option.
    [root@k8smaster03 ~]# 
    

    通过以下命令在 nginx 节点查看日志

    [root@k8smaster01 ~]# tail /var/log/nginx/k8s-access.log -f
    192.168.121.87 192.168.121.84:6443 - [01/Dec/2022:20:12:58 +0800] 200 172 # 192.168.121.84
    192.168.121.82 192.168.121.84:6443 - [01/Dec/2022:20:28:27 +0800] 200 172 
    192.168.20.29 192.168.121.85:6443 - [01/Dec/2022:20:29:45 +0800] 200 547  # 192.168.121.85
    192.168.20.29 192.168.121.85:6443 - [01/Dec/2022:20:29:49 +0800] 200 547
    192.168.20.29 192.168.121.87:6443 - [01/Dec/2022:20:29:49 +0800] 200 547  # 192.168.121.87
    192.168.20.29 192.168.121.84:6443 - [01/Dec/2022:20:29:56 +0800] 200 547
    192.168.20.29 192.168.121.85:6443 - [01/Dec/2022:20:30:06 +0800] 200 547
    192.168.20.29 192.168.121.87:6443 - [01/Dec/2022:20:30:06 +0800] 200 547
    192.168.20.29 192.168.121.87:6443 - [01/Dec/2022:20:30:06 +0800] 200 517
    192.168.20.29 192.168.121.84:6443 - [01/Dec/2022:20:30:06 +0800] 200 547
    

    可以看到轮询调度把请求流量分发给三台 master。

  2. 查看集群健康状态
     [root@k8smaster01 ~]# kubectl get cs
     NAME                 STATUS      MESSAGE                                                         ERROR
     scheduler            Unhealthy   Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connect: connection refused
     controller-manager   Unhealthy   Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connect: connection refused
     etcd-0               Healthy     {"health":"true"}
     
     # 出现这种情况是kube-controller-manager.yaml和kube-scheduler.yaml设置的默认端口是0,在文件中注释掉就可以了。(每台master节点都要执行操作)
     vim /etc/kubernetes/manifests/kube-scheduler.yaml
     vim /etc/kubernetes/manifests/kube-controller-manager.yaml
     # 每台master重启kubelet  
     systemctl restart kubelet.service
     或
     systemctl restart kubelet
     ~~~
    
    
  3. 安装 K8s-Dashboard

    使用如下命令下载 recommended.yaml

    wget  https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml

修改默认配置,默认 Dashboard 只能集群内部访问,为了能够从集群外部也能访问 Dashboard,修改其中 kubernetes-dashboard 的 service ,指定 nodePort 端口为 50001,新增 type 类型为 nodePort。

    vi recommended.yaml
    
    # 修改配置
    kind: Service
    apiVersion: v1
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
      name: kubernetes-dashboard
      namespace: kubernetes-dashboard
    spec:
      type: NodePort # 新增
      ports:
        - port: 443
          targetPort: 8443
          nodePort: 18443 # 新增
      selector:
        k8s-app: kubernetes-dashboard

上面配置项的解释:

  • apiVersion:指定api版本,此值必须在kubectl api-versions中

  • Kind:指定创建资源的角色/类型

  • metadata:资源的元数据/属性

  • name:资源 Service 类型的名称,在同一个 namespace 中必须唯一

  • namespace:资源 Service 所属的命名空间

  • spec:资源规范字段

  • selector:标签选择器,用于确定当前 Service 代理哪些 Pod,仅适用于 ClusterIP、NodePort 和 LoadBalancer 类型。如果类型为 ExternalName,则忽略。

  • type:NodePort 类型可以对外暴露,让外部访问这个集群,主要有 ClusterIP、NodePort、LoadBalancer 和 ExternalName,默认ClusterIP

  • ports:Service 对外暴露的端口列表

  • port:Service 服务监听的端口,Service 在集群内部暴露的端口

  • targetPort:Pod 端口容器暴露的端口

  • nodePort:对外暴露的端口号,如果不指定则随机生成一个端口号

部署 Dashboard

   # kubectl apply 命令是一种申明式的 API 调用办法,通过将 Pod 的配置编写在一份 yaml 文件中,再调用 API,进行 Pod 部署的形式
   kubectl apply -f recommended.yaml
   
   [root@k8smaster01 ~]# kubectl apply -f recommended.yaml
   namespace/kubernetes-dashboard unchanged
   serviceaccount/kubernetes-dashboard unchanged
   secret/kubernetes-dashboard-certs unchanged
   secret/kubernetes-dashboard-csrf configured
   Warning: resource secrets/kubernetes-dashboard-key-holder is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
   secret/kubernetes-dashboard-key-holder configured
   configmap/kubernetes-dashboard-settings unchanged
   role.rbac.authorization.k8s.io/kubernetes-dashboard unchanged
   clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard unchanged
   rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard unchanged
   clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard unchanged
   deployment.apps/kubernetes-dashboard created
   service/dashboard-metrics-scraper created
   deployment.apps/dashboard-metrics-scraper created
   The Service "kubernetes-dashboard" is invalid: spec.ports[0].nodePort: Invalid value: 18443: provided port is not in the valid range. The range of valid ports is 30000-32767

如上出现报错信息,端口范围错误,解决方法修改kube-apiserver.yaml文件,master节点都要修改。

     vim /etc/kubernetes/manifests/kube-apiserver.yaml
     # 找到 --service-cluster-ip-range 这一行,在这一行的下一行增加 如下内容
     - --service-node-port-range=1-65535
     
     # 配置如下
     apiVersion: v1
     kind: Pod
     metadata:
     creationTimestamp: null
     labels:
      component: kube-apiserver
      tier: control-plane
     name: kube-apiserver
     namespace: kube-system
     spec:
     containers:
      - command:
      - kube-apiserver
      - --advertise-address=192.168.0.254
      - --allow-privileged=true
      - --authorization-mode=Node,RBAC
      - --client-ca-file=/etc/kubernetes/pki/ca.crt
      - --enable-admission-plugins=NodeRestriction
      - --enable-bootstrap-token-auth=true
      - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
      - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
      - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
      - --etcd-servers=https://127.0.0.1:2379
      - --insecure-port=0
      - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
      - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
      - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
      - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
      - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
      - --requestheader-allowed-names=front-proxy-client
      - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
      - --requestheader-extra-headers-prefix=X-Remote-Extra-
      - --requestheader-group-headers=X-Remote-Group
      - --requestheader-username-headers=X-Remote-User
      - --secure-port=6443
      - --service-account-key-file=/etc/kubernetes/pki/sa.pub
      - --service-cluster-ip-range=10.1.0.0/16
      - --service-node-port-range=1-65535

最后 重启 kubelet

 systemctl daemon-reload
 systemctl restart kubelet

查看 pod,svc 状态:

   kubectl get pod,svc -n kubernetes-dashboard
   
   # 查询 Pod 
   kubectl get pod --all-namespaces -o wide | grep "dashboard"
   
   # 删除 Pod
   
   kubectl delete deployment kubernetes-dashboard  --namespace=kubernetes-dashboard
   kubectl delete deployment dashboard-metrics-scraper --namespace=kubernetes-dashboard
   
   # 查询 service
   
   kubectl get service -A
   
   # 删除 service
   kubectl delete service kubernetes-dashboard  --namespace=kubernetes-dashboard
   kubectl delete service dashboard-metrics-scraper  --namespace=kubernetes-dashboard
   
   # 删除账户和密钥
   kubectl delete sa kubernetes-dashboard --namespace=kubernetes-dashboard
   kubectl delete secret kubernetes-dashboard-certs --namespace=kubernetes-dashboard
   kubectl delete secret kubernetes-dashboard-key-holder --namespace=kubernetes-dashboard

访问指定的 18443 端口,master 节点 IP 为 192.168.121.100,通过 chrome 浏览器访问地址: https://192.168.121.100:18443

  1. 安装 Kuboard v3

       kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3.yaml
       # 您也可以使用下面的指令,唯一的区别是,该指令使用华为云的镜像仓库替代 docker hub 分发 Kuboard 所需要的镜像
       # kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3-swr.yaml
    

    执行指令 watch kubectl get pods -n kuboard,等待 kuboard 名称空间中所有的 Pod 就绪

    访问 Kuboard

    在浏览器中打开链接 http://your-node-ip-address:30080
    输入初始用户名和密码,并登录
    用户名: admin 密码: Kuboard123

安装 metrics server

Metrics-Server是k8s集群采集监控数据的聚合器,如采集node、pod的cpu、内存等数据,从 Kubernetes1.8 开始默认使用Metrics-Server采集数据,并通过Metrics API的形式提供查询,但是,kubeadm安装的k8s集群默认是没有安装Metrics-Server的,所以我们来安装一下Metrics-Server。

metrics-servery用途:metric-server主要用来通过aggregate api向其它组件(kube-scheduler、HorizontalPodAutoscaler、Kubernetes集群客户端等)提供集群中的pod和node的cpu和memory的监控指标,弹性伸缩中的podautoscaler就是通过调用这个接口来查看pod的当前资源使用量来进行pod的扩缩容的。

> 需要注意的是:
1.metric-server提供的是实时的指标(实际是最近一次采集的数据,保存在内存中),并没有数据库来存储
2.这些数据指标并非由metric-server本身采集,而是由每个节点上的cadvisor采集,metric-server只是发请求给cadvisor并将metric格式的数据转换成aggregate api
3.由于需要通过aggregate api来提供接口,需要集群中的kube-apiserver开启该功能(开启方法可以参考官方社区的文档)

**部署:**
yaml文件下载
官方地址是:https://github.com/kubernetes-sigs/metrics-server,最新的版本是v0.6.1
```shell
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.1/components.yaml
```
> 修改yaml文件,两处配置需要修改
1、因为下载的yaml是k8s官方镜像,所以将image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1改为阿里云的镜像image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1
2、在deployment中的args末尾中添加- args: - --kubelet-insecure-tls #添加这一句,表示不验证客户端证书
注意:k8s官方建议测试环境使用 --kubelet-insecure-tls	参数可以跳过证书认证,线上环境有必要的还是需要签发证书。
```shell
[root@k8smaster01 ~]# vim components.yaml
# 重新部署metrics-server
[root@k8smaster01 ~]# kubectl apply  -f components.yaml
# metrics-server pod已经成功运行
[root@k8smaster01 ~]# kubectl get pods -n kube-system -l k8s-app=metrics-server
NAME                             READY   STATUS    RESTARTS   AGE
metrics-server-568bfb584-xxsmn   1/1     Running   0          63s
[root@k8smaster01 ~]# 
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值