01| 裸机部署 K8S:从零搭建生产可用集群

目录

[一、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 集群在支撑。
  • 进阶优化
    1. 使用 Kubernetes 集群联邦(Federation)管理跨地域集群
    2. 采用虚拟节点(Virtual Kubelet)实现弹性扩容到公有云
    3. 使用 KEDA(Kubernetes Event-Driven Autoscaling)实现基于事件的自动伸缩

3 Kubernetes 简介

kubernetes

  • 名字由来:中间有 8 个字母,所以简称 K8S
  1. 在 Docker 作为高级容器引擎快速发展的同时,在 Google 内部,容器技术已经应用了很多年。Borg 系统运行管理着成千上万的容器应用。
  2. Kubernetes 项目来源于 Borg,可以说是集结了 Borg 设计思想的精华,并且吸收了 Borg 系统中的经验和教训。
  3. 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 选举。
  • 进阶优化
    1. 使用 etcd 的 SSD 存储,提高读写性能
    2. 对 API Server 进行水平扩展
    3. 使用自定义调度器优化特定工作负载的调度

课后防宕机指南

  • 错误 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 服务时:

  1. kubernetes 环境启动之后,master 和 node 都会将自身的信息存储到 etcd 数据库中
  2. web 服务的安装请求会首先被发送到 master 节点的 apiServer 组件
  3. apiServer 组件会调用 scheduler 组件来决定到底应该把这个服务安装到哪个 node 节点上在此时,它会从 etcd 中读取各个 node 节点的信息,然后按照一定的算法进行选择,并将结果告知 apiServer
  4. apiServer 调用 controller-manager 去调度 Node 节点安装 web 服务
  5. kubelet 接收到指令后,会通知 docker,然后由 docker 来启动一个 web 服务的 pod
  6. 如果需要访问 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 更轻量、更稳定、性能更好。
  • 进阶优化
    1. 使用 containerd 的 snapshotter 功能加速镜像拉取
    2. 配置镜像缓存,减少重复拉取
    3. 使用 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)收集日志。
  • 进阶优化
    1. 使用 journald 作为日志驱动,性能更好
    2. 配置 Docker 的资源限制,防止单个容器占用过多资源
    3. 使用分布式镜像仓库,提高镜像拉取速度
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 性能更好,资源占用更低。
  • 进阶优化
    1. 配置 cri-dockerd 的日志轮转
    2. 调整 cri-dockerd 的资源限制
    3. 使用 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 节点。
  • 进阶优化
    1. 使用 kubeadm 配置文件进行集群初始化,而不是命令行参数
    2. 配置 etcd 的备份策略
    3. 启用审计日志

课后防宕机指南

  • 错误: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 提供了更好的网络性能和网络策略支持。
  • 进阶优化
    1. 使用 VXLAN 或 IPIP 模式,根据网络环境选择合适的模式
    2. 配置 Flannel 的 MTU,提高网络性能
    3. 启用网络策略,限制 Pod 之间的通信
2.2.2.11 节点扩容

在所有的 worker 节点中:

  1. 确认部署好以下内容
  2. 禁用 swap
  3. 安装:
    • kubelet-1.30.0
    • kubeadm-1.30.0
    • kubectl-1.30.0
    • docker-ce
    • cri-dockerd
  4. 修改 cri-dockerd 启动文件添加
  5. 启动服务
    • 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=1net.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 kubeadmdnf 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

相关推荐
LuminousCPP1 小时前
数据结构-线性表第一篇
数据结构·经验分享·笔记·顺序表
jran-1 小时前
Docker 容器化技术&docker安装
运维·docker·容器
呉師傅1 小时前
将CD音频抓轨转换成MP3的两种方法【图文解释】
运维·服务器·网络·windows·电脑·音视频
拾光Ծ1 小时前
【Linux系统】线程(上)
java·linux·运维·jvm·线程·c/c++
金玉满堂@bj1 小时前
pytest+uiautomation+allure 数据驱动桌面自动化项目搭建指南-yaml版本
运维·自动化·pytest
Elastic 中国社区官方博客1 小时前
通过项目标签和路由,在 Elasticsearch Serverless 中实现更快的跨项目搜索
大数据·elasticsearch·搜索引擎·云原生·serverless·全文检索
晓蓝WQuiet2 小时前
《鸟哥的Linux私房菜》笔记 第七至十六章
linux·运维·笔记
山岚的运维笔记2 小时前
Bash 专业人员笔记 -- 第 11 章:`true`、`false` 和 `:` 命令
linux·运维·服务器·开发语言·笔记·学习·bash
ccyl012 小时前
UOS server 版(摩尔X300显卡)服务器安装显卡驱动
运维·服务器