一、Kubernetes 简介及部署方法
(一)基础知识
1.应用部署方式演变
在部署应用程序的方式上,主要经历了三个阶段:
| 阶段 | 描述 | 优点 | 缺点 |
| 传统部署 | 直接部署在物理机上 | 简单,不需要其它技术的参与 | 不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响 |
| 虚拟化部署 | 在物理机上运行多个独立虚拟机 | 程序环境不会相互产生影响,提供了一定程度的安全性 | 增加了操作系统,浪费了部分资源 |
| 容器化部署 | 共享操作系统,轻量隔离 | 高效、快速启动 | 需解决故障恢复、弹性伸缩等问题 |
2.容器编排工具应用
为应对容器化带来的管理挑战,主流编排工具包括:
Swarm:Docker 原生编排工具
Mesos:Apache 资源管控组合
Kubernetes:Google 开源,成为事实标准
3.kubernetes 简介
(1)Borg 奠定基础
Kubernetes 脱胎于 Google 内部运行多年的 Borg 系统,后者已在数以万计的容器应用管理中验证了大规模调度、资源隔离和自动恢复等能力。
(2)继承与革新
但 Borg 作为内部系统,存在配置复杂、扩展性差、绑定内部基础设施等缺陷。Kubernetes 并非简单复制 Borg,而是在其设计思想基础上进行了现代化重构——采用声明式 API、插件化架构(CRI/CNI/CSI),并将管理粒度从容器提升到 Pod。
(3)核心创新
Pod 作为最小部署单元,允许将多个容器组合为一个逻辑整体(如 Sidecar 模式),使 Kubernetes 管理的对象从零散容器升维为完整应用服务。
(4)核心理念
用户只需声明期望状态(副本数、资源、访问方式等),Kubernetes 自动完成调度、部署、自愈、滚动更新和弹性伸缩。将底层复杂性屏蔽于平台之内,将简洁体验留给用户,这正是 Kubernetes 成为云原生时代基础设施标准的核心原因。
(5)功能特点
| 功能 | 作用 |
| 自我修复 | 一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器 |
| 弹性伸缩 | 可以根据需要,自动对集群中正在运行的容器数量进行调整 |
| 服务发现 | 服务可以通过自动发现的形式找到它所依赖的服务 |
| 负载均衡 | 如果一个服务起动了多个容器,能够自动实现请求的负载均衡 |
| 版本回退 | 如果发现新发布的程序版本有问题,可以立即回退到原来的版本 |
| 存储编排 | 可以根据容器自身的需求自动创建存储卷 |
4.K8S 的设计架构
(1)各个组件用途
一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件,各司其职,共同完成集群的调度、运行与管理。
master 节点(集群的控制平面,负责集群决策)
| 组件名称 | 核心职责 | 补充说明 |
| ApiServer | 资源操作的唯一入口,接收用户命令,提供认证、授权、API 注册与发现 | 所有 kubectl 请求均先经过它,是集群的"前台" |
| Scheduler | 负责将 Pod 调度到合适的 Node 节点 | 通过预选和优选算法,综合资源、亲和性等因素决策 |
| ControllerManager | 维护集群状态,管理部署、故障检测、自动扩缩容、滚动更新等 | 运行 Deployment、ReplicaSet、Node 等多种控制器 |
| Etcd | 存储集群中所有资源对象的信息(键值数据库) | 基于 Raft 协议保证数据一致性,需定期备份 |
node 节点(集群的数据平面,负责为容器提供运行环境)
| 组件名称 | 核心职责 | 补充说明 |
| kubelet | 管理容器生命周期,同时负责存储(CSI)和网络(CNI)的接入 | 每个 Node 必装,是 Node 上的"管家" |
| Container runtime | 负责镜像管理和 Pod 中容器的真正运行 | 通过 CRI 接口对接,常见实现有 containerd、CRI-O |
| kube-proxy | 为 Service 提供集群内部的服务发现和负载均衡 | 通过维护 iptables/IPVS 规则实现流量转发 |
(2)各组件之间的调用关系
当我们要运行一个 Web 服务时,各组件按照以下流程协同工作:
集群启动后,Master 和 Node 各自将自身信息注册到 Etcd 数据库中。当用户提交 Web 服务部署请求时,请求首先到达 Master 节点的 ApiServer 组件,ApiServer 作为集群唯一入口完成认证和准入控制后,调用 Scheduler 组件进行 Pod 选址;Scheduler 从 Etcd 中读取各 Node 的资源信息,通过预选和优选算法选择合适的 Node,并将选址结果返回给 ApiServer。随后 ApiServer 调用 ControllerManager 将部署指令下发至目标 Node。目标 Node 上的 kubelet 接收到指令后,通知容器运行时(如 Docker/containerd)拉取镜像并启动 Web 服务的 Pod。Pod 运行后,kube-proxy 为 Pod 生成访问代理,通过维护 iptables/IPVS 规则实现服务发现和负载均衡,使得集群内外可通过 Service 名称访问该 Web 服务。
(3)常用名词观念
master:集群的控制节点,负责集群的管控和决策。每个集群至少需要一个 Master 节点,生产环境中通常部署多个以实现高可用。
node:工作负载节点,由 Master 统一管理和分配容器任务。Node 上运行着 kubelet 和容器运行时,负责执行 Master 下发的指令并报告自身状态。
pod:Kubernetes 的最小部署和调度单元,容器均运行在 Pod 之中。一个 Pod 可以包含一个或多个容器,这些容器共享网络命名空间、存储卷和生命周期,通常将密切协作的容器(如主容器与辅助容器)部署在同一 Pod 中。
controller:控制器,用于实现对 Pod 的生命周期管理,包括启动、停止、重启、滚动更新和弹性伸缩等操作。常见的 Controller 有 Deployment(无状态应用)、StatefulSet(有状态应用)、DaemonSet(每个节点运行一个)和 Job/CronJob(任务型)等。
service:Pod 对外服务的统一访问入口。由于 Pod 的 IP 地址是动态变化的,Service 通过标签选择器关联一组同类的 Pod,为其提供固定的访问地址和负载均衡能力。
label:标签,本质是一组键值对,用于对资源(如 Pod)进行分类和筛选。用户通过 Label 来识别和管理一组具有相同标签的资源,是 Service 和 Controller 选择 Pod 的依据。
namespace:命名空间,用于将集群内的资源进行逻辑隔离。不同 Namespace 中的资源名称可以相同,互不干扰,常用于区分开发、测试、生产环境或多个团队的资源,并可结合 ResourceQuota 进行资源配额管理。
(4)分层架构
核心层:Kubernetes 最基础的功能层,对外提供 API 以便构建上层应用,对内提供插件式的应用执行环境,是整个系统的基石。
应用层:负责各类工作负载的部署(包括无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS 解析等)。
管理层:提供系统度量(基础设施、容器和网络的监控指标)、自动化能力(自动扩缩容、动态存储 Provision 等)以及策略管理(RBAC 权限、ResourceQuota 资源配额、PodSecurityPolicy 安全策略、NetworkPolicy 网络策略等)。
接口层:为用户和外部系统提供交互方式,包括 kubectl 命令行工具、各类客户端 SDK 以及集群联邦(Federation)能力。
生态系统:在接口层之上构建的庞大容器集群管理调度生态,可划分为两个范畴:Kubernetes 外部生态(日志、监控、配置管理、CI/CD、Workflow、FaaS、OTS 应用、ChatOps 等)和 Kubernetes 内部生态(CRI 容器运行时接口、CNI 容器网络接口、CSI 容器存储接口、镜像仓库、Cloud Provider 云服务商集成、集群自身的配置和管理等)。
(二)K8S集群环境搭建
1.K8S 中容器的管理方式
Kubernetes 通过容器运行时接口(CRI,Container Runtime Interface)来管理容器,支持多种容器运行时作为底层实现。目前主流的容器管理方式有以下三种:
| 管理方式 | 说明 |
| containerd | Kubernetes 默认使用的容器运行时方式。在创建集群时无需额外配置,K8S 会直接使用 containerd 来管理和运行容器。containerd 是 Docker 底层的核心组件,轻量且高效,是目前最推荐的运行时。 |
| Docker | 早期使用最广泛的容器运行时。Kubernetes 在 1.24 版本后已移除对 Docker 作为底层运行时的原生支持(废弃了 kubelet 中的 Docker 驱动),但用户仍可借助 cri-docker 这个适配器来继续使用 Docker 创建集群。 |
| CRI-O | 专门为 Kubernetes 设计的轻量级容器运行时,直接实现 CRI 接口,无需额外适配层,是 Kubernetes 创建容器最直接的方式之一。使用时需在创建集群时安装 CRI-O 插件,并对 kubelet 的启动参数进行配置。 |
注意:使用 Docker 和 CRI-O 这两种方式时,都需要对 kubelet 程序的启动参数进行额外设置,以指定所使用的运行时类型和连接方式;而 containerd 作为默认选项,通常无需额外配置即可直接使用。
2.构建 habor 镜像仓库
(1)部署 docker 本地仓库
创建一台 harbor 主机,进行以下操作:
卸载系统中的 Podman,因为 Kubernetes 用的是 containerd 或 Docker 作为容器引擎,而 Podman 是另一套容器工具,和它们可能产生冲突。所以安装 K8s 环境之前,先把自带的 Podman 删掉,避免后续部署出问题。
搭建 Harbor 镜像仓库的 Web 访问基础环境
添加 Docker 的 yum 软件源
下载 docker 的所有软件包
将下载好的 Docker RPM 包集中到 HTTP 目录,并安装 createrepo 工具,目的是搭建本地 yum 源,供内网其他主机通过 HTTP 访问和安装 Docker
在该目录下生成 repodata 子目录,其中包含仓库索引和依赖关系信息
安装docker
(2)安装 docker 在 harbor 仓库节点
加载 Linux 内核模块,并将该配置持久化,确保系统重启后依然生效。
重新加载配置
定义 docker 的启动方式和参数,让 Docker 通过 containerd 来运行容器,并启用 iptables 管理网络规则
重新加载 systemd 配置并启动 Docker 服务,同时设置为开机自启
(3)生成key
(4)编辑 harbor 配置文件
解压 harbor 安装包
修改域名、证书、密码等参数
执行 Harbor 安装脚本,并启用 ChartMuseum 组件,用于存储和管理 Helm Chart 包
解决端口占用问题
写启动脚本
(5)启动并验证
3.所有主机配置
(1)所需主机
| 主机名 | ip | 角色 |
| harbor | 172.168.75.254 | harbor仓库 |
| k8s-master | 172.168.75.100 | master,k8s集群控制节点 |
k8s-node1 | 172.168.75.10 | worker,k8s集群工作节点 |
| k8s-node2 | 172.168.75.20 | worker,k8s集群工作节点 |
(2)关闭 swap
将三个节点的主机名分别映射到对应的 IP 地址,确保它们之间互通成功
(3)安装 docker
在 harbor 主机中分发证书到所有主机
所有主机配置 docker 加速器
所有主机配置 kubernetes 安装源
检测
重启三台主机,检查 swap 关了没
4.利用 Ansible 构建部署 kubernetes
(1)配置 epel 源,安装 ansible
(2)配置所需用户
(3)生成 ansible 的临时配置文件并建立运行环境
建立用户
(4)生成 ansible 的主配置文件并测试
(5)利用 ansible 剧本部署 docker
- name: devops k8s from ansible
hosts: all
tasks:
- name: setup docker repo
yum_repository:
name: docker
description: docker
baseurl: http://172.168.75.254:4444/docker
file: docker
gpgcheck: no- name: install docker
dnf:
name: docker-ce
state: present- name: setup docker.service
replace:
path: /lib/systemd/system/docker.service
regexp: "ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock"
replace: "ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true"- name: ensure docker directory exists
file:
path: /etc/docker
state: directory
mode: '0755'- name: setup docker registry
copy:
content: |
{
"registry-mirrors":["https://reg.lyy.org"]
}
dest: /etc/docker/daemon.json- name: setup docker certs
file:
path: /etc/docker/certs.d/reg.lyy.org
state: directory- name: cp certs file
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
loop:
- src: /etc/docker/certs.d/reg.lyy.org/ca.crtdest: /etc/docker/certs.d/reg.lyy.org/ca.crt
- src: /etc/docker/certs.d/reg.lyy.org/ca.crt
dest: /etc/pki/ca-trust/source/anchors/ca.crt- name: load module
copy:
dest: "{{ item.dest }}"
content: "{{ item.value }}"
loop:
- dest: /etc/modules-load.d/docker_mod.conf
value: br_netfilter
- dest: /etc/sysctl.d/docker.conf
value: |
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1- name: update ca cert
shell: "update-ca-trust extract;sysctl --system"- name: start services
service:
name: "{{ item }}"
state: restarted
enabled: yes
loop:
- docker
- systemd-modules-load.service
(6)利用 ansible 安装 cri-dockerd
新增加内容
- name: stup cri-dockerd
copy:
src: "{{item.src}}"
dest: "{{item.dest}}"
mode: '0755'
loop:
- src: ./cri-dockerd/cri-dockerd
dest: /usr/bin/cri-dockerd- src: "./cri-dockerd/cri-docker.service"
dest: "/lib/systemd/system/cri-docker.service"- src: "./cri-dockerd/cri-docker.socket"
dest: "/lib/systemd/system/cri-docker.socket"- name: update ca cert
shell: "update-ca-trust extract;sysctl --system;systemctl daemon-reload"- name: start services
service:
name: "{{item}}"
state: restarted
enabled: yes
loop:
- docker
- systemd-modules-load.service
- cri-docker
(7)利用 ansible 部署 k8s 软件
- name: install kubernetes from ansible
hosts: all
tasks:
- name: setup k8s repo
yum_repository:
name: kubernetes
description: kubernetes
baseurl: https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm
file: kubernetes
gpgcheck: no- name: install software in master
dnf:
name: "{{item}}"
state: present
loop:
- kubeadm-1.35.7-150500.1.1
- kubelet-1.35.7-150500.1.1
- kubectl-1.35.7-150500.1.1
when: inventory_hostname == "172.168.75.100"- name: install software in work node
dnf:
name: "{{item}}"
state: present
loop:
- kubeadm-1.35.7-150500.1.1
- kubelet-1.35.7-150500.1.1
when: inventory_hostname == "172.168.75.10" or inventory_hostname == "172.168.75.20"- name: setup kubectl kubeadm complication
lineinfile:
path: /root/.bashrc
line: |
source <(kubectl completion bash)
source <(kubeadm completion bash)
when: inventory_hostname == "172.168.75.100"- name: start kubelet
service:
name: kubelet
state: started
enabled: yes
让补齐功能生效(kubectl 命令后按2次 tab 键)
5.下载 kubernetes 集群所需镜像
(1)查看镜像
(2)下载镜像
(3)上传镜像到本地 harbor
6.在 master 中初始化 kubernetes 集群
(1)在 master 中完成集群初始化
其他主机加入本集群的凭证
如果忘记,可以输入以下命令去查看
如果初始化出问题,可输入kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock 重置集群设定
(2)添加 kubernets 环境变量到本机
(3)添加 node 节点到本集群
测试
(4)安装网络插件
测试