目录
[一、Kubernetes 简介及部署方法](#一、Kubernetes 简介及部署方法)
[1 应用部署方式演变](#1 应用部署方式演变)
[2 容器编排应用](#2 容器编排应用)
[3 Kubernetes 简介](#3 Kubernetes 简介)
[4 K8S 的设计架构](#4 K8S 的设计架构)
[1.4.1 K8S 各个组件用途](#1.4.1 K8S 各个组件用途)
[1.4.2 K8S 各组件之间的调用关系](#1.4.2 K8S 各组件之间的调用关系)
[1.4.3 K8S 的 常用名词概念](#1.4.3 K8S 的 常用名词概念)
[1.4.4 k8S 的分层架构](#1.4.4 k8S 的分层架构)
[二、K8S 集群环境搭建](#二、K8S 集群环境搭建)
[2.1 k8s 中容器的管理方式](#2.1 k8s 中容器的管理方式)
[2.2 k8s 集群部署](#2.2 k8s 集群部署)
[2.2.1 k8s 环境部署说明](#2.2.1 k8s 环境部署说明)
[2.2.2 集群环境初始化](#2.2.2 集群环境初始化)
[2.2.2.1. 所有禁用 swap 和本地解析](#2.2.2.1. 所有禁用 swap 和本地解析)
[2.2.2.2. 所有安装 docker](#2.2.2.2. 所有安装 docker)
[2.2.2.3. 所有节点设定 docker 的资源管理模式为 systemd](#2.2.2.3. 所有节点设定 docker 的资源管理模式为 systemd)
[2.2.2.4. 所有节点复制 harbor 仓库中的证书并启动 docker](#2.2.2.4. 所有节点复制 harbor 仓库中的证书并启动 docker)
[2.2.2.5 安装 K8S 部署工具](#2.2.2.5 安装 K8S 部署工具)
[2.2.2.6 设置 kubectl 命令补齐功能](#2.2.2.6 设置 kubectl 命令补齐功能)
[2.2.2.7 在所有节点安装 cri-docker](#2.2.2.7 在所有节点安装 cri-docker)
[2.2.2.8 在 master 节点拉取 K8S 所需镜像](#2.2.2.8 在 master 节点拉取 K8S 所需镜像)
[2.2.2.9 集群初始化](#2.2.2.9 集群初始化)
[2.2.2.10 安装 flannel 网络插件](#2.2.2.10 安装 flannel 网络插件)
[2.2.2.11 节点扩容](#2.2.2.11 节点扩容)
[1. 加载模块 (所有节点)](#1. 加载模块 (所有节点))
[2. 调整内核功能参数 (所有节点)](#2. 调整内核功能参数 (所有节点))
[3. 禁用 swap (所有节点)](#3. 禁用 swap (所有节点))
[4. 部署软件仓库 (所有节点)](#4. 部署软件仓库 (所有节点))
[5. 安装 kubernetes 所需软件](#5. 安装 kubernetes 所需软件)
[master 节点](#master 节点)
[work 节点](#work 节点)
[一、构建 harbor 镜像仓库](#一、构建 harbor 镜像仓库)
[1. 安装 docker](#1. 安装 docker)
[2. 生成 key](#2. 生成 key)
[3. 编辑 harbor 配置文件](#3. 编辑 harbor 配置文件)
[4. 启动并验证](#4. 启动并验证)
[二、构建部署 kubernetes 所需主机](#二、构建部署 kubernetes 所需主机)
[1. 所有主机配置](#1. 所有主机配置)
[三、kubernetes 的部署](#三、kubernetes 的部署)
[1. 安装 cri-dockerd (所有主机中安装)](#1. 安装 cri-dockerd (所有主机中安装))
[2. 安装构建 kubernetes 集群所需软件](#2. 安装构建 kubernetes 集群所需软件)
[3. 下载 kubernetes 集群所需镜像](#3. 下载 kubernetes 集群所需镜像)
[4. 在 master 中初始化 kubernetes 集群](#4. 在 master 中初始化 kubernetes 集群)
[5. 安装网络插件](#5. 安装网络插件)
一、Kubernetes 简介及部署方法
1 应用部署方式演变
在部署应用程序的方式上,主要经历了三个阶段:
传统部署 虚拟化部署 容器部署
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ App │ │ App │ │ App │
│ Bin/Library │ │ Bin/Library │ │ Bin/Library │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ OS │ │ VM │ │ Container │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ Hardware │ │ Hypervisor │ │Container Runtime│
└─────────────┘ ├─────────────┤ ├─────────────┤
│ OS │ │ OS │
├─────────────┤ ├─────────────┤
│ Hardware │ │ Hardware │
└─────────────┘ └─────────────┘

【图片位置 1:应用部署方式演进图】
传统部署:互联网早期,会直接将应用程序部署在物理机上
- 优点:简单,不需要其它技术的参与
- 缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
- 优点:程序环境不会相互产生影响,提供了一定程度的安全性
- 缺点:增加了操作系统,浪费了部分资源
容器化部署:与虚拟化类似,但是共享了操作系统
生活类比:这就像住房的演变。传统部署是 "大杂院",所有人共用一个院子,互相干扰;虚拟化部署是 "公寓楼",每户有独立的房间和水电,但每户都要单独装修;容器部署是 "胶囊公寓",每个人有独立的睡眠空间,但共享公共的厨房、卫生间和走廊,空间利用率最高。
**[!NOTE]**容器化部署方式带来很多的便利,但是也会出现一些问题,比如说:
- 一个容器故障停机了,怎么样让另外一个容器立刻启动去替补停机的容器
- 当并发访问量变大的时候,怎么样做到横向扩展容器数量
- 容器最终还要落地在硬件上
K8S 是对容器进行自动编排的工具;自动检索我所控制的主机当中谁的资源是最合适运行这个容器的,那我就让这个容器在哪里去运行;一个和操作系统绑定越来越浅的过程;
核心解释:Kubernetes 本质上是一个 "容器操作系统",它把整个数据中心抽象成一台巨大的计算机。你只需要告诉它 "我要运行 5 个 Nginx 容器",它会自动找最合适的服务器去运行,容器挂了自动重启,流量大了自动扩容。
2 容器编排应用
为了解决这些容器编排问题,就产生了一些容器编排的软件:
- Swarm:Docker 自己的容器编排工具
- Mesos:Apache 的一个资源统一管控的工具,需要和 Marathon 结合使用
- Kubernetes:Google 开源的的容器编排工具

容器编排工具市场份额
┌─────────────────────────────────────────────────┐
│ Kubernetes 77% ████████████████████████████ │
│ OpenShift 10% ████ │
│ Amazon ECS 2% █ │
│ 其他 11% ████ │
└─────────────────────────────────────────────────┘
【图片位置 2:容器编排工具市场份额图】
企业级生产应用:
- 千万级并发场景:Kubernetes 是互联网大厂的标准配置。淘宝双 11、微信红包、抖音直播等场景,背后都是数万节点的 Kubernetes 集群在支撑。
- 进阶优化 :
- 使用 Kubernetes 集群联邦(Federation)管理跨地域集群
- 采用虚拟节点(Virtual Kubelet)实现弹性扩容到公有云
- 使用 KEDA(Kubernetes Event-Driven Autoscaling)实现基于事件的自动伸缩
3 Kubernetes 简介

kubernetes
- 名字由来:中间有 8 个字母,所以简称 K8S
- 在 Docker 作为高级容器引擎快速发展的同时,在 Google 内部,容器技术已经应用了很多年。Borg 系统运行管理着成千上万的容器应用。
- Kubernetes 项目来源于 Borg,可以说是集结了 Borg 设计思想的精华,并且吸收了 Borg 系统中的经验和教训。
- Kubernetes 对计算资源进行了更高层次的抽象 (化繁为简),通过将容器进行细致的组合,将最终的应用服务交给用户。
kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
- 自我修复:一旦某一个容器崩溃,能够在 1 秒左右迅速启动新的容器
- 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
- 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
- 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
- 存储编排:可以根据容器自身的需求自动创建存储卷
大大减少了人为处理。
核心解释:Google 在 2004 年就开始使用容器技术,Borg 系统管理着全球数百万台服务器上的数十亿个容器。Kubernetes 是 Borg 的开源版本,相当于把 Google 十几年的大规模容器管理经验免费送给了全世界。
4 K8S 的设计架构
1.4.1 K8S 各个组件用途

Kubernetes集群架构
┌─────────────────────────────────────────────────────────────┐
│ 主控节点/Master │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ API Server│ │Scheduler │ │Controller│ │ Etcd │ │
│ │ │ │ │ │ Manager │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 工作节点/Node │ │ 工作节点/Node │ │ 工作节点/Node │
│ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │
│ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │
│ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ kube-proxy │ │ │ │ kube-proxy │ │ │ │ kube-proxy │ │
│ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │
│ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ Docker │ │ │ │ Docker │ │ │ │ Docker │ │
│ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │
│ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │
│ │ Pod Pod Pod │ │ │ │ Pod Pod Pod │ │ │ │ Pod Pod Pod │ │
│ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
【图片位置 3:Kubernetes 集群架构图】
**解释这个图:**一个 kubernetes 集群主要是由控制节点 (master)、工作节点 (node) 构成,每个节点上都会安装不同的组件。
1. master:集群的控制平面,负责集群的决策
- ApiServer:资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API 注册和发现等机制
- Scheduler:负责集群资源调度,按照预定的调度策略将 Pod 调度到相应的 node 节点上
- ControllerManager:负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
- Etcd:负责存储集群中各种资源对象的信息
2. node:集群的数据平面,负责为容器提供运行环境
- kubelet:负责维护容器的生命周期,同时也负责 Volume (CVI) 和网络 (CNI) 的管理
- Container runtime:负责镜像管理以及 Pod 和容器的真正运行 (CRI)
- kube-proxy:负责为 Service 提供 cluster 内部的服务发现和负载均衡
生活类比:Kubernetes 集群就像一个餐厅。Master 节点是 "餐厅管理层":API Server 是 "前台接待",所有顾客的请求都先到这里;Scheduler 是 "排班经理",负责把客人安排到合适的桌子;Controller Manager 是 "运营经理",负责监督餐厅正常运转;Etcd 是 "数据库",记录所有订单和员工信息。Node 节点是 "服务员",每个服务员负责几张桌子(Pod),为客人提供服务。
企业级生产应用:
- 千万级并发场景:生产环境中 Master 节点必须高可用部署(至少 3 个节点),使用 etcd 集群存储数据。API Server 前面要加负载均衡器,Scheduler 和 Controller Manager 要开启 leader 选举。
- 进阶优化 :
- 使用 etcd 的 SSD 存储,提高读写性能
- 对 API Server 进行水平扩展
- 使用自定义调度器优化特定工作负载的调度
课后防宕机指南:
- 错误 1 :etcd 磁盘满了
- 报错 :
etcdserver: mvcc: database space exceeded - 排查思路 :
df -h检查 etcd 数据目录磁盘使用率;etcdctl endpoint status查看数据库大小;执行etcdctl compact压缩历史数据
- 报错 :
- 错误 2 :API Server 证书过期
- 报错 :
x509: certificate has expired or is not yet valid - 排查思路 :
kubeadm certs check-expiration检查证书有效期;kubeadm certs renew all更新所有证书
- 报错 :
1.4.2 K8S 各组件之间的调用关系
当我们要运行一个 web 服务时:
- kubernetes 环境启动之后,master 和 node 都会将自身的信息存储到 etcd 数据库中
- web 服务的安装请求会首先被发送到 master 节点的 apiServer 组件
- apiServer 组件会调用 scheduler 组件来决定到底应该把这个服务安装到哪个 node 节点上在此时,它会从 etcd 中读取各个 node 节点的信息,然后按照一定的算法进行选择,并将结果告知 apiServer
- apiServer 调用 controller-manager 去调度 Node 节点安装 web 服务
- kubelet 接收到指令后,会通知 docker,然后由 docker 来启动一个 web 服务的 pod
- 如果需要访问 web 服务,就需要通过 kube-proxy 来对 pod 产生访问的代理
核心解释:这是一个典型的 "声明式 API" 工作流程。你只需要告诉 Kubernetes"我想要什么"(运行一个 web 服务),而不是 "怎么做"。Kubernetes 会自动协调各个组件,最终达到你期望的状态。
坑(Gotchas):
- 很多新手会误以为 Kubernetes 是 "命令式" 的,直接去操作容器。这是错误的,你应该始终通过 API Server 操作资源对象。
- 不要手动修改 kubelet 管理的容器,Kubernetes 会自动把它恢复到期望状态。
1.4.3 K8S 的 常用名词概念
- Master:集群控制节点,每个集群需要至少一个 master 节点负责集群的管控
- Node:工作负载节点,由 master 分配容器到这些 node 工作节点上,然后 node 节点上的 kubelet 负责管理容器的生命周期
- Pod:kubernetes 的最小控制单元,容器都是运行在 pod 中的,一个 pod 中可以有 1 个或者多个容器
- Controller:控制器,通过它来实现对 pod 的管理,比如启动 pod、停止 pod、伸缩 pod 的数量等等
- Service:pod 对外服务的统一入口,下面可以维护着同一类的多个 pod
- Label:标签,用于对 pod 进行分类,同一类 pod 会拥有相同的标签
- NameSpace:命名空间,用来隔离 pod 的运行环境
核心解释:
- Pod 是 "豌豆荚",里面可以装多个 "豌豆"(容器)。这些容器共享网络和存储,就像同一个豌豆荚里的豌豆长在一起。
- Service 是 "负载均衡器",它给一组 Pod 提供一个固定的 IP 和端口,不管 Pod 怎么变化,Service 的地址不变。
- Namespace 是 "虚拟集群",可以把一个物理集群分成多个逻辑集群,不同团队使用不同的 Namespace,互不干扰。
1.4.4 k8S 的分层架构

Kubernetes分层架构
┌─────────────────────────────────────────────────┐
│ Ecosystem 生态系统 │
├─────────────────────────────────────────────────┤
│ Interface Layer 接口层 │
│ Client Libraries and Tools │
├─────────────────────────────────────────────────┤
│ Governance Layer 管理层 │
│ Automation and Policy Enforcement │
├─────────────────────────────────────────────────┤
│ Application Layer 应用层 │
│ Deployment and Routing │
├─────────────────────────────────────────────────┤
│ Nucleus 核心层 │
│ API and Execution │
├─────────────────────────────────────────────────┤
│ Container Runtime Network Plugin Volume Plugin │
│ Registry Image Provider Cloud Provider Identity │
└─────────────────────────────────────────────────┘
【图片位置 4:Kubernetes 分层架构图】
解释这个图:每层之间为轻耦合:层与层之间需求量不是很大。
- 核心层:Kubernetes 最核心的功能,对外提供 API 构建高层的应用,对内提供插件式应用执行环境
- 应用层:部署 (无状态应用、有状态应用、批处理任务、集群应用等) 和路由 (服务发现、DNS 解析等)
- 管理层:系统度量 (如基础设施、容器和网络的度量),自动化 (如自动扩展、动态 Provision 等) 以及策略管理 (RBAC、Quota、PSP、NetworkPolicy 等)
- 接口层:kubectl 命令行工具、客户端 SDK 以及集群联邦
- 生态系统 :在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴
- Kubernetes 外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS 应用、ChatOps 等
- Kubernetes 内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等
核心解释:Kubernetes 采用了 "微内核 + 插件" 的架构。核心只提供最基本的功能,所有其他功能都通过插件实现。这使得 Kubernetes 具有极强的扩展性,可以适应各种不同的场景。
二、K8S 集群环境搭建
2.1 k8s 中容器的管理方式
K8S 集群创建方式有 3 种:
- containerd:默认情况下,K8S 在创建集群时使用的方式
- docker:Docker 使用的普及率最高,虽然 K8S 在 1.24 版本后已经移除了 kubelet 对 docker 的支持,但可以借助 cri-docker 方式来实现集群创建
- cri-o:CRI-O 的方式是 Kubernetes 创建容器最直接的一种方式,在创建集群的时候,需要借助于 cri-o 插件的方式来实现 Kubernetes 集群的创建。
**[!NOTE]**docker 和 cri-o 这两种方式要对 kubelet 程序的启动参数进行设置
核心解释:CRI(Container Runtime Interface)是 Kubernetes 定义的容器运行时接口。任何实现了 CRI 接口的容器运行时都可以被 Kubernetes 使用。Docker 没有实现 CRI,所以需要一个中间层 cri-dockerd 来转换。
企业级生产应用:
- 千万级并发场景:生产环境推荐使用 containerd 作为容器运行时,它比 Docker 更轻量、更稳定、性能更好。
- 进阶优化 :
- 使用 containerd 的 snapshotter 功能加速镜像拉取
- 配置镜像缓存,减少重复拉取
- 使用 Nydus 或 OverlayBD 等加速镜像格式
2.2 k8s 集群部署
2.2.1 k8s 环境部署说明
K8S 中文官网:https://kubernetes.io/zh-cn/
| 主机名 | ip | 角色 |
|---|---|---|
| harbor.timinglee.org | 172.25.254.254 | harbor 仓库 |
| k8s-master.timinglee.org | 172.25.254.100 | master , k8s 集群控制节点 |
| k8s-node1.timinglee.org | 172.25.254.10 | worker , k8s 集群工作节点 |
| k8s-node2.timinglee.org | 172.25.254.20 | worker , k8s 集群工作节点 |
- 所有节点禁用 selinux 和防火墙
- 所有节点同步时间和解析
- 所有节点安装 docker-ce
- 所有节点禁用 swap, 注意注释掉 /etc/fstab 文件中的定义
坑(Gotchas):
- 必须禁用 swap!Kubernetes 不支持 swap,启用 swap 会导致 kubelet 无法启动。
- 所有节点的时间必须同步,否则会导致证书验证失败。
- 主机名必须能解析,否则会导致集群通信异常。
2.2.2 集群环境初始化
所有 k8s 集群节点执行以下步骤
2.2.2.1. 所有禁用 swap 和本地解析
bash
]# systemctl mask swap.target
]# swapoff -a
]# vim /etc/fstab
# /etc/fstab
# Created by anaconda on Sun Feb 19 17:38:40 2023
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
/dev/mapper/rhel-root / xfs defaults 0 0
UUID=ddb06c77-c9da-4e92-afd7-53cd76e6a94a /boot xfs defaults 0 0
#/dev/mapper/rhel-swap swap swap defaults 0 0
/dev/cdrom /media iso9660 defaults 0 0
[root@k8s-master ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.100 k8s-master.timinglee.org
172.25.254.10 k8s-node1.timinglee.org
172.25.254.20 k8s-node2.timinglee.org
172.25.254.254 reg.timinglee.org
核心代码逐行解析:
systemctl mask swap.target:底层动作 :将 swap.target 单元链接到 /dev/null,彻底禁用 swap 服务,防止系统自动启用 swap。作用:确保 swap 永远不会被启用。swapoff -a:底层动作 :立即关闭所有已启用的 swap 分区。作用:临时禁用 swap,配合上面的命令实现永久禁用。- 注释 /etc/fstab 中的 swap 行:底层动作 :防止系统在下次启动时自动挂载 swap 分区。作用:永久禁用 swap。
- 配置 /etc/hosts:底层动作 :添加主机名到 IP 的映射,使节点之间可以通过主机名互相访问。作用:解决集群内部的主机名解析问题。
坑(Gotchas):
- 只执行
swapoff -a是不够的,必须同时注释 /etc/fstab 中的 swap 行,否则重启后 swap 会自动启用。 - /etc/hosts 中的主机名必须和
hostname命令的输出完全一致,否则会导致 kubelet 无法正常工作。
课后防宕机指南:
- 错误:kubelet 启动失败,报错 "failed to run Kubelet: running with swap on is not supported"
- 排查思路 :执行
swapon -s检查是否有 swap 分区启用;检查 /etc/fstab 文件是否有 swap 挂载项;执行systemctl status swap.target检查 swap 服务状态。
2.2.2.2. 所有安装 docker
bash
[root@k8s-master ~]# vim /etc/yum.repos.d/docker.repo
[docker]
name=docker
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0
[root@k8s-master ~]# dnf install docker-ce -y
核心代码逐行解析:
- 创建 docker.repo 文件:底层动作 :添加 Docker 的 YUM 软件源,指向阿里云镜像站。作用:加速 Docker 的下载和安装。
dnf install docker-ce -y:底层动作 :从配置的软件源中下载并安装 Docker 社区版。作用:安装容器运行时环境。
坑(Gotchas):
- 不要使用系统自带的 docker 包,版本通常比较旧,可能与 Kubernetes 不兼容。
- 确保安装的是
docker-ce而不是docker,后者是旧版本的 Docker。
2.2.2.3. 所有节点设定 docker 的资源管理模式为 systemd
bash
[root@k8s-master ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://reg.timinglee.org"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
核心代码逐行解析:
"registry-mirrors": ["https://reg.timinglee.org"]:底层动作 :配置 Docker 镜像加速器,指向本地的 Harbor 仓库。作用:加速镜像拉取速度,减少公网带宽占用。"exec-opts": ["native.cgroupdriver=systemd"]:底层动作 :设置 Docker 使用 systemd 作为 cgroup 驱动。作用:与 kubelet 的 cgroup 驱动保持一致,避免资源管理冲突。"log-driver": "json-file":底层动作 :设置 Docker 使用 JSON 文件作为日志驱动。作用:标准的日志格式,便于日志收集和分析。"max-size": "100m":底层动作 :限制每个容器的日志文件大小为 100MB。作用:防止日志文件无限增长,占满磁盘空间。"storage-driver": "overlay2":底层动作 :设置 Docker 使用 overlay2 作为存储驱动。作用:目前性能最好、最稳定的存储驱动。
坑(Gotchas):
- 最容易踩的坑:cgroup 驱动不一致!kubelet 默认使用 systemd 作为 cgroup 驱动,如果 Docker 使用 cgroupfs,会导致资源管理混乱,容器无法正常启动。
- 日志大小限制非常重要,生产环境中经常出现日志占满磁盘的情况。
企业级生产应用:
- 千万级并发场景:生产环境中必须配置日志轮转,并且使用集中式日志系统(如 ELK)收集日志。
- 进阶优化 :
- 使用 journald 作为日志驱动,性能更好
- 配置 Docker 的资源限制,防止单个容器占用过多资源
- 使用分布式镜像仓库,提高镜像拉取速度
2.2.2.4. 所有节点复制 harbor 仓库中的证书并启动 docker
bash
[root@k8s-master ~]# ls -l /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@k8s-master ~]# systemctl enable --now docker
# 登陆harbor仓库
[root@k8s-master ~]# docker login reg.timinglee.org
[root@k8s-master ~]# docker info
Client: Docker Engine - Community
Version: 27.1.2
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.16.2
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.29.1
Path: /usr/libexec/docker/cli-plugins/docker-compose
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 27.1.2
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: systemd # 资源管理更改为systemd
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 8fc6bcff51318944179630522a095cc9dbf9f353
runc version: v1.1.13-0-g58aa920
init version: de40ad0
Security Options:
seccomp
Profile: builtin
cgroupns
Kernel Version: 5.14.0-427.13.1.el9_4.x86_64
Operating System: Red Hat Enterprise Linux 9.4 (Plow)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 736.3MiB
Name: k8s-master.timinglee.org
ID: f3c291bf-287d-4cf6-8e69-5f21c79fa7c6
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://reg.westos.org/ # 认证harbor仓库
Live Restore Enabled: false
核心代码逐行解析:
- 复制 ca.crt 到 /etc/docker/certs.d/reg.timinglee.org/:底层动作 :将 Harbor 仓库的 CA 证书添加到 Docker 的信任证书列表中。作用:使 Docker 信任自签名的 Harbor 仓库,可以安全地拉取和推送镜像。
systemctl enable --now docker:底层动作 :设置 Docker 服务开机自启,并立即启动 Docker 服务。作用:确保 Docker 在系统启动时自动运行。docker login reg.timinglee.org:底层动作 :使用用户名和密码登录 Harbor 仓库。作用:获得推送和拉取私有镜像的权限。docker info:底层动作 :显示 Docker 的详细信息,包括版本、存储驱动、cgroup 驱动等。作用:验证 Docker 是否正确安装和配置。
坑(Gotchas):
- 证书目录的名称必须和仓库地址完全一致,包括端口号。如果仓库使用非标准端口,目录名应该是
reg.timinglee.org:443。 - 证书文件必须命名为
ca.crt,不能是其他名称。
2.2.2.5 安装 K8S 部署工具
bash
# 部署软件仓库,添加K8S源
[root@k8s-master ~]# vim /etc/yum.repos.d/k8s.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm
gpgcheck=0
# 安装软件
[root@k8s-master ~]# dnf install kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 -y
核心代码逐行解析:
- 创建 k8s.repo 文件:底层动作 :添加 Kubernetes 的 YUM 软件源,指向阿里云镜像站。作用:加速 Kubernetes 组件的下载和安装。
dnf install kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 -y:底层动作 :安装指定版本的 kubelet、kubeadm 和 kubectl。作用:安装 Kubernetes 的核心组件。
坑(Gotchas):
- 所有节点的 Kubernetes 版本必须完全一致,否则会导致集群不稳定。
- 不要安装最新版本,建议使用比最新版本晚 1-2 个版本的稳定版。
2.2.2.6 设置 kubectl 命令补齐功能
bash
[root@k8s-master ~]# dnf install bash-completion -y
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@k8s-master ~]# source ~/.bashrc
核心代码逐行解析:
dnf install bash-completion -y:底层动作 :安装 bash 自动补全工具。作用:为 kubectl 提供命令自动补全功能。echo "source <(kubectl completion bash)" >> ~/.bashrc:底层动作 :将 kubectl 的自动补全脚本添加到 bash 的配置文件中。作用:使自动补全功能在每次登录时自动生效。source ~/.bashrc:底层动作 :重新加载 bash 配置文件。作用:使自动补全功能立即生效,无需重新登录。
2.2.2.7 在所有节点安装 cri-docker
k8s 从 1.24 版本开始移除了 dockershim,所以需要安装 cri-docker 插件才能使用 docker。
软件下载:https://github.com/Mirantis/cri-dockerd
bash
[root@k8s-master ~]# dnf install libcgroup-0.41-19.el8.x86_64.rpm \
> cri-dockerd-0.3.14-3.el8.x86_64.rpm -y
[root@k8s-master ~]# vim /lib/systemd/system/cri-docker.service
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket
[Service]
Type=notify
# 指定网络插件名称及基础容器镜像
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.9
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
[root@k8s-master ~]# systemctl daemon-reload
[root@k8s-master ~]# systemctl start cri-docker
[root@k8s-master ~]# ll /var/run/cri-dockerd.sock
srw-rw---- 1 root docker 0 8月 26 22:14 /var/run/cri-dockerd.sock # cri-dockerd的套接字文件
核心代码逐行解析:
- 安装 libcgroup 和 cri-dockerd:底层动作 :安装 cri-dockerd 及其依赖包。作用:提供 CRI 接口,使 Kubernetes 可以使用 Docker 作为容器运行时。
- 修改 cri-docker.service 文件:底层动作 :配置 cri-dockerd 的启动参数。作用 :
--container-runtime-endpoint fd://:指定容器运行时端点--network-plugin=cni:使用 CNI 网络插件--pod-infra-container-image=reg.timinglee.org/k8s/pause:3.9:指定 Pod 基础容器镜像
systemctl daemon-reload:底层动作 :重新加载 systemd 配置。作用:使修改后的服务文件生效。systemctl start cri-docker:底层动作 :启动 cri-docker 服务。作用:启动 CRI 接口服务。ll /var/run/cri-dockerd.sock:底层动作 :检查 cri-dockerd 的 Unix 套接字文件是否存在。作用:验证 cri-docker 是否正常启动。
坑(Gotchas):
- 最容易踩的坑 :忘记指定
--pod-infra-container-image参数,或者指定的镜像无法访问。这会导致 Pod 无法启动,一直处于 Pending 状态。 - cri-docker 的版本必须与 Kubernetes 的版本兼容,否则会出现兼容性问题。
企业级生产应用:
- 千万级并发场景:生产环境中建议使用 containerd 而不是 cri-dockerd,因为 containerd 性能更好,资源占用更低。
- 进阶优化 :
- 配置 cri-dockerd 的日志轮转
- 调整 cri-dockerd 的资源限制
- 使用 Unix 套接字而不是 TCP 套接字,提高性能
2.2.2.8 在 master 节点拉取 K8S 所需镜像
bash
# 拉取k8s集群所需要的镜像
[root@k8s-master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock
# 上传镜像到harbor仓库
[root@k8s-master ~]# docker images | awk '/google/{ print $1":"$2}' \
| awk -F "/" '{system("docker tag "$0" reg.timinglee.org/k8s/"$3)}'
[root@k8s-master ~]# docker images | awk '/k8s/{system("docker push "$1":"$2)}'
核心代码逐行解析:
kubeadm config images pull:底层动作 :拉取 Kubernetes 集群所需的所有镜像。作用 :提前拉取镜像,加快集群初始化速度。--image-repository registry.aliyuncs.com/google_containers:指定镜像仓库为阿里云镜像站--kubernetes-version v1.30.0:指定 Kubernetes 版本--cri-socket=unix:///var/run/cri-dockerd.sock:指定 CRI 套接字
- 第一个 awk 命令:底层动作 :将从阿里云拉取的镜像重新打标签,指向本地 Harbor 仓库。作用:将镜像上传到本地仓库,供所有节点使用。
- 第二个 awk 命令:底层动作 :将打了标签的镜像推送到本地 Harbor 仓库。作用:使所有节点都可以从本地仓库拉取镜像,提高速度。
坑(Gotchas):
- 必须指定正确的
--cri-socket参数,否则 kubeadm 无法与容器运行时通信。 - 确保 Harbor 仓库有足够的存储空间来存储这些镜像。
2.2.2.9 集群初始化
bash
# 启动kubelet服务
[root@k8s-master ~]# systemctl status kubelet.service
# 执行初始化命令
[root@k8s-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.timinglee.org/k8s \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock
# 指定集群配置文件变量
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
[root@k8s-master ~]# source ~/.bash_profile
# 当前节点没有就绪,因为还没有安装网络插件,容器没有运行
[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master.timinglee.org NotReady control-plane 4m25s v1.30.0
[root@k8s-master ~]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-647dc95897-2sgn8 0/1 Pending 0 6m13s
kube-system coredns-647dc95897-bvtxb 0/1 Pending 0 6m13s
kube-system etcd-k8s-master.timinglee.org 1/1 Running 0 6m29s
kube-system kube-apiserver-k8s-master.timinglee.org 1/1 Running 0 6m30s
kube-system kube-controller-manager-k8s-master.timinglee.org 1/1 Running 0 6m29s
kube-system kube-proxy-fq85m 1/1 Running 0 6m14s
kube-system kube-scheduler-k8s-master.timinglee.org 1/1 Running 0 6m29s
**[!NOTE]**在此阶段如果生成的集群 token 找不到了可以重新生成
bash
运行
[root@k8s-master ~]# kubeadm token create --print-join-command kubeadm join 172.25.254.100:6443 --token 5hwptm.zwn7epa6pvatbpwf --discovery-token-ca-cert-hash sha256:52f1a83b70ffc8744db5570288ab51987ef2b563bf906ba4244a300f61e9db23
核心代码逐行解析:
kubeadm init:底层动作 :初始化 Kubernetes 集群。作用 :--pod-network-cidr=10.244.0.0/16:指定 Pod 网络的 CIDR 地址段,必须与后续安装的网络插件一致--image-repository reg.timinglee.org/k8s:指定镜像仓库为本地 Harbor 仓库--kubernetes-version v1.30.0:指定 Kubernetes 版本--cri-socket=unix:///var/run/cri-dockerd.sock:指定 CRI 套接字
- 设置 KUBECONFIG 环境变量:底层动作 :告诉 kubectl 集群配置文件的位置。作用:使 kubectl 可以与集群通信。
kubectl get node:底层动作 :获取集群节点信息。作用:查看节点状态。kubectl get pod -A:底层动作 :获取所有命名空间的 Pod 信息。作用:查看集群组件的运行状态。
坑(Gotchas):
- 最容易踩的坑 :
--pod-network-cidr参数必须与网络插件的配置一致。如果使用 Flannel,必须是10.244.0.0/16;如果使用 Calico,默认是192.168.0.0/16。 - 初始化完成后,必须立即保存
kubeadm join命令,否则需要重新生成 token。
企业级生产应用:
- 千万级并发场景:生产环境中必须使用高可用的 Master 节点,至少 3 个 Master 节点。
- 进阶优化 :
- 使用 kubeadm 配置文件进行集群初始化,而不是命令行参数
- 配置 etcd 的备份策略
- 启用审计日志
课后防宕机指南:
- 错误:coredns Pod 一直处于 Pending 状态
- 排查思路:这是正常现象,因为还没有安装网络插件。安装网络插件后,coredns 会自动变为 Running 状态。
2.2.2.10 安装 flannel 网络插件
官方网站:https://github.com/flannel-io/flannel
bash
# 下载flannel的yaml部署文件
[root@k8s-master ~]# wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
# 下载镜像:
[root@k8s-master ~]# docker pull docker.io/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker pull docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel1
# 上传镜像到仓库
[root@k8s-master ~]# docker tag flannel/flannel:v0.25.5 reg.timinglee.org/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker push reg.timinglee.org/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker tag flannel/flannel-cni-plugin:v1.5.1-flannel1 reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
[root@k8s-master ~]# docker push reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
# 编辑kube-flannel.yml 修改镜像下载位置
[root@k8s-master ~]# vim kube-flannel.yml
# 需要修改以下几行
[root@k8s-master ~]# grep -n image kube-flannel.yml
146 : image: reg.timinglee.org/flannel/flannel:v0.25.5
173 : image: reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
184 : image: reg.timinglee.org/flannel/flannel:v0.25.5
# 安装flannel网络插件
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml
核心代码逐行解析:
- 下载 kube-flannel.yml:底层动作 :下载 Flannel 网络插件的部署文件。作用:定义了 Flannel 的所有资源对象。
- 拉取并上传 Flannel 镜像:底层动作 :将 Flannel 镜像上传到本地 Harbor 仓库。作用:使所有节点都可以从本地仓库拉取镜像。
- 修改 kube-flannel.yml 中的镜像地址:底层动作 :将镜像地址改为本地 Harbor 仓库的地址。作用:避免从公网拉取镜像,提高速度。
kubectl apply -f kube-flannel.yml:底层动作 :在集群中创建 Flannel 的所有资源对象。作用:安装 Flannel 网络插件,实现 Pod 之间的网络通信。
坑(Gotchas):
- Flannel 的版本必须与 Kubernetes 的版本兼容,否则会出现网络问题。
- 确保所有节点都可以访问 Flannel 镜像,否则 Flannel Pod 无法启动。
企业级生产应用:
- 千万级并发场景:生产环境中建议使用 Calico 而不是 Flannel,因为 Calico 提供了更好的网络性能和网络策略支持。
- 进阶优化 :
- 使用 VXLAN 或 IPIP 模式,根据网络环境选择合适的模式
- 配置 Flannel 的 MTU,提高网络性能
- 启用网络策略,限制 Pod 之间的通信
2.2.2.11 节点扩容
在所有的 worker 节点中:
- 确认部署好以下内容
- 禁用 swap
- 安装:
- kubelet-1.30.0
- kubeadm-1.30.0
- kubectl-1.30.0
- docker-ce
- cri-dockerd
- 修改 cri-dockerd 启动文件添加
- --network-plugin=cni
- --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.9
- 启动服务
- kubelet.service
- cri-docker.service
以上信息确认完毕后即可加入集群:
bash
[root@k8s-node1 & 2 ~]# kubeadm join 172.25.254.100:6443 --token 5hwptm.zwn7epa6pvatbpwf --discovery-token-ca-cert-hash sha256:52f1a83b70ffc8744db5570288ab51987ef2b563bf906ba4244a300f61e9db23 --cri-socket=unix:///var/run/cri-dockerd.sock
在 master 节点中查看所有 node 的状态:
bash
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master.timinglee.org Ready control-plane 98m v1.30.0
k8s-node1.timinglee.org Ready <none> 21m v1.30.0
k8s-node2.timinglee.org Ready <none> 21m v1.30.0
**[!NOTE]**所有节点的 STATUS 为 Ready 状态,那么恭喜你,你的 kubernetes 就装好了!!
测试集群运行情况:
bash
# 建立一个pod
[root@k8s-master ~]# kubectl run test --image nginx
# 查看pod状态
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test 1/1 Running 0 6m29s
# 删除pod
[root@k8s-master ~]# kubectl delete pod test
核心解释:
kubeadm join命令将 worker 节点加入到集群中。- 当所有节点的状态都变为 Ready 时,说明集群已经正常运行。
- 运行一个测试 Pod 可以验证集群的基本功能是否正常。
一、系统环境设定
1. 加载模块 (所有节点)
bash
[root@master ~]# cat > /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
[root@master ~]# modprobe -a overlay
[root@master ~]# modprobe -a br_netfilter
[root@master ~]# lsmod | grep -E "overlay|br_netfilter"
br_netfilter 36864 0
bridge 417792 1 br_netfilter
overlay 229376 0
核心代码逐行解析:
- 创建 /etc/modules-load.d/k8s.conf:底层动作 :配置系统在启动时自动加载 overlay 和 br_netfilter 内核模块。作用:这两个模块是 Kubernetes 网络和存储所必需的。
modprobe -a overlay br_netfilter:底层动作 :立即加载这两个内核模块。作用:使模块立即生效,无需重启系统。lsmod | grep -E "overlay|br_netfilter":底层动作 :检查模块是否成功加载。作用:验证模块加载是否成功。
坑(Gotchas):
- 如果内核版本过低,可能没有这两个模块,需要升级内核。
- 确保模块在系统重启后仍然自动加载。
2. 调整内核功能参数 (所有节点)
bash
[root@master ~]# cat > /etc/sysctl.d/k8s.conf <<EOF
vm.swappiness=0
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
EOF
[root@master ~]# sysctl -p /etc/sysctl.d/k8s.conf
vm.swappiness = 0
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
核心代码逐行解析:
vm.swappiness=0:底层动作 :设置系统不使用 swap 分区。作用:确保 Kubernetes 不会使用 swap。net.ipv4.ip_forward=1:底层动作 :启用 IP 转发功能。作用:使 Pod 可以访问外部网络。net.bridge.bridge-nf-call-ip6tables=1和net.bridge.bridge-nf-call-iptables=1:底层动作 :使桥接流量经过 iptables 和 ip6tables 的过滤。作用:使 Kubernetes 的网络策略生效。sysctl -p:底层动作 :使内核参数立即生效。作用:无需重启系统即可应用新的参数。
坑(Gotchas):
- 这些内核参数是 Kubernetes 正常运行的必要条件,缺少任何一个都会导致集群异常。
- 确保这些参数在系统重启后仍然生效。
3. 禁用 swap (所有节点)
bash
[root@master ~]# sed '/swap/s/^/#/g' -i /etc/fstab
[root@master ~]# systemctl disable --now swap.target
[root@master ~]# systemctl mask swap.target
核心代码逐行解析:
sed '/swap/s/^/#/g' -i /etc/fstab:底层动作 :注释掉 /etc/fstab 文件中的所有 swap 挂载项。作用:防止系统在启动时自动挂载 swap 分区。systemctl disable --now swap.target:底层动作 :禁用 swap 服务并立即停止它。作用:临时禁用 swap。systemctl mask swap.target:底层动作 :将 swap.target 链接到 /dev/null。作用:彻底禁用 swap,防止任何程序启用它。
4. 部署软件仓库 (所有节点)
bash
[root@master ~]# cat > /etc/yum.repos.d/k8s.repo <<EOF
[docker-ce]
name = docker-ce
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0
EOF
[root@master ~]# dnf search kubeadm
[root@master ~]# dnf search containerd
核心代码逐行解析:
- 创建 k8s.repo 文件:底层动作 :添加 Docker 和 Kubernetes 的 YUM 软件源。作用:加速软件的下载和安装。
dnf search kubeadm和dnf search containerd:底层动作 :搜索软件包。作用:验证软件源是否配置正确。
5. 安装 kubernetes 所需软件
master 节点
bash
[root@master ~]# dnf install containerd.io kubeadm-1.35.0 kubelet-1.35.0 kubectl-1.35.0 -y
# 生成containerd配置文件
[root@master ~]# containerd config default > /etc/containerd/config.toml
[root@master ~]# vim /etc/containerd/config.toml
SystemdCgroup = true
sandbox = 'registry.aliyuncs.com/google_containers/pause:3.10.1'
# 生成crictl配置文件
[root@master ~]# cat > /etc/crictl.yaml <<EOF
> runtime-endpoint: unix:///run/containerd/containerd.sock
> image-endpoint: unix:///run/containerd/containerd.sock
> timeout: 10
> debug: false
> EOF
测试:
bash
[root@master ~]# crictl images
IMAGE TAG IMAGE ID SIZE
work 节点
配置镜像加速:
bash
[root@master ~]# vim /etc/containerd/config.toml
[plugins.'io.containerd.cri.v1.images'.registry]
config_path = '/etc/containerd/certs.d'
[root@master ~]# mkdir -p /etc/containerd/certs.d/
[root@master ~]# mkdir -p /etc/containerd/certs.d/docker.io/
[root@master ~]# cat > /etc/containerd/certs.d/docker.io/hosts.toml <<EOF
server = 'https://docker.io'
[host."https://docker.1ms.run"]
capabilities = ['pull', 'resolve']
EOF
[root@master ~]# systemctl restart containerd.service
设置命令补全:
bash
[root@master ~]# source <(crictl completion bash)
[root@master ~]# echo "source <(crictl completion bash)" >> .bash_profile
下载镜像测试:
bash
[root@master ~]# crictl pull busybox
[root@master ~]# crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/library/busybox latest af3f0f48a24ed 2.22MB
实验实操集合
一、构建 harbor 镜像仓库
1. 安装 docker
bash
[root@harbor ~]# cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name = docker
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
EOF
[root@harbor ~]# dnf install docker-ce-3:28.5.2-1.el9 -y
[root@harbor ~]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
[root@harbor ~]# modprobe -a br_netfilter
[root@harbor ~]# vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
[root@harbor ~]# sysctl --system
[root@harbor ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true
[root@harbor ~]# systemctl daemon-reload
[root@harbor ~]# systemctl enable --now docker
2. 生成 key
bash
[root@harbor ~]# mkdir /data/certs -p
[root@harbor ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout /data/certs/timinglee.org.key \
-addext "subjectAltName = DNS:reg.timinglee.org" \
-x509 -days 365 -out /data/certs/timinglee.org.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shannxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:kubernetes
Organizational Unit Name (eg, section) []:harbor
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org
3. 编辑 harbor 配置文件
bash
[root@harbor ~]# tar zxf harbor-offline-installer-v2.5.4.tgz -C /opt/
[root@harbor ~]# cd /opt/harbor/
[root@harbor harbor]# ls
common.sh harbor.v2.5.4.tar.gz harbor.yml.tmpl install.sh LICENSE prepare
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml
[root@harbor harbor]# vim harbor.yml
hostname: reg.timinglee.org
certificate: /data/certs/timinglee.org.crt
private_key: /data/certs/timinglee.org.key
harbor_admin_password: lee
[root@harbor harbor]# ./install.sh --with-chartmuseum
4. 启动并验证
bash
[root@harbor harbor]# mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
[root@harbor harbor]# cp /data/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@harbor harbor]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.200 harbor reg.timinglee.org
[root@harbor harbor]# systemctl restart docker
[root@harbor harbor]# docker compose up -d
[root@harbor harbor]# docker login reg.timinglee.org -u admin
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
二、构建部署 kubernetes 所需主机
| 主机名 | ip | 配置 | 角色 |
|---|---|---|---|
| harbor.timinglee.org | 172.25.254.254 | cpu1 、 mem 1G | harbor 仓库 |
| master-node | 172.25.254.100 | cpu4 、 mem>4G | master , k8s 集群控制节点 |
| node1 | 172.25.254.10 | cpu2 、 mem 2G | worker , k8s 集群工作节点 |
| node2 | 172.25.254.20 | cpu2 、 mem 2G | worker , k8s 集群工作节点 |
1. 所有主机配置
关闭 swap:
bash
systemctl disable --now swap.target
systemctl mask swap.target
sed '/swap/s/^/#/g' -i /etc/fstab
安装 docker:
bash
# 配置可以使用harbor仓库
mkdir /etc/docker/certs.d/reg.timinglee.org/ -p
# 在harbor主机中分发证书到所有主机
[root@harbor ~]# for i in 100 10 20
> do
> scp /data/certs/timinglee.org.crt root@172.25.254.$i:/etc/docker/certs.d/reg.timinglee.org/ca.crt
> done
systemctl enable docker
systemctl restart docker
所有主机配置 docker 加速器:
bash
cat >/etc/docker/daemon.json <<EOF
{
"registry-mirrors":["https://reg.timinglee.org"]
}
EOF
systemctl restart docker
docker info
# 可以看到
Registry Mirrors:
https://reg.timinglee.org/
所有主机彼此建立解析:
bash
vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.100 master
172.25.254.10 node1
172.25.254.20 node2
172.25.254.200 reg.timinglee.org
所有主机配置 kubernetes 安装源:
bash
vim /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0
# 检测
dnf list kubelet
以上操作完成后重启主机检测 swap 分区:
bash
swapon -s
# 没有任何输出表示ok
三、kubernetes 的部署
1. 安装 cri-dockerd (所有主机中安装)
bash
[root@master ~]# ls
anaconda-ks.cfg cri-dockerd-0.3.14-3.el8.x86_64.rpm libcgroup-0.41-19.el8.x86_64.rpm
[root@master ~]# rpm -ivh *.rpm
警告: libcgroup-0.41-19.el8.x86_64.rpm: 头V4 RSA/SHA256 Signature, 密钥 ID 6d745a60: NOKEY
Verifying... ################################# [100%]
准备中... ################################# [100%]
正在升级/安装...
1:libcgroup-0.41-19.el8 ################################# [ 50%]
2:cri-dockerd-3:0.3.14-3.el8 ################################# [100%]
vim /lib/systemd/system/cri-docker.service
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.10.1
ll /var/run/cri-dockerd.sock
2. 安装构建 kubernetes 集群所需软件
master 节点:
bash
dnf install kubelet kubeadm kubectl -y
systemctl enable --now kubelet.service
node 节点:
bash
dnf install kubelet kubeadm -y
systemctl enable --now kubelet.service
master 节点中 kubectl 和 kubeadm 补齐:
bash
[root@master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@master ~]# echo "source <(kubeadm completion bash)" >> ~/.bashrc
[root@master ~]# source ~/.bashrc
3. 下载 kubernetes 集群所需镜像
下载镜像:
bash
[root@master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.35.3 \
--cri-socket=unix:///var/run/cri-dockerd.sock
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.35.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-controller-manager:v1.35.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-scheduler:v1.35.3
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-proxy:v1.35.3
[config/images] Pulled registry.aliyuncs.com/google_containers/coredns:v1.13.1
[config/images] Pulled registry.aliyuncs.com/google_containers/pause:3.10.1
[config/images] Pulled registry.aliyuncs.com/google_containers/etcd:3.6.6-0
上传镜像到本地 harbor:
bash
[root@master ~]# docker login reg.timinglee.org -u admin
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/google/{system("docker tag "$0" reg.timinglee.org/k8s/"$3)}'
[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/timinglee/{system("docker push "$0)}'
4. 在 master 中初始化 kubernetes 集群
在 master 中完成集群初始化:
bash
[root@master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.timinglee.org/k8s \
--kubernetes-version v1.35.3 \
--cri-socket=unix:///var/run/cri-dockerd.sock
# 每个人不一样,其他主机加入本集群的凭证
kubeadm join 172.25.254.100:6443 --token tdwjoc.8d1yw3wl4r4tm6c4 \
--discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927
# 如果忘记
[root@master ~]# kubeadm token create --print-join-command
kubeadm join 172.25.254.100:6443 --token jl4ztx.cax3iysvu7onsh5s --discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927
# 如果初始化出问题
[root@master ~]# kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock # 可以重置集群设定
添加 kubernets 环境变量到本机:
bash
[root@master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" > ~/.bash_profile
[root@master ~]# source ~/.bash_profile
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady control-plane 102s v1.35.3
添加 node 节点到本集群:
bash
[root@node1 ~]# kubeadm join 172.25.254.100:6443 --token jl4ztx.cax3iysvu7onsh5s --discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927 --cri-socket=unix:///var/run/cri-dockerd.sock
测试:
bash
[root@master ~]# kubectl get nodes # 可以看到集群中主机但是因为网络插件问题状态是NotReady
NAME STATUS ROLES AGE VERSION
master NotReady control-plane 5m16s v1.35.3
node1 NotReady <none> 66s v1.35.3
node2 NotReady <none> 58s v1.35.3
5. 安装网络插件
bash
[root@master ~]# ls
anaconda-ks.cfg cri-dockerd-0.3.14-3.el8.x86_64.rpm flannel-0.28.1.tar libcgroup-0.41-19.el8.x86_64.rpm kube-flannel.yml
[root@master ~]# docker load -i flannel-0.28.1.tar
[root@master ~]# docker tag ghcr.io/flannel-io/flannel-cni-plugin:v1.9.0-flannel1 reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
[root@master ~]# docker push reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
The push refers to repository [reg.timinglee.org/flannel-io/flannel-cni-plugin]
2c8aa52d4746: Pushed
5aa68bbbc67e: Pushed
v1.9.0-flannel1: digest: sha256:b3d30c221113b30fea3e8a7fccb145e929b097d0319b9eeb6b5a591b10b5c671 size: 739
[root@master ~]# docker tag ghcr.io/flannel-io/flannel:v0.28.1 reg.timinglee.org/flannel-io/flannel:v0.28.1
[root@master ~]# docker push reg.timinglee.org/flannel-io/flannel:v0.28.1
The push refers to repository [reg.timinglee.org/flannel-io/flannel]
5668da16a30b: Pushed
5f70bf18a086: Pushed
00012e17b6cc: Pushed
9738bb9596cf: Pushed
b6233bc105d7: Pushed
03767449b95b: Pushed
9a7d8cf9ff51: Pushed
13a60c10faeb: Pushed
70dc5e033175: Pushed
256f393e029f: Pushed
v0.28.1: digest: sha256:e671adbc267460164555159210066d3304a43e3b5dd85cc0b5b6ad62e83aab52 size: 2414
[root@master ~]# vim kube-flannel.yml
image: flannel-io/flannel:v0.28.1
image: flannel-io/flannel-cni-plugin:v1.9.0-flannel1
image: flannel-io/flannel:v0.28.1
[root@master ~]# kubectl apply -f kube-flannel.yml
namespace/kube-flannel created
serviceaccount/flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
测试:
bash
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready control-plane 13m v1.35.3
node1 Ready <none> 9m44s v1.35.3
node2 Ready <none> 9m36s v1.35.3