基于 Kubeadm 方式搭建 Kubernetes 单 Master 集群

大纲

Kubernetes 集群架构介绍

集群部署架构分类

  • 无中心节点架构的系统,比如:GlusterFS
  • 有中心节点架构的系统,比如:HDFS、K8s

Kubernetes 核心概念

Kubernetes 三个核心概念(Pod、Controller、Service)的介绍如下:

  • Pod(最小部署单元)

    • Pod 是 Kubernetes 中最小的调度和运行单元。
    • 本质上是一组容器的集合(通常是一个容器)。
    • 容器之间共享网络(IP、端口)和存储卷。
    • Pod 的生命周期可以是短暂的,比如用于运行临时任务或被控制器自动重建。
  • Controller(控制器)

    • 用于管理和自动化 Pod 的部署与副本数量。
    • 支持无状态应用部署(如 Deployment)。
    • 支持有状态应用部署(如 StatefulSet)。
    • 可实现以下功能:
      • 保证指定数量的 Pod 实例持续运行。
      • 在多个节点上部署同一类 Pod(如 DaemonSet)。
      • 支持一次性任务(Job)和定时任务(CronJob)。
  • Service(服务)

    • 负责定义一组 Pod 的访问规则。
    • 提供统一的访问入口(Cluster IP、NodePort、LoadBalancer 等),实现服务发现与负载均衡。
    • 解决 Pod 动态 IP 和短生命周期带来的访问不稳定问题。

这三个核心概念的关系:

  • Pod 是具体运行的实例。
  • Controller 管理 Pod 的创建、副本和调度。
  • Service 让外部或内部服务可以稳定地访问 Pod。

Kubernetes 集群架构概览

kubernetes-framework-2

Kubernetes 集群架构组件

kubernetes-framework-1

  • Master(主控节点):Kubernetes 集群控制节点,负责对集群进行调度管理,接受集群外的用户去集群操作请求。Master 由 API Server、Scheduler、Controller Manager、Etcd 存储系统组成

    • Scheduler:节点调度,选择 Node 节点来应用部署
    • API Server:集群统一入口,以 RESTful 接口将数据交给 Etcd 进行存储
    • Controller Manager:处理集群中的常规后台任务,一个资源对应一个控制器
    • Etcd 存储系统:用于存储集群相关的数据
  • Node(工作节点):Kubernetes 集群工作节点,负责运行用户业务应用容器,Node 由 Kubelet、Kube-Proxy 和 Container Runtime 组成

    • Kubelet:负责 Pod 对应的容器的创建、启停管理,与 Master 节点协作,实现集群管理的基本功能
    • Kube-Proxy:提供 Kubernetes 的通信与负载均衡功能的重要组件

Kubernetes 依赖容器运行时(Container Runtime)来管理和运行容器。

  • 历史上,Kubernetes 主要使用 Docker 作为容器运行时。Kubernetes 通过内置的 dockershim 组件与 Docker 实现兼容。
  • 从 Kubernetes 1.20 版本开始,官方宣布弃用内置的 dockershim 组件,逐步移除对 Docker 作为直接容器运行时的支持。
  • 现代 Kubernetes 推荐使用符合 Container Runtime Interface (CRI) 标准的容器运行时,主要有:
    • containerd:由 Docker 社区捐赠的轻量级容器运行时,稳定且高效,广泛使用。
    • CRI-O:专门为 Kubernetes 设计的容器运行时,注重轻量和安全。

Etcd 是什么

  • 在分布式系统中,Etcd 是一个高可用、强一致性的分布式键值存储系统,在 Kubernetes 等系统中扮演着核心元数据存储和协调中心的角色。
  • Etcd 属于更底层的基础组件,使用 Raft 算法实现强一致性(满足 CAP 中的 C 和 P),提供了一致性的 KV 存储、watch、lease、事务等机制。

Kubernetes 集群搭建说明

集群搭建要求

搭建 Kubernetes 集群需要满足以下几个条件:

  • 多台机器或虚拟机,建议操作系统 CentOS 7(64 位)
  • 集群中所有机器之间的网络可以互通
  • 系统内可以访问外网,需要拉取镜像
  • 系统禁用 Swap 分区(必须)
  • Master 节点的硬件配置要求
    • 当 Master 节点只运行运行控制平面组件(如 API Server、Controller Manager 和 Scheduler)
      • 2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 20GB 或更多
    • 当 Master 节点运行控制平面组件,且承载用户 Pod 的调度和运行任务
      • 6GB 或更多 RAM,6 个 CPU 或更多 CPU,硬盘 60GB 或更多
  • Node 节点的硬件配置要求
    • 4GB 或更多 RAM,4 个 CPU 或更多 CPU,硬盘 40GB 或更多

集群搭建类型

Kubernetes 集群搭建类型分为单 Master 集群和多 Master 集群两种(如下图所示),为了提高集群的可用性,生产环境一般采用多 Master 集群方案。

kubernetes-cluster-plan

搭建单 Master 集群

术语说明

为了方便描述,本文使用 Node 节点 来替代 Kubernetes 的 Worker Node,使用 Master 节点 来替代 Master Node

搭建目标

本节将基于 Kubeadm 方式搭建单 Master 的 Kubernetes 集群,核心目标如下

  • (1) 在所有节点上分别安装 Docker、Kubeadm、Kubectl、Kubelet
  • (2) 初始化 Kubernetes 的 Master 节点
  • (3) 部署 CNI 网络插件(Flannel)
  • (4) 将 Node 节点加入到 Kubernetes 集群中
  • (5) 部署 Dashboard 可视化插件,可视化监控 Kubernetes 资源

版本说明

软件版本安装方式
CentOS7.9多个独立虚拟机
Docker18.06.1YUM
Kubelet1.18.0YUM
Kubectl1.18.0YUM
Kubeadm1.18.0YUM
Dashboard2.0.3Kubernetes

服务器规划

kubernetes-kubeadm-1

Host 名称角色 IPCPU 核数内存磁盘
k8s-mastermaster192.168.31.61>= 2C>=2G>=20G
k8s-node1node(worker)192.168.31.62>= 4C>=4G>=40G
k8s-node2node(worker)192.168.31.63>= 4C>=4G>=40G
k8s-node3node(worker)192.168.31.64>= 4C>=4G>=40G

操作系统初始化

t 特别注意

  • 以下系统初始化操作都必须在所有节点(包括 Master 和 Node)上都执行一次,重点是安装 Docker、Kubeadm、Kubectl、Kubelet
  • 这里要求 Kubelet、Kubeadm、Kubectl 的版本与 Docker 的版本互相匹配(兼容),不建议安装最新版本的 Docker,因为 Kubernetes 对最新版的 Docker 兼容不够及时,容易导致使用 Kubeadm 方式搭建 Kubernetes 集群失败。

关闭防火墙

1
2
3
4
5
# 临时关闭
# systemctl stop firewalld

# 永久关闭
# systemctl disable firewalld

关闭 selinux

1
2
3
4
5
# 临时关闭
# setenforce 0

# 永久关闭
# sed -i 's/enforcing/disabled/' /etc/selinux/config

关闭 swap 分区

1
2
3
4
5
# 临时关闭
$ swapoff -a

# 永久关闭
# sed -i 's/.*swap.*/#&/' /etc/fstab

系统时间同步(强烈建议使用 chrony 而不是 ntpdate)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 卸载ntpdate服务
# yum remove -y ntpdate

# 安装chrony服务
# yum install -y chrony

# 开机自启动chrony服务
# systemctl enable chronyd

# 启动chrony服务
# systemctl start chronyd

# 配置NTP源,添加国内公共的NTP服务器
# vim /etc/chrony.conf
server ntp.aliyun.com iburst
server ntp1.tencent.com iburst
server cn.pool.ntp.org iburst

# 重启chrony服务
# systemctl restart chronyd

# 检查chrony服务的运行状态
# systemctl status chronyd

# 查看chrony服务的时间同步状态
# chronyc tracking

# 强制同步一次时间(只在刚部署、时间差很多的时候用)
# chronyc makestep

设置主机名(比如 k8s-masterk8s-node1k8s-node2k8s-node3

1
# hostnamectl set-hostname <hostname>

添加 hosts 配置信息

1
2
3
4
5
6
# 添加hosts信息
# vim /etc/hosts
192.168.31.61 k8s-master
192.168.31.62 k8s-node1
192.168.31.63 k8s-node2
192.168.31.64 k8s-node3

将桥接的 IPv4 流量传递到 iptables 的链

1
2
3
4
5
6
7
# 创建系统配置文件,并添加路由规则
# vim /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# 使配置生效
# sysctl --system

安装特定版本的 Docker,这是由于 Kubernetes 默认的 CRI(容器运行时)为 Docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 添加YUM源
# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

# 安装Docker(指定版本号,否则默认安装最新版本)
# yum -y install docker-ce-18.06.1.ce-3.el7

# 开机自启动Docker
# systemctl enable docker

# 启动Docker
# systemctl start docker

# 创建Docker的配置目录
# mkdir /etc/docker

# 配置阿里的Docker镜像加速(请更换自己的镜像地址,或者使用国内公共的镜像地址)
# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": [
"https://b9pmyelo.mirror.aliyuncs.com",
"https://ustc-edu-cn.mirror.aliyuncs.com",
"https://mirror.iscas.ac.cn",
"https://docker.nju.edu.cn",
"https://docker.m.daocloud.io",
"https://ccr.ccs.tencentyun.com",
"https://dockerhub.timeweb.cloud"
]
}
EOF

# 重启Docker
# systemctl restart docker

# 查看Docker的运行状态
# systemctl status docker

# 查看Docker的版本
# docker --version

# 查看Docker的安装信息
# docker info

安装特定版本的 Kubeadm、Kubectl、Kubelet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 添加YUm源
# 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
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

# 安装(指定版本号,否则默认会安装最新版本)
# yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0

# 开机自启动Kubelet
# systemctl enable kubelet

# 提示:Kubelet安装完成后不需要手动启动,因为在Node节点成功加入集群之前,Kubelet自身会不断重启(期间会伴随着各种启动错误,这点不用在意)

Kubelet、Kubeadm、Kubectl 的作用

组件作用使用场景
Kubelet 每个 Node 上的核心组件,负责管理 Pod 生命周期,与 API Server 通信,执行容器操作每个 Node 上都必须运行 Kubelet,确保容器按 PodSpec 正确运行
KubectlKubernetes 的命令行客户端工具,用于与 API Server 通信,管理资源查询资源(kubectl get)、创建资源(kubectl apply)、调试排查(kubectl logs
Kubeadm 用于快速部署和管理 Kubernetes 集群的工具初始化主节点(kubeadm init)、加入工作节点(kubeadm join)、升级集群等

初始化 Master 节点

在 Master 节点上,通过 Kubeadm 初始化 Master 节点,命令行参数 --service-cidr--pod-network-cidr 一般都不需要更改,其他参数请根据自己的实际情况进行修改,详细参数说明如下,点击查看详细的初始化日志信息

  • --apiserver-advertise-address:Master 节点的 IP 地址(需要自行更改),还可以指定为 Haproxy + Keepalived 的 VIP
  • --kubernetes-version:Kubernetes 的版本号,必须与上面 Kubelet 的版本号一致
  • --image-repository:由于默认拉取镜像的地址 k8s.gcr.io 在国内无法访问,所以需要指定阿里云镜像仓库地址
  • --pod-network-cidr:指定 Pod Network 的地址范围,由于 Kubernetes 支持多种网络方案,而且不同网络方案对参数有各自要求,设置为 10.244.0.0/16 表示使用 Flannel 网络方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 初始化Master节点
# kubeadm init \
--apiserver-advertise-address=192.168.31.61 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16

# 当终端打印如下的提示信息,则说明Docker开始拉取镜像,这个过程比较耗时(严重依赖网速),当镜像拉取完成后,会自动启动相关的Docker容器
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'

# 初始化完成后,记录下终端最后打印的Kubeadm命令(如下所示),后续添加Node节点到K8s集群时会使用到
### kubeadm join 192.168.1.109:6443 --token jve1cd.3ulp5fqifsptti23 --discovery-token-ca-cert-hash sha256:01229ee179cf13855dbf38bc050b3251928571996d60878f30ce13c08aaa62d5

# 查看已拉取的Docker镜像列表
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.aliyuncs.com/google_containers/kube-proxy v1.18.0 43940c34f24f 11 months ago 117MB
registry.aliyuncs.com/google_containers/kube-apiserver v1.18.0 74060cea7f70 11 months ago 173MB
registry.aliyuncs.com/google_containers/kube-controller-manager v1.18.0 d3e55153f52f 11 months ago 162MB
registry.aliyuncs.com/google_containers/kube-scheduler v1.18.0 a31f78c7c8ce 11 months ago 95.3MB
registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5d 13 months ago 683kB
registry.aliyuncs.com/google_containers/coredns 1.6.7 67da37a9a360 13 months ago 43.8MB
registry.aliyuncs.com/google_containers/etcd 3.4.3-0 303ce5db0e90 16 months ago 288MB

# 查看正在运行的Docker容器列表
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8902ba7f9c36 43940c34f24f "/usr/local/bin/kube…" 6 minutes ago Up 6 minutes k8s_kube-proxy_kube-proxy-5wbfw_kube-system_feace9db-cf7f-44c0-8cb0-9cb057e9833c_0
9657b36dd4e4 registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 6 minutes ago Up 6 minutes k8s_POD_kube-proxy-5wbfw_kube-system_feace9db-cf7f-44c0-8cb0-9cb057e9833c_0
563fa6cc803d 74060cea7f70 "kube-apiserver --ad…" 7 minutes ago Up 7 minutes k8s_kube-apiserver_kube-apiserver-k8s-master_kube-system_f3e487c167f719bc8a1a89c83db337de_0
487a0a0789f0 303ce5db0e90 "etcd --advertise-cl…" 7 minutes ago Up 7 minutes k8s_etcd_etcd-k8s-master_kube-system_f81fbe2336e90a6be7ee4138c7f4cf4a_0
24b369e313bf a31f78c7c8ce "kube-scheduler --au…" 7 minutes ago Up 7 minutes k8s_kube-scheduler_kube-scheduler-k8s-master_kube-system_ca2aa1b3224c37fa1791ef6c7d883bbe_0
bcce27087ebe d3e55153f52f "kube-controller-man…" 7 minutes ago Up 7 minutes k8s_kube-controller-manager_kube-controller-manager-k8s-master_kube-system_c4d2dd4abfffdee4d424ce839b0de402_0
cb06c651871a registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 7 minutes ago Up 7 minutes k8s_POD_kube-scheduler-k8s-master_kube-system_ca2aa1b3224c37fa1791ef6c7d883bbe_0
e8aea6d3013c registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 7 minutes ago Up 7 minutes k8s_POD_kube-controller-manager-k8s-master_kube-system_c4d2dd4abfffdee4d424ce839b0de402_0
f204181916d3 registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 7 minutes ago Up 7 minutes k8s_POD_kube-apiserver-k8s-master_kube-system_f3e487c167f719bc8a1a89c83db337de_0
2f8174b2abff registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 7 minutes ago Up 7 minutes k8s_POD_etcd-k8s-master_kube-system_f81fbe2336e90a6be7ee4138c7f4cf4a_0

在 Master 节点配置 Kubectl 工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建目录
# mkdir -p $HOME/.kube

# 拷贝配置文件
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

# 文件授权
# chown $(id -u):$(id -g) $HOME/.kube/config

# 查看组件的运行状态
# kubectl get cs
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health":"true"}

# 提示:当上面的 STATUS 都变更为 "Healthy"(可能需要等待一段时间),则表示组件都处于健康状态,否则需要检查错误;如果排除不了问题,可以使用 "kubeadm reset" 命令重置 Master 节点,然后再重新执行 "kubeadm init" 命令初始化 Master 节点

Master 节点安装 CNI 网络插件

CNI 网络插件的安装细节

特别注意,网上有部分资料是在将 Node 节点加入到 Kubernetes 集群之后,才开始安装 CNI 网络插件的,本文给出的教程刚好相反。由于 kubectl apply 这个命令会创建一个 DaemonSet 类型的资源,而 DaemonSet 的特性是:会在 Kubernetes 集群中所有「可调度」的 Node 节点上运行一个 Pod 副本。所以,即使在安装 CNI 网络插件时,Node 节点还没加入 Kubernetes 集群,一旦执行 kubeadm join 操作,新加入的 Node 节点会被 Kubernetes 集群感知到,Kubelet 连接成功后,DaemonSet 就会在新 Node 节点上自动调度一个 Pod(比如 Flannel Pod)。换言之,在 Master 节点上,通过 kubectl apply 命令安装 CNI 网络插件后,默认会将 CNI 网络插件部署到整个 Kubernetes 集群的所有节点(包括 Master 和 Node),无需手动在每个节点上重复执行 kubectl apply 命令来安装 CNI 网络插件。

为什么必须安装 CNI 网络插件

  • Kubernetes 本身不包含网络实现,但它要求集群中的所有 Pod 能够彼此通信(无论位于哪个节点),这是 Kubernetes 网络模型的基本要求。
  • 通过 Kubeadm 搭建 Kubernetes 集群时,使用 kubeadm init 初始化 Master 节点后,默认只有控制平面功能,没有网络功能。
  • 当没有安装 CNI 网络插件时,Pod 会卡在 ContainerCreating 状态,因为找不到网络(CNI)配置。
  • 当安装 CNI 网络插件(如 Flannel)后,多个节点之间的 Pod 才能通信和正常运行。

在 Master 节点查看所有节点的运行状态,此时 Master 节点处于 NotReady(未就绪)状态,这是因为集群中尚未安装 Flannel 网络插件,安装完网络插件后状态会自动变为 Ready

1
2
3
4
# 查看所有节点的运行状态
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady master 12m v1.18.0

在 Master 节点安装 Flannel 网络插件,若 kubectl apply -f 命令执行后提示网络连接失败,可留意文章后面给出的解决方案

1
2
# 安装Flannel网络插件
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

在 Master 节点查看 Pod 的运行状态,当所有 Pod 的运行状态都变更为 Running(可能需要等待十几分钟甚至几十分钟),则说明所有 Pod 都正常运行

1
2
3
4
5
6
7
8
9
10
11
# 查询Pod的运行状态
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7ff77c879f-67rjn 1/1 Running 0 4m35s
coredns-7ff77c879f-xpq9h 1/1 Running 0 4m35s
etcd-k8s-master 1/1 Running 0 4m44s
kube-apiserver-k8s-master 1/1 Running 0 4m44s
kube-controller-manager-k8s-master 1/1 Running 0 4m44s
kube-flannel-ds-4jtp4 1/1 Running 0 2m36s
kube-proxy-8bbhk 1/1 Running 0 4m34s
kube-scheduler-k8s-master 1/1 Running 0 4m44s

特别注意

Flannel 网络插件安装完成后,需要耐心等待一段较长的时间(可能需要等待十几分钟甚至几十分钟),直到使用 kubectl get pods -n kube-system 命令查看到的所有 Pod 的运行状态都变更为 Running 为止,也就是说 Pod 的状态最终不能为 Pending,否则说明 Pod 的运行存在一定的问题,需要进一步定位错误原因。

在 Master 节点再次查看所有节点的运行状态,当 Master 节点的运行状态变更为 Ready 状态,就可以开始将 Node 节点加入集群了

1
2
3
4
# 查看所有节点的运行状态
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 12m v1.18.0

将 Node 节点加入到 Kubernetes 集群

在各个 Node 节点里分别执行以下命令(请自行更改,切忌直接复制执行),向 Kubernetes 集群添加新节点,该命令是上面 kubeadm init 命令执行完成后在终端记录下来的

1
2
# 添加Node节点到集群
# kubeadm join 192.168.1.109:6443 --token jve1cd.3ulp5fqifsptti23 --discovery-token-ca-cert-hash sha256:01229ee179cf13855dbf38bc050b3251928571996d60878f30ce13c08aaa62d5

在 Master 节点执行以下命令,查看集群中所有 Node 节点的运行状态,当它们的运行状态都变更为 Ready 时(需要等待一段较长的时间),则表示所有 Node 节点都成功加入了集群

1
2
3
4
5
6
7
# 查看所有节点的运行状态
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 24h v1.18.0
k8s-node1 Ready <none> 92m v1.18.0
k8s-node2 Ready <none> 91m v1.18.0
k8s-node3 Ready <none> 91m v1.18.0

特别注意

这里通过 kubeadm join 命令将各个 Node 节点加入集群后,需要等待一段较长的时间(可能十几分钟甚至几十分钟),才能看到集群中所有 Node 节点的运行状态从 NotReady 变更为 Ready

测试 Kubernetes 集群是否正常运行

在 Master 节点执行以下命令,查看集群中所有节点的运行状态,当它们的运行状态都变更为 Ready 时,则表示 Kubernetes 集群已经成功搭建起来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 查看所有节点的运行状态
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 24h v1.18.0
k8s-node1 Ready <none> 92m v1.18.0
k8s-node2 Ready <none> 91m v1.18.0
k8s-node3 Ready <none> 91m v1.18.0

# 查询Pod的运行状态
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7ff77c879f-67rjn 1/1 Running 0 30m
coredns-7ff77c879f-xpq9h 1/1 Running 0 30m
etcd-k8s-master 1/1 Running 0 30m
kube-apiserver-k8s-master 1/1 Running 0 30m
kube-controller-manager-k8s-master 1/1 Running 0 30m
kube-flannel-ds-4jtp4 1/1 Running 0 28m
kube-flannel-ds-6k8sp 1/1 Running 0 23m
kube-flannel-ds-bzwrt 1/1 Running 0 23m
kube-flannel-ds-rc8vv 1/1 Running 0 23m
kube-proxy-8bbhk 1/1 Running 0 30m
kube-proxy-9f96v 1/1 Running 0 23m
kube-proxy-9j6qh 1/1 Running 0 23m
kube-proxy-bqm7t 1/1 Running 0 23m
kube-scheduler-k8s-master 1/1 Running 0 30m

# 查看集群版本
# kubectl version --short
Client Version: v1.18.0
Server Version: v1.18.0

# 提示:当各节点的 Linux 系统重启后,Kubernetes 集群里对应的组件会自动启动,不需要人为干预

在 Master 节点执行以下命令,目的是在 Kubernetes 集群里创建一个 Nginx 的 Deployment,验证 Kubernetes 集群是否正常运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建Nginx
# kubectl create deployment nginx --image=nginx

# 暴露Nginx的端口
# kubectl expose deployment nginx --port=80 --type=NodePort --target-port=80

# 查看Pod
# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod/nginx-f89759699-59cb7 1/1 Running 0 2m1s

# 查看Service
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 48m
service/nginx NodePort 10.102.129.11 <none> 80:32517/TCP 10s

通过浏览器访问 http://192.168.31.62:32517,请自行更改 IP 和端口;其中 IP 可以是任意节点的 IP 地址,端口由 kubectl get svc 命令可得知。若 Ngninx 容器在 Kubernetes 集群中创建并启动成功,则浏览器可以正常访问 Nginx 的首页(如下图所示),如下图所示:

若希望删除刚在 Kubernetes 集群创建的 Nginx 容器,可以在 Master 节点执行以下命令:

1
2
3
4
5
# 删除Service
# kubectl delete service nginx

# 删除Deployment
# kubectl delete deployment nginx

部署 Dashboard 可视化插件

在 Kubernetes 集群部署 Dashboard 可视化插件的过程中,以下所有操作都是直接在 Master 节点里执行,后续不再累述。

Dashboard 简介

在 Kubernetes 社区中,有一个很受欢迎的 Dashboard 项目,它可以给用户提供一个可视化的 Web 界面来查看当前集群的各种信息。用户可以用 Kubernetes Dashboard 部署容器化的应用、监控应用的运行状态、执行故障排查任务以及管理 Kubernetes 各种资源。

特别注意

Dashboard 的版本必须与 Kubernetes 版本相匹配(兼容),否则 Dashboard 可能无法正常运行。

Dashboard 部署

通过 YAML 文件直接部署 Dashboard,这里的 Kubernetes 1.8 版本对应的 Dashboard 版本为 v2.0.3,两者的版本号必须匹配

1
2
# 部署Dashboard
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml

查看 Dashboard 的运行状态,可以看到运行了 2 个 Pod 及 2 个 Service

1
2
3
4
5
6
7
8
9
10
11
# 查看Pod的运行状态
# kubectl -n kubernetes-dashboard get pods
NAME READY STATUS RESTARTS AGE
dashboard-metrics-scraper-69b5dcbfcb-zq9sd 1/1 Running 0 9m36s
kubernetes-dashboard-5795496d75-jfmfq 1/1 Running 0 9m15s

# 查看Service的运行状态
# kubectl -n kubernetes-dashboard get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.96.115.247 <none> 8000/TCP 117s
kubernetes-dashboard ClusterIP 10.100.88.170 <none> 443/TCP 117s

特别注意

  • 使用 kubectl -n kubernetes-dashboard get pods 命令查看 Dashboard 的运行状态时,必须确保 Pod 的状态为 Running,且 RESTARTS = 0,否则 Dashboard 可能无法正常运行。当 Dashboard 无法正常运行,可以执行以下两个命令重启 Dashboard:
  • (1) 重启 Dashboard Metrics Scraper:kubectl -n kubernetes-dashboard rollout restart deployment dashboard-metrics-scraper
  • (2) 重启 Dashboard:kubectl -n kubernetes-dashboard rollout restart deployment kubernetes-dashboard

Dashboard 暴露服务

这里作为演示,使用 NodePort 方式将 Dashboard 的服务暴露在集群外,指定使用 30443 端口(可自定义)

1
2
3
4
5
6
7
8
# 暴露Service
# kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard -p '{"spec":{"type":"NodePort","ports":[{"port":443,"targetPort":8443,"nodePort":30443}]}}'

# 查看暴露的Service
# kubectl -n kubernetes-dashboard get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.96.115.247 <none> 8000/TCP 6m2s
kubernetes-dashboard NodePort 10.100.88.170 <none> 443:30443/TCP 6m2s

或者下载 YAML 文件,手动更改 Service 部分的端口,并以 NodePort 方式进行部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 下载YAML文件
# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml

# 更改YAML文件
# vim 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: 30443
selector:
k8s-app: kubernetes-dashboard
---

# 更新配置
# kubectl apply -f recommended.yaml

Dashboard 认证方式登录

Dashboard 支持 Kubeconfig 和 Token 两种认证方式,这里选择 Token 认证方式登录,首先执行以下操作创建登录用户

1
2
3
4
5
# 创建YAML配置文件,复制下面的配置内容到文件中
# vim dashboard-adminuser.yaml

# 创建Dashboard登录用户
# kubectl apply -f dashboard-adminuser.yaml

YAML 配置文件 dashboard-adminuser.yaml 的完整内容如下,指定了一个名称为 admin-user 的服务账号,并放在 kubernetes-dashboard 命名空间下,同时将 cluster-admin 角色绑定到 admin-user 账户,这样 admin-user 账户就有了管理员的权限。默认情况下,Kubeadm 创建集群时已经创建了 cluster-admin 角色,只需直接绑定即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard

查看 admin-user 账户的 Token

1
2
# 查看Token
# kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

通过火狐浏览器访问 Dashboard 的登录界面,URL 是 https://<any_node_ip>:30443,其中 any_node_ip 可以是任意一个集群节点的 IP 地址。由于谷歌浏览器会强制使用 HTTPS 协议,这将导致无法访问 Dashboard 的登录页面,因此建议使用火狐浏览器进行访问

kubernetes-dashboard-1

将获取到的 Token 复制到登录界面的 Token 输入框中,这样就可以正常登录 Dashboard

kubernetes-dashboard-2

Dashboard 配置登录超时

提示

Dashboard 默认登录超时时间是 15min,可以为 Dashboard 容器增加 --token-ttl 参数来自定义登录超时时间。

下载并打开对应的 YAML 配置文件

1
2
3
4
5
# 下载YAML文件
# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml

# 编辑YAML文件
# vim recommended.yaml

然后找到 --auto-generate-certificates 配置项(如下所示),在它后面添加 --token-ttl=43200 配置项

1
2
3
4
5
6
7
8
9
10
11
12
spec:
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.0.3
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
- --token-ttl=43200 # 只需要添加这行配置内容

最后更新配置信息

1
2
# 更新配置信息
# kubectl apply -f recommended.yaml

单 Master 集群搭建问题

集群搭建问题一

1
[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2

执行 kubeadm init 命令时,提示 CPU 核心数少于 2,可以添加命令参数 --ignore-preflight-errors=NumCPU 忽略警告

集群搭建问题二

1
[ERROR Swap]: running with swap on is not supported. Please disable swap

执行 kubeadm init 命令时,提示启用了 swap 分区,可以添加命令参数 --ignore-preflight-errors 'Swap' 忽略错误,强烈建议禁用 Swap 分区,而不是忽略该错误信息

集群搭建问题三

1
[WARNING SystemVerification]: this Docker version is not on the list of validated versions: 19.03.1. Latest validated version: 18.09

执行 kubeadm init 命令时,提示 Docker 的版本过高,可能与 Kubernetes 的版本不兼容

集群搭建问题四

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

执行 kubectl apply -f https://raw.githubusercontent.com/xxx 命令时,提示网络链接失败,这是国内无法访问 raw.githubusercontent.com 导致,临时解决方法如下:

  • https://www.ipaddress.com 网站上查询 raw.githubusercontent.com 域名的真实 IP 地址
  • 更改系统的 /etc/hosts 配置文件,添加一行内容 185.199.108.133 raw.githubusercontent.com,将 185.199.108.133 替换为查询到真实的 IP 地址
  • 重新执行 kubectl apply -f https://raw.githubusercontent.com/xxx 命令即可

参考资料