Docker + k8s 探索

1. Docker部分(快速入门)

1.1 Docker简介

docker本身是一个开源的容器化平台,开发者可以借助docker,将应用程序及其所需依赖打包成一个可移植,可部署的容器。

docker与传统虚拟机的区别?

传统虚拟机是模拟出独立的硬件与系统,并在此基础上创建应用程序。而docker则是在主机系统上建立多个应用和配套环境,把应用和配套环境独立打包为一个单位,这是进程级别的隔离。

1.2. Docker架构

1.2.1 Docker架构大体介绍

docker总体的架构可以分为三部分,分别是:Client、Docker Host、Registry,三部分各司其职。通过docker命令实现总体交互。

1.2.2 Docker Client

Docker Client是Docker的交互客户端,负责与用户进行交互,其交互形式是通过命令行进行交互。例如:

bash 复制代码
docker build # 构建镜像
docker run # 启动镜像
docker pull # 拉取镜像

通过输入不同的命令,Docker Client会向Docker的守护进程发送这些指令,而Docker的守护进程负责进一步的调度,从而实现不同的行为

1.2.3 Docker Host

Docker Host 是安装并运行 Docker 引擎(Docker Daemon,即守护进程)的主机。它负责管理容器、镜像、网络和存储等资源。Docker Host 接收来自 Docker Client 的请求,由其本地的 Docker 守护进程执行相应的操作,例如拉取镜像、创建和运行容器等。简言之,Docker Host 是实际运行和管理 Docker 工作负载的机器。

在 Docker Host 中:

  • 镜像(Image) 是一个只读的模板,包含了运行应用程序所需的代码、运行时环境、库、配置文件等。它用于创建容器,本身不运行,是静态的。
  • 容器(Container) 是镜像的运行实例。当镜像被启动(如通过 docker run)时,Docker Host 会基于该镜像创建一个可写层,并运行其中的程序,形成一个隔离的、轻量级的运行环境------这就是容器。

因此:镜像是静态的构建产物,容器是镜像的动态运行实例

1.2.4 Docker Registry

Docker Registry 是用于存储和分发 Docker 镜像的服务。它保存了镜像的仓库(Repository),每个仓库可以包含多个镜像版本(通过标签 Tag 区分)。用户可以通过 docker pull 从 Registry 下载镜像,或通过 docker push 将本地构建的镜像上传到 Registry。最常用的公共 Registry 是 Docker Hub,企业也可以搭建私有的 Registry(如使用 Harbor 或官方 registry 镜像)来管理内部镜像。

1.3 Docker的安装

针对Windows用户,如果想要在本机上运行一些中间件,推荐直接下载基于Windows的Linux子系统(即WSL),并下载docker hub,具体的操作可以参考安装 WSL | Microsoft Learn

安装好后,同时在Docker Hub中配置镜像加速源,docker hub -> 设置 -> Docker Engine,设置如下

bash 复制代码
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ]
}

1.4 Docker的使用

1.4.1 镜像相关命令

  1. 拉取镜像: docker pull
bash 复制代码
docker pull nginx # 拉取镜像

docker pull nginx:latest # 等同于上面的命令,不指定版本,默认拉取最新版本镜像
  1. 列出已有镜像:docker images
bash 复制代码
docker images

# 输出示例
REPOSITORY                  TAG      IMAGE ID       CREATED         SIZE
nginx                       latest   ca871a86d45a   10 days ago     225MB
confluentinc/cp-kafka       latest   d20bd62f0182   6 weeks ago     858MB
confluentinc/cp-zookeeper   latest   7610a50b13e7   8 months ago    1.75GB
  • REPOSITORY: 镜像所属仓库名称
  • TAG:镜像标签,默认是latest,表示最新版本
  • IMAGE ID:镜像ID,镜像的唯一标识
  • CREATED:镜像创建时间
  • SIZE:镜像大小
  1. 删除镜像:docker rmi
bash 复制代码
docker rmi nginx
# 输出示例
Untagged: nginx:latest
Deleted: sha256:ca871a86d45a3ec6864dc45f014b11fe626145569ef0e74deaffc95a3b15b430
  1. 对于latest标签,需要注意的事情

  2. latest是一个普通的标签名,默认由镜像构建者打上,并不会保证其所指向该镜像的最新版本

  3. 在本地使用时,Docker 会使用本地已有的 xxx:latest 镜像,不会自动检查远程是否有更新。

  4. 拉取镜像的时(如 docker pull xxx:latest):才会从远程 Registry 获取当前被标记为 latest 的那个镜像版本。

  5. 通常不建议在生产环境中使用latest标签,因为其语义模糊,无法表达具体的版本号,并且可能导致环境不一致、难以回滚等问题。

1.5.1 容器相关命令

  1. 运行镜像:docker run
bash 复制代码
docker run -d -p 81:80 nginx
  • -d 表示后台运行
  • -p 端口映射,左边为宿主机开放端口,右边为虚拟容器内部端口,例如上述案例中,宿主机的81端口映射到虚拟容器内部的80端口中

其他的可指定选项

  • -P:随机端口映射
  • -p:指定端口映射,其有以下几种格式
    • ip:hostPort:containerPort 表示ip对应的主机的端口hostPort,与该容器的containerPort进行映射
    • ip::containerPort 表示ip对应主机的端口containPort,与该容器的containerPort进行映射
    • hostPort:containerPort 表示本机的端口hostPort,与该容器的containerPort进行映射
    • containerPort 表示将容器的containerPort端口,随机映射到注解的高端口(等价于-P)
  • --net:指定网络模式,该选项有以下可选参数
    • --net=bridge: 默认选项,表示连接到默认的网桥
    • --net=host: 容器使用宿主机的网络
    • --net=container:Name-or-Id: 告诉Docker让新建的容器加入已有的容器的网络配置
    • --net=none:不配置该容器的网络,用户可以自定义网络配置

这个命令会启动本地的nginx:latest镜像(不加标签默认是latest),如果本地没有该镜像,会优先从远程仓库中拉取该镜像再进行启动

  1. 停止容器:docker stop <容器id>

  2. 启动容器:docker start <容器id>

  3. 查看容器日志:docker logs <容器id>

  4. 查看容器其他命令:docker --help

1.5 Docker Compose

1.5.1 简单介绍

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 docker-compose.yml(或 compose.yaml)文件,用户可以配置应用所需的所有服务(如 Web、数据库、缓存等),然后通过一条命令启动或停止整个应用栈。

1.5.2 基本使用流程

1. 编写docker-compose.yaml文件

复制代码
version: '3.8'
services:
  web:
    image: nginx:1.25
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: example
    ports:
      - "3306:3306"

2. 在该目录下执行命令

  • docker compose up:创建并启动所有服务(加 -d 可后台运行)
  • docker compose down:停止并移除所有容器、网络等资源
  • docker compose ps:查看服务状态
  • docker compose logs:查看日志

💡 注意:新版 Docker Desktop 已内置 docker compose(无空格)子命令(推荐),旧版可能需单独安装 docker-compose(带连字符)。

优势:

  • 声明式配置:所有依赖、端口、环境变量集中管理;
  • 一键启停 :避免手动逐个运行多个 docker run
  • 开发/测试友好:快速搭建本地多服务环境。

⚠️ 提示:生产环境中建议结合镜像版本号(如 nginx:1.25 而非 latest),确保环境一致性。

总结:一般情况下,可以直接借助AI快速生成初版的docker compose配置文件,再根据实际情况进行微调即可

1.6 Dockerfile

1.6.1 简单介绍

Dockerfile 是一个文本文件,包含一系列指令(Instructions),用于自动化构建 Docker 镜像。开发者通过编写 Dockerfile,定义应用运行所需的环境、依赖、代码和启动命令,Docker 会按顺序执行这些指令,生成一个可重复、可移植的镜像。

1.6.2 简单示例

1. 创建文件

复制代码
# 使用官方 Python 3.11 镜像作为基础镜像
FROM python:3.11-slim

# 设置工作目录
WORKDIR /app

# 将本地 requirements.txt 复制到容器中,这里的 "."代指当前目录
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码到容器,.表示当前的目录
COPY . .

# 暴露容器端口(仅为文档说明,实际运行不依赖此指令)
EXPOSE 8000

# 容器启动时运行的命令,这里会以空格进行分割,相当于运行 python app.py
CMD ["python", "app.py"]

核心指令说明:

  • FROM:指定基础镜像(必须是第一条非注释指令)
  • WORKDIR:设置后续指令的工作目录
  • COPY:将宿主机文件/目录复制到镜像中
  • RUN:在构建时执行命令(如安装软件包)
  • CMD:指定容器启动时默认执行的命令(可被 docker run 覆盖)
  • EXPOSE:声明容器监听的端口(仅为提示,不自动发布端口)

2. 构建与使用

在Dockerfile的所在目录中执行:

复制代码
docker build -t my-app:1.0

-t 指定镜像名称和标签,. 表示构建上下文为当前目录。

运行构建好的镜像:

复制代码
docker run -d -p 8000:8000 my-app:1.0

💡 最佳实践

  • 使用明确版本的基础镜像 (如 python:3.11 而非 latest);
  • 合并 RUN 指令减少镜像层数;
  • 利用 .dockerignore 排除无关文件(如 node_modules/, .git/);
  • 遵循最小化原则,只安装必要依赖。

1.6.3 镜像构建------运行

Dockerfile构建的过程,本质上是将该文件内部的不同命令,进行不同程度的封装。

  • RUNCOPYADDENVWORKDIR 等指令
    1. 属于 "构建时"操作 ,用于准备应用程序运行所需的环境和文件 (如安装依赖、复制代码、设置路径等)。
    2. 这些操作的结果被固化到镜像的只读层中,成为镜像的一部分。
  • CMDENTRYPOINT 指令
    1. 属于 "运行时"元数据 ,定义了容器启动时默认要执行的命令 (即应用程序本身的入口)。
    2. 它们不会在构建时执行 ,而是被记录在镜像中,等到 docker run 时才真正运行。

📦 所以,整个镜像 = 运行环境(由 RUN/COPY 等构建) + 启动指令(由 CMD/ENTRYPOINT 定义) 。构建完成后,这个镜像就是一个自包含、可移植的"应用包",在任何支持 Docker 的地方运行时,都能复现一致的行为。

1.7 搭建私有docker镜像仓库

1.7.1 构建并启动私有仓库地址

  1. 在本地目录中,创建一个用于存储镜像仓库的目录,例如/data/docker-registry目录

  2. 创建一个名为docker-compose.yml的文件,其中定义了私有仓库的配置,示例如下

    version: '3'

    services:
    registry:
    image: registry:2
    container_name: docker-registry
    restart: always
    ports:
    - "5000:5000" # 暴露端口
    volumes:
    - /data/docker-registry:/var/lib/registry # 数据卷挂载,持久化
    - ./auth:/auth # 挂载包含 htpasswd 文件的目录
    environment:
    REGISTRY_STORAGE_DELETE_ENABLED: "true" # 允许删除镜像(可选)
    REGISTRY_AUTH: htpasswd # 启用 htpasswd 认证
    REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd # 指定 htpasswd 文件路径
    REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm" # 可选:认证领域名称

  3. 在docker-compose.yml文件所在目录下,执行run命令

    -d 参数可选,用于后台启动

    docker compose up -d

1.7.2 设置私有仓库的账号密码

1, 下载加密包,在 Ubuntu/Debian 中,这个工具包叫 apache2-utils

复制代码
sudo apt update
sudo apt install apache2-utils
  1. 创建auth目录,这个目录就是上面docker-compose.yml文件中,指定的密码目录

    mkdir -p /data/docker-registry/auth

  2. 创建一个密码文件并添加用户 'admin',并添加密码

    sudo htpasswd -Bc /data/docker-registry/auth/htpasswd admin

1.7.3 登录docker-registry

  1. 执行以下的命令,并登录账号密码\\

    docker login 127.0.0.1:5000

注意:在登录的过程中,可能会遇到这样的问题:

复制代码
yutao@LAPTOP-884J9O4I:/mnt/d/Program-Project/data/docker-registry$ docker login 127.0.0.1:5000
Username: admin
Password:
Error saving credentials: error storing credentials - err: exit status 1, out: ``
yutao@LAPTOP-884J9O4I:/mnt/d/Program-Project/data/docker-registry$

这是因为在 WSL 中运行 docker login 时,Docker 默认会尝试使用一个凭据助手(如 docker-credential-desktop、docker-credential-secretservice 等)来安全地存储凭据。但在 WSL 环境中,这些助手可能不可用或配置不正确,导致保存失败。

我们可以采用以下命令解决,其原理是禁用凭据助手

复制代码
mkdir -p ~/.docker
cat > ~/.docker/config.json <<EOF
{
  "credsStore": "",
  "auths": {}
}
EOF

随后再次登录,应该就能成功了

1.7.4 推送镜像到私有仓库

  1. 编辑 /etc/docker/daemon.json(若不存在则创建):

    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<EOF
    {
    "insecure-registries": ["127.0.0.1:5000"]
    }
    EOF

  2. 然后重启 Docker:

    sudo systemctl restart docker

  3. 拉取一个测试镜像(例如 hello-worldnginx

    docker pull nginx:alpine

  4. 给镜像打上私有 registry 的标签

    docker tag nginx:alpine 127.0.0.1:5000/my-nginx:latest

格式:<registry-host>:<port>/<repo-name>:<tag>

  1. 推送镜像

    docker push 127.0.0.1:5000/my-nginx:latest

  2. 查看镜像是否推送成功(示例,admin:abc123321替换为自己的账密)

    curl --user admin:abc123321 http://127.0.0.1:5000/v2/

    yutao@LAPTOP-884J9O4I:/mnt/d/Program-Project/data/docker-registry curl --user admin:abc123321 http://127.0.0.1:5000/v2/ _catalog {"repositories":["my-nginx"]} yutao@LAPTOP-884J9O4I:/mnt/d/Program-Project/data/docker-registry

2. k8s部分

2.1 k8s简介

  1. k8s官方文档:Kubernetes 文档 | Kubernetes

  2. K8s 就是 Kubernetes 的简称(用数字 8 代替了中间的 8 个字母)。

3. 为什么需要k8s?

在不使用k8s的时候,我们通常会通过docker,将应用封装到虚拟容器内部运行。但是当一个应用需要大量这样的容器时,人工管理会变得十分复杂。而k8s就是用来自动化部署、扩展和管理这些容器化应用的开源平台。

4. k8s的特点?

  • 自动化: K8s 可以自动帮你把应用部署到服务器上。
  • 自我修复: 如果某个容器崩溃了,K8s 会自动重启它;如果服务器坏了,它会把容器转移到其他健康的服务器上。
  • 弹性伸缩: 就像橡皮筋一样,流量大时它自动增加容器数量,流量小时自动减少,帮你省钱又保证服务不卡顿。

5. k8s如何工作(架构是怎样的)?

组件名称 角色 功能描述
Master (控制平面) 集群的大脑 负责管理整个集群,决定把容器放在哪里运行,监控状态。
Node (工作节点) 工人的手脚 真正运行容器的地方,负责执行 Master 下达的任务。
Pod 最小单元 K8s 管理的最小单位,里面可以包含一个或多个紧密相关的容器。
  • Pod: K8s 调度的最小单位是 Pod,而不是单个容器。一个Pod中可以装多个容器。
  • Deployment: 用来定义你想要运行多少个 Pod,以及它们应该是什么样子的。比如"我要让我的网站一直保持 3 个实例在运行"。
  • Service: 为 Pod 提供一个稳定的访问入口(IP 或域名)。因为 Pod 可能会随时挂掉重建,IP 地址会变,但 Service 的地址是不变的,它会自动把流量转发给背后的 Pod(负载均衡)。

6. 云原生与k8s

云原生的目标是什么?

维度 目标 云原生如何实现
敏捷性(Agility) 快速响应市场变化,加速创新 微服务 + CI/CD + 自动化部署 → 每天发布上百次
弹性与效率(Efficiency) 资源按需使用,成本最优 容器化 + K8s 自动扩缩容 → 流量低时自动缩容省成本
韧性与安全(Resilience & Security) 系统稳定、故障自愈、安全内嵌 声明式编排 + 自愈机制 + 零信任安全 → 故障秒级恢复

因此,云原生是一套设计理念,而k8s则是其中的一种重要的技术实现形式

7. 总结

K8s 就像是一个**"云操作系统"**,它把一堆物理机或虚拟机整合成一个巨大的资源池,你只需要告诉它"我要运行什么应用、需要多少资源",它就会自动帮你搞定部署、扩容、故障恢复等所有复杂的事情。

2.2 Control Plane - Node 架构

K8s v1.20 起,官方已弃用 "Master/Slave" 术语,改用 Control Plane / Node,但"Master-Worker"说法仍广泛使用

1. 控制平面(Control Plane)------ 集群的大脑

部署在 1 个或多个高可用节点上,包含以下关键组件:

组件 功能说明
kube-apiserver 🧠 唯一入口:所有操作(kubectl、调度器、控制器等)都必须通过它。提供 RESTful API,负责认证、鉴权、验证和数据存取。
etcd 💾 数据中心 :分布式键值数据库,存储集群所有状态信息(如 Pod 配置、Service 规则、节点状态)。必须高可用(通常 3 或 5 节点)。
kube-scheduler 🗺️ 调度器 :监听未调度的 Pod,根据资源需求(CPU/内存)、亲和性、污点容忍等策略,选择最优 Node 来运行 Pod
kube-controller-manager 🔁 控制器管家 :运行多个控制器(如 ReplicaSet Controller、Node Controller),确保实际状态 = 用户声明的期望状态(例如 Pod 挂了就自动重建)。
cloud-controller-manager(可选) ☁️ 云适配器:对接公有云(AWS/Azure/GCP),管理云资源(如负载均衡、路由表)。仅在云环境使用。

⚠️ 所有控制平面组件不直接通信,全部通过 kube-apiserver 中转,保证架构清晰、解耦。

2. 工作节点(Node)------ 集群的手脚

每个 Node 上必须运行以下组件:

组件 功能说明
kubelet 👷 节点代理 :与 Control Plane 通信,接收指令并管理本机 Pod 的生命周期(创建/启动/监控容器),定期上报节点状态。
kube-proxy 🌐 网络代理 :维护 Node 上的网络规则,实现 Service 的负载均衡和流量转发(支持 iptables/IPVS 模式),让 Pod 可被访问。
Container Runtime 📦 容器运行时 :真正运行容器的底层引擎,如 containerdCRI-O(Docker 已不再原生支持,需通过 cri-dockerd 适配)。
Pod(逻辑单元) 🫘 最小部署单位:一个或多个共享网络/存储的容器组合,由 kubelet 管理。

3. 典型工作流程(以创建一个 Pod 为例)

  1. 用户通过 kubectl 提交创建 Pod 的请求。
  2. 请求经 kube-apiserver 认证后,写入 etcd
  3. kube-scheduler 发现未调度的 Pod,选择一个合适的 Node。
  4. 调度结果写回 etcd,目标 Node 上的 kubelet 监听到变化。
  5. kubelet 调用容器运行时(如 containerd)拉取镜像并启动容器。
  6. kube-proxy 自动配置 iptables/IPVS 规则,使 Service 能访问该 Pod。

4. 总结

K8s 的 Control Plane - Node 架构,就是通过"一个智能大脑(Control Plane)指挥一群听话的手脚(Nodes)",实现对成千上万容器的自动化、高可靠、弹性化管理。

2.3 手动配置k8s集群

2.3.1 前置准备

  1. 在配置k8s集群前,需要有三台虚拟机,并分别安装了docker

2. 设置主机名解析

a. 三台虚拟机分别需要设置hostname为k8s-master、k8s-worker-01、k8s-worker-02,方便后续的解析

复制代码
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-worker-01
hostnamectl set-hostname k8s-worker-02

b. 验证:分别输入hostname指令,即可查询当前主机对应的主机名

c. 在每台主机中分别执行如下指令(注意,将对应的ip地址换为真实的虚拟机ip)

复制代码
cat >> /etc/hosts << EOF
192.168.40.133 k8s-master
192.168.40.132 k8s-worker-01
192.168.40.131 k8s-worker-02
EOF

d. 验证:在任意虚拟机中发送如下命令

复制代码
ping k8s-master
ping k8s-worker-01
ping k8s-worker-02
  1. 其他前置处理

a. 为Kubernetes 准备网络环境,确保 iptables 能正确处理容器网络流量。

复制代码
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
  • 作用 :让系统开机时自动加载 br_netfilter 内核模块。

  • 为什么需要?
    Kubernetes 使用网桥(bridge)连接 Pod,这个模块能让 iptables 正确处理桥接流量。

    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF

  • 作用 :开启桥接网络对 iptables 的支持。

  • 关键参数说明

    • net.bridge.bridge-nf-call-iptables = 1:允许 IPv4 流量通过 iptables 过滤。

    • net.bridge.bridge-nf-call-ip6tables = 1:允许 IPv6 流量通过 iptables 过滤。

      sudo sysctl --system

  • 作用:立即应用上面的配置(无需重启)。

b. 关闭swap分区

复制代码
# 1. 立即关闭 swap
sudo swapoff -a

# 2. 永久禁用(注释掉 /etc/fstab 中的 swap 行)
sudo sed -i '/swap/s/^/#/' /etc/fstab

什么是swap?

Swap(交换空间) 是 Linux 用硬盘上的一块空间,当作"备用内存"。

  • 物理内存(RAM)不够用 时,系统会把一部分暂时不用的数据挪到硬盘上的 swap 区,腾出内存给新程序用。
  • 它就像"内存的替补",但速度比内存慢很多(因为硬盘比内存慢)。

为什么 Kubernetes 要关掉 swap?

  • Kubernetes 需要 精确控制内存分配,而 swap 会让内存使用变得不可预测。
  • 如果用了 swap,Pod 可能卡顿、调度异常,甚至导致节点不稳定。
  • 所以 K8s 强制要求关闭 swap ,否则 kubeadm init 会报错。

2.3.2 安装kubelet、kubeadm、kubectl

  • kubelet:运行在每个节点上的"代理",负责管理本机的 Pod 和容器(听从控制平面指挥)。
  • kubeadm :用来快速安装和初始化 Kubernetes 集群的工具(比如创建 master 节点、加入 worker 节点)。
  • kubectl :操作集群的命令行工具,你用它来查看 Pod、部署应用、管理资源等。

在所有节点上执行以下命令(以 CentOS/RHEL 为例):

复制代码
# 1. 配置 Kubernetes 源(用阿里云镜像)
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# 2. 安装三个组件(指定版本可加 -<版本号>,如-1.30.0),这里使用1.27.6,与后续的k8s初始化保持一致的版本
sudo yum install -y kubelet-1.27.6-0 kubeadm-1.27.6-0 kubectl-1.27.6-0

# 3. 启动 kubelet 并设为开机自启
sudo systemctl enable --now kubelet

验证(输入一下命令,只要可以输出版本号,就说明没有问题)

复制代码
# 查看 kubeadm 版本
kubeadm version

# 查看 kubelet 版本
kubelet --version

# 查看 kubectl 版本
kubectl version --client

2.3.3 拉取k8s镜像

复制代码
# 指定国内镜像源(避免超时)
kubeadm config images pull \
   --image-repository registry.aliyuncs.com/google_containers \
   --kubernetes-version v1.27.6

这条命令会自动拉取 Kubernetes 初始化需要的所有镜像(如 kube-apiserver、etcd 等),并重命名成官方格式。所有节点都可运行,但只需在 master 节点执行即可(worker 会按需拉取)。

拉取过程中,可能会出现如下问题:

复制代码
[root@k8s-master wangyutao]# sudo kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers
I0111 02:17:51.831285   39801 version.go:256] remote version is much newer: v1.35.0; falling back to: stable-1.28
failed to pull image "registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.15": output: time="2026-01-11T02:17:55-08:00" level=fatal msg="validate service connection: CRI v1 image API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.ImageService"
, error: exit status 1
To see the stack trace of this error execute with --v=5 or higher
[root@k8s-master wangyutao]# 

这个错误说明:

kubeadm 无法通过 CRI(容器运行时接口)和 containerd 通信,因为你的 containerd 版本较新,但配置未启用 CRI 插件。

解决方案:

1. 启用 containerd 的 CRI 支持

复制代码
# 生成默认配置(如果还没有)
containerd config default > /etc/containerd/config.toml
  1. 然后确保 /etc/containerd/config.toml 中有这一行(通常默认已启用):

    [plugins."io.containerd.grpc.v1.cri"]

  2. 重启 containerd

    systemctl restart containerd

  3. 再试一次拉取镜像

    kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

验证是否拉取成功

复制代码
crictl images | grep -E 'kube-apiserver|etcd|coredns|pause|kube-controller-manager|kube-scheduler'

验证过程中,可能会遇到这样的报错

复制代码
[root@k8s-worker-02 wangyutao]# crictl images | grep -E 'kube-apiserver|etcd|coredns|pause|kube-controller-manager|kube-scheduler'
WARN[0000] image connect using default endpoints: [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead. 
E0111 02:58:23.133095   43413 remote_image.go:119] "ListImages with filter from image service failed" err="rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory\"" filter="&ImageFilter{Image:&ImageSpec{Image:,Annotations:map[string]string{},},}"
FATA[0000] listing images: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial unix /var/run/dockershim.sock: connect: no such file or directory" 

这个错误是因为 crictl 尝试连接到默认的容器运行时端点(如 /var/run/dockershim.sock),但找不到这些文件。这是因为 Kubernetes 已经移除了 dockershim 支持,并且你需要指定正确的容器运行时端点。

解决方案:

  1. 创建或修改 crictl 的配置文件

    sudo tee /etc/crictl.yaml <<EOF
    runtime-endpoint: unix:///run/containerd/containerd.sock
    image-endpoint: unix:///run/containerd/containerd.sock
    timeout: 10
    debug: false
    EOF

  2. 再次验证

    crictl images | grep -E 'kube-apiserver|etcd|coredns|pause|kube-controller-manager|kube-scheduler'

  3. 如果正常,那么输出类似于这样

    registry.aliyuncs.com/google_containers/kube-apiserver v1.28.15 3b4e7c6a6b2d3 1.2GB
    registry.aliyuncs.com/google_containers/kube-controller-manager v1.28.15 9f8f34c3e32d4 1.1GB
    registry.aliyuncs.com/google_containers/kube-scheduler v1.28.15 5f8f34c3e32d4 95MB
    registry.aliyuncs.com/google_containers/etcd 3.5.6-0 3b4e7c6a6b2d3 300MB
    registry.aliyuncs.com/google_containers/pause 3.6 3b4e7c6a6b2d3 747kB
    registry.aliyuncs.com/google_containers/coredns v1.8.6 3b4e7c6a6b2d3 41MB

2.3.4. 初始化k8s节点

  1. 在主节点机器上,运行如下命令

    kubeadm init
    --apiserver-advertise-address=192.168.40.133
    --control-plane-endpoint=k8s-master
    --image-repository=registry.aliyuncs.com/google_containers
    --kubernetes-version=v1.27.6
    --pod-network-cidr=10.244.0.0/16

  2. 初始化好后,需要额外做以下事情

启用环境变量(在init的日志输出中会有提示)

复制代码
export KUBECONFIG=/etc/kubernetes/admin.conf
  1. 为kubectl配置kubeconfig文件,复制 admin.conf 到当前用户的 kube 目录即可

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

  2. 验证集群

    查看节点(应该显示 k8s-master 为 Ready)

    kubectl get nodes

    查看系统 Pod

    kubectl get pods -n kube-system

✅ 当 STATUSReady ,且所有系统 Pod 都 Running,说明集群已就绪!

2.3.5 worker节点加入集群

  1. 需要在每个worker节点中,执行如下命令(需要以root账户执行)

    kubeadm join k8s-master:6443
    --token 2gqq4k.sjwepar0hk1ffsog
    --discovery-token-ca-cert-hash sha256:8fee861ec4f673fec0dab223c2cdd7facc7cf74339a256e1177787952c52d0d5

  2. 其中的token、discovery-token-ca-cert-hash,需要从主节点初始化成功的日志中获取,也可以通过以下命令中直接获取到,并对上述的命令进行替换即可

    1. 列出当前有效的 token

    kubeadm token list

    如果没有有效 token(默认 24 小时过期),可以创建一个新 token:

    kubeadm token create

    2. 获取 discovery-token-ca-cert-hash

    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

    3. 也可以通过这个命令一次性获取所有信息

    kubeadm token create --print-join-command

    输出示例:kubeadm join k8s-master:6443 --token abcd12.efgh34ijkl56mnop --discovery-token-ca-cert-hash sha256:8fee861ec4f673fec0dab223c2cdd7facc7cf74339a256e1177787952c52d0d5

  3. 检查节点状态。通过以下命令检查节点启动状态

    kubectl get pods -n kube-flannel -w

输出示例

复制代码
[root@k8s-master ~]# kubectl get pods -n kube-flannel -w
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-jwdv8   1/1     Running   0          28m
kube-flannel-ds-qwt7b   1/1     Running   0          28m
kube-flannel-ds-vrvfj   1/1     Running   0          28m
  1. 搭建服务测试

在主节点中,输入一下命令,拉取nginx镜像并搭建pod,测试能否搭建成功

复制代码
kubectl run test-nginx --image=nginx

输出成功示例

复制代码
kubectl get pods

NAME         READY   STATUS    RESTARTS   AGE
test-nginx   1/1     Running   0          11m

到这里,k8s集群的搭建就算圆满完成了!

2.4 kubectl命令使用

2.4,1 kubectl简介

kubectl官方文档:命令行工具 (kubectl) | Kubernetes

kubectl(发音为 "cube control" 或 "kube control")是 Kubernetes 官方提供的命令行工具(CLI),用于与 Kubernetes 集群进行交互。它是用户管理、操作和调试 Kubernetes 资源的核心工具。

核心作用

  • 与 Kubernetes API Server 通信kubectl 通过读取 $HOME/.kube/config(即 kubeconfig 文件)中的集群地址、认证信息等,向控制平面发送请求。
  • 管理集群资源:可以创建、查看、更新、删除 Pod、Deployment、Service、Namespace 等各种 Kubernetes 对象。
  • 调试与监控:支持查看日志、进入容器、检查事件、描述资源状态等。

2.4.2 kubectl常用命令

1. kubectl的命令格式

复制代码
kubectl [command] [TYPE] [NAME] [flags]
  • command :操作,如 getdescribedelete
  • TYPE :资源类型,如 podservicedeployment(可缩写,如 posvcdeploy
  • NAME:资源名称(可选)
  • flags :选项,如 -n namespace--kubeconfig

2. kubectl常用命令总结

查看资源(Get)

复制代码
kubectl get pods                          # 查看 Pod
kubectl get nodes                         # 查看节点
kubectl get svc                           # 查看 Service
kubectl get deploy                        # 查看 Deployment
kubectl get ns                            # 查看命名空间
kubectl get all -n <namespace>            # 查看某命名空间下所有资源

查看详细信息(Describe)

复制代码
kubectl describe pod <pod-name>           # 查看 Pod 详情(事件、状态等)
kubectl describe node <node-name>         # 查看节点详情(资源、污点等)

创建/删除资源

复制代码
kubectl create -f file.yaml               # 从 YAML 创建资源
kubectl apply -f file.yaml                # 声明式创建或更新资源(推荐)
kubectl delete -f file.yaml               # 删除 YAML 中定义的资源
kubectl delete pod <pod-name>             # 直接删除某个 Pod

日志与进入容器

复制代码
kubectl logs <pod-name>                   # 查看 Pod 日志
kubectl logs -f <pod-name>                # 实时跟踪日志(类似 tail -f)
kubectl exec -it <pod-name> -- /bin/sh    # 进入容器执行 shell

端口转发(调试用)

复制代码
kubectl port-forward svc/<service-name> 8080:8080 -n <ns>
# 将本地 8080 端口转发到集群中某服务的 8080 端口

其他实用命令

复制代码
kubectl top pod                           # 查看 Pod CPU/内存使用(需 Metrics Server)
kubectl top node                          # 查看节点资源使用
kubectl explain pod                       # 查看 Pod 的 API 字段说明
kubectl config view                       # 查看当前 kubeconfig 配置
kubectl cluster-info                      # 查看集群基本信息

注意事项

  • -n <namespace> 指定命名空间(默认是 default
  • --help 查看任意命令的帮助,例如:kubectl get pods --help
  • 使用别名简化:alias k=kubectl,然后 k get pod

2.5 命名空间

k8s命名空间文档:名字空间演练 | Kubernetes

命名空间(Namespace) 是k8s一种逻辑隔离机制,用于将集群中的资源(如 Pod、Service、Deployment 等)分组管理。

  • 就像 "文件夹" 一样,把不同项目、团队或环境的资源分开。
  • 默认有 defaultkube-systemkube-public 等命名空间。
  • 不同命名空间里的资源名字可以重复 (比如两个 namespace 都可以有叫 web 的 Pod)。
  • 资源不能直接跨命名空间访问 (需用全名,如 service.namespace.svc.cluster.local)。

命令行查看所有的命名空间

复制代码
# 三个命令都可以查看所有的namespaces
kubectl get namespace
kubectl get ns
kubectl get namespaces

四个默认的命名空间

  1. default:用户创建资源时未指定命名空间,就会放在这里。
  2. kube-system:Kubernetes 系统组件(如 kube-apiserver、coredns、kube-proxy)所在的空间。
  3. kube-public:公共资源,所有用户(包括未认证的)都可读,通常包含集群信息(如 cluster-info ConfigMap)。
  4. kube-node-lease:用于存储节点心跳信息(Node Lease),帮助快速检测节点是否存活。

✅ 这些命名空间在集群初始化时自动创建,不要手动删除或修改

2.6 Pod

2.6.1 Pod简介

Pod 是 Kubernetes 中最小的部署和调度单元。其特性如下:

  • 一个 Pod 可以包含 一个或多个容器(通常是一个主容器,有时加一些辅助容器,叫 Sidecar)。
  • 同一个 Pod 里的容器共享网络、存储和生命周期 :它们有相同的 IP 地址、能通过 localhost 互相访问,并一起被调度到同一个节点上。
  • Pod 是短暂的(ephemeral):一旦被删除,就不会恢复(由控制器如 Deployment 负责重建)。

Pod = 一个或多个紧密协作的容器 + 共享资源 + 最小调度单位。

2.6.2 创建Pod

  1. 创建Pod示例:运行一个nginx容器

通过命令行方式

复制代码
kubectl run mynginx --image=nginx:1.14.2
  1. 通过指定的yaml文件创建pod

创建如下文件(例如mynginx-01.yaml)

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: mynginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest

运行命令

复制代码
kubectl apply -f mynginx-01.yaml

2.6.3 Pod其他常用命令

  1. 查看pod状态

    查看状态

    kubectl get pods

    输出样例

    NAME READY STATUS RESTARTS AGE
    mynginx 1/1 Running 0 2m45s
    test-nginx 1/1 Running 0 64m

    查看详细状态

    kubectl get pods -owide

    输出样例

    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    mynginx 1/1 Running 0 5m29s 10.244.1.2 k8s-worker-02 <none> <none>
    test-nginx 1/1 Running 0 67m 10.244.2.2 k8s-worker-01 <none> <none>

  2. 删除pod

    kubectl delete pod test-nginx

  3. 为某个pod生成详细的运行时状态清单

    这里会查询到容器运行时候的状态

    kubectl get pod mynginx -o yaml

    这里会将运行时候的状态导出到nginx-pod.yaml文件中

    kubectl get pod mynginx -o yaml > nginx-pod.yaml

.查看该yaml文件

复制代码
vim nginx-pod.yaml

输出样例

复制代码
# Kubernetes API 版本和资源类型
apiVersion: v1
kind: Pod

# 元数据:描述 Pod 的基本信息(由系统或用户定义)
metadata:
  # 系统自动记录的创建时间(通常无需手动指定)
  creationTimestamp: "2026-01-12T10:08:45Z"
  # 标签,通常由 `kubectl run` 自动生成,用于选择器或分类
  labels:
    run: mynginx
  # Pod 名称(必须)
  name: mynginx
  # 所属命名空间(默认为 default)
  namespace: default
  # 资源版本号,Kubernetes 内部用于乐观并发控制(不可修改)
  resourceVersion: "15633"
  # 全局唯一标识符(UUID),由系统生成
  uid: 9a17b40e-5410-4694-8fc3-b820a245ac8c

# spec:声明你希望 Pod 达到的"期望状态"(declarative configuration)
spec:
  # 容器列表(至少一个)
  containers:
  - # 镜像地址(未指定 registry 默认为 docker.io/library/)
    image: nginx:1.14.2
    # 镜像拉取策略:本地有就不拉(适合测试;生产建议 Always)
    imagePullPolicy: IfNotPresent
    # 容器名称(必须)
    name: mynginx
    # 资源限制(空表示无限制,默认 BestEffort QoS)
    resources: {}
    # 容器终止时写入消息的路径(用于调试退出原因)
    terminationMessagePath: /dev/termination-log
    # 终止消息的读取方式
    terminationMessagePolicy: File
    # 挂载 ServiceAccount Token(用于访问 Kubernetes API)
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-7xhx6
      readOnly: true

  # DNS 策略:使用集群内部 DNS(如 CoreDNS)
  dnsPolicy: ClusterFirst
  # 是否自动注入服务环境变量(如 MY_SERVICE_HOST)
  enableServiceLinks: true
  # Pod 被调度到的具体节点(由调度器决定,一般不手动设置)
  nodeName: k8s-worker-02
  # 抢占策略:可抢占低优先级 Pod(高级调度特性)
  preemptionPolicy: PreemptLowerPriority
  # 优先级数值(0 表示普通 Pod)
  priority: 0
  # 容器退出后是否重启(Pod 级别策略)
  restartPolicy: Always
  # 使用的调度器名称
  schedulerName: default-scheduler
  # Pod 级别的安全上下文(如 runAsUser、fsGroup 等)
  securityContext: {}
  # 关联的 ServiceAccount(用于权限控制)
  serviceAccount: default
  serviceAccountName: default
  # Pod 终止前等待的优雅停机时间(秒)
  terminationGracePeriodSeconds: 30
  # 容忍节点污点(允许在 not-ready 或 unreachable 节点上短暂停留)
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  # 自动挂载的卷:包含 token、ca.crt 和 namespace 信息
  volumes:
  - name: kube-api-access-7xhx6
    projected:
      defaultMode: 420  # 权限模式(八进制 644)
      sources:
      # ServiceAccount Token(用于认证 API Server)
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      # 集群 CA 证书
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      # Downward API:将 metadata.namespace 注入文件
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

# status:Pod 当前的实际运行状态(只读,由 kubelet 更新)
status:
  # Pod 生命周期各阶段的状态条件
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2026-01-12T10:08:45Z"
    status: "True"
    type: Initialized     # Init 容器已完成
  - lastProbeTime: null
    lastTransitionTime: "2026-01-12T10:10:01Z"
    status: "True"
    type: Ready           # Pod 已就绪,可接收流量
  - lastProbeTime: null
    lastTransitionTime: "2026-01-12T10:10:01Z"
    status: "True"
    type: ContainersReady # 所有容器已就绪
  - lastProbeTime: null
    lastTransitionTime: "2026-01-12T10:08:45Z"
    status: "True"
    type: PodScheduled    # 已成功调度到节点

  # 容器实际运行状态
  containerStatuses:
  - containerID: containerd://0cb7469f478baa7114bde6e0cec1f2544307f345854bfd8d4fcffdbeb74be856
    image: docker.io/library/nginx:1.14.2   # 实际使用的完整镜像名
    imageID: docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
    lastState: {}         # 上次终止状态(空表示首次启动)
    name: mynginx
    ready: true           # 容器已通过就绪探针(如有)
    restartCount: 0       # 重启次数
    started: true         # 容器已启动
    state:
      running:
        startedAt: "2026-01-12T10:10:00Z"  # 容器启动时间

  # 节点 IP(物理机 IP)
  hostIP: 192.168.40.131
  # Pod 当前生命周期阶段(Pending/Running/Succeeded/Failed/Unknown)
  phase: Running
  # 分配给 Pod 的集群内部 IP(由 CNI 插件如 Flannel 分配)
  podIP: 10.244.1.2
  podIPs:
  - ip: 10.244.1.2
  # 服务质量等级(BestEffort = 无资源限制)
  qosClass: BestEffort
  # Pod 开始调度的时间
  startTime: "2026-01-12T10:08:45Z"

2.7 Deployment

2.7.1 Deployment简介

Deployment 是k8s中一种高级控制器对象,用于声明式地管理 Pod 的部署和生命周期,特别适用于无状态应用。其主要功能如下

  1. 副本管理(Replica Management)
    自动维持指定数量的 Pod 副本(例如 replicas: 3),如果某个 Pod 挂了,Deployment 会自动重建。
  2. 滚动更新(Rolling Update)
    更新镜像或配置时,逐步替换旧 Pod,保证服务不中断(默认策略)。
  3. 版本回滚(Rollback)
    如果新版本出问题,可一键回退到上一个稳定版本。
  4. 暂停/恢复更新
    支持在更新过程中暂停,方便调试。
  5. 声明式配置
    你只需描述"最终想要什么状态",K8s 会自动让系统向该状态收敛。

底层原理:

  • Deployment 不直接管理 Pod ,而是通过 ReplicaSet(RS) 来控制 Pod。
  • 每次更新(如改镜像)会创建新的 ReplicaSet,逐步扩新缩旧,实现平滑升级。

2.7.2 Deployment命令使用

  1. 创建Deployment

命令格式:

复制代码
# 基础创建
kubectl create deployment <deployment-name> --image=<container-image>

命令示例:

复制代码
# 基础创建示例
kubectl create deployment my-tomcat --image=tomcat:9.0.55

# 新增可选参数(比如暴露端口)
kubectl create deployment my-app --image=nginx --port=80

# 指定副本数量为3
kubectl create deployment my-app --image=nginx --replicas=3
  1. 查看状态

    列出所有 Deployment

    kubectl get deployments

    查看详细信息(包括 Pod 状态、ReplicaSet 等)

    kubectl describe deployment my-app

    以 YAML 格式输出 Deployment 配置(可用于备份或修改)

    kubectl get deployment my-app -o yaml

  2. 扩容、缩容

    将副本数扩缩到 3

    kubectl scale deployment my-app --replicas=3

    或使用完整资源名

    kubectl scale deploy/my-app --replicas=5

  3. 更新镜像(滚动更新)

    更新容器镜像(触发滚动更新)

    kubectl set image deployment/my-app nginx=nginx:1.25

    查看滚动更新状态

    kubectl rollout status deployment/my-app

    查看历史版本(用于回滚)

    kubectl rollout history deployment/my-app

  4. 回滚镜像

    回滚到上一个版本

    kubectl rollout undo deployment/my-app

    回滚到指定版本(需先用 history 查看 revision)

    kubectl rollout undo deployment/my-app --to-revision=2

  5. 暴露服务

    为 Deployment 创建 ClusterIP Service(集群内访问)

    kubectl expose deployment my-app --port=80 --target-port=80

    创建 NodePort 类型 Service(外部可通过节点 IP + 端口访问)

    kubectl expose deployment my-app --port=80 --type=NodePort

    创建 LoadBalancer(云环境适用)

    kubectl expose deployment my-app --port=80 --type=LoadBalancer

  6. 删除Deployment

    为 Deployment 创建 ClusterIP Service(集群内访问)

    kubectl expose deployment my-app --port=80 --target-port=80

    创建 NodePort 类型 Service(外部可通过节点 IP + 端口访问)

    kubectl expose deployment my-app --port=80 --type=NodePort

    创建 LoadBalancer(云环境适用)

    kubectl expose deployment my-app --port=80 --type=LoadBalancer

  7. 进入 Pod 调试(常配合 Deployment 使用)

    获取 Pod 名称

    kubectl get pods -l app=my-app

    进入容器(假设容器名为 my-app)

    kubectl exec -it <pod-name> -- /bin/bash

    查看日志

    kubectl logs <pod-name>
    kubectl logs -f <pod-name> # 实时跟踪日志

  8. 编辑 Deployment(在线修改)

    编辑 Deployment(在线修改)

  9. 使用yaml形式(生产推荐)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-tomcat
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: tomcat # ← Deployment 通过这个"选择器"找 Pod
    template:
    metadata:
    labels:
    app: tomcat # ← 所有新创建的 Pod 都带这个标签
    spec:
    containers:
    - name: tomcat
    image: tomcat:9.0.55

2.7.3 注意事项

  1. Deployment会始终保持pod的期望状态(指定副本数、可运行状态)
  2. 当pod被删除,ReplicaSet会发现当前 Pod 数量少于期望值,于是自动创建一个新的 Pod 来替代它。 这就是 Kubernetes 的 自愈能力(self-healing)。
  3. 当pod变多了,会自动删除多余的pod、Deployment(通过其管理的 ReplicaSet)始终以 spec.replicas 字段定义的副本数为"目标状态"。因此,ReplicaSet 会 主动终止(删除)多余的 Pod,直到数量回到期望值。
  4. Deployment通过标签"管理"Pod,Deployment 创建的每个 Pod 都有相同的标签(比如app=tomcat)。而ReplicaSet(由 Deployment 创建)会持续监控:所有带 app=tomcat 标签的 Pod。注意,如果手动创建一个也带 app: tomcat 的 Pod,它也会被这个 ReplicaSet "接管" ------ 而如果副本数超了,就有可能被删掉。

2.7.4 Deployment拉取镜像失败解决方案

1. 判断使用的是container还是docker

在宿主机上运行

复制代码
kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.containerRuntimeVersion}'
  1. 如果是container,则修改container的镜像配置

    sudo vi /etc/containerd/config.toml

  2. 找到 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 段落,在其下添加:

    [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://docker.1ms.run"]

✅ 注意缩进!它必须是 mirrors 的子表。(缩进一般是两个空格)

  1. 保存并重启 containerd

    sudo systemctl restart containerd

  2. 测试拉取标准镜像

    sudo crictl pull nginx

2.8 Service

2.8.1 Service简介

1. 什么是Service?

ServiceKubernetes 中实现服务发现负载均衡核心资源对象。 它的主要作用是:为一组 Pod 提供稳定的网络访问入口(IP + 端口),即使这些 Pod 会频繁地被创建、销毁、更换 IP。

2. 为什么需要Service?

在 Kubernetes 中:

  • Pod 是临时的(ephemeral):它们随时可能被删除、重建,IP 地址会变。
  • 应用之间不能直接依赖 Pod IP 通信(因为 IP 不稳定)。
  • 需要一个"固定入口"来访问一组功能相同的 Pod(比如多个 Tomcat 实例)

因此Service就会作为一组Pod的"固定入口"

3. Service的核心功能

功能 说明
服务发现 其他 Pod 可以通过 Service 名称(如 my-tomcat)访问它,无需知道具体 Pod IP
负载均衡 自动将请求分发到后端多个健康的 Pod
解耦 前端不关心后端有多少个 Pod、IP 是什么,只认 Service

4. Service 如何工作?

核心就是标签选择器,与Deployment类似,Service 通过 标签选择器(selector) 找到它要代理的 Pod,所以

  • Deployment 创建带 app=tomcat 标签的 Pod;
  • Service 通过相同标签找到这些 Pod;
  • 请求发到 Service → 自动转发到任意一个健康 Pod。

5. Service的几种类型

类型 用途 访问方式
ClusterIP(默认) 集群内部访问 只能在 Kubernetes 集群内通过虚拟 IP 或 DNS 访问
NodePort 从集群外部访问(测试用) 通过任意 Node 的 IP + 高端口(如 30000-32767)访问
LoadBalancer 云厂商集成(生产推荐) 云平台自动创建外部负载均衡器(如 AWS ELB、阿里云 SLB)
ExternalName 映射外部服务 返回 CNAME 记录,用于访问集群外的服务

2.8.2. Service常用命令

  1. 创建不同类型的Service

    默认 ClusterIP(集群内访问)

    kubectl expose deployment my-tomcat --port=8080

    NodePort(外部可通过 http://<node-ip>:<node-port> 访问)

    kubectl expose deployment my-tomcat --port=8080 --type=NodePort

    LoadBalancer(云环境)

    kubectl expose deployment my-tomcat --port=8080 --type=LoadBalancer

  2. 测试是否创建成功

    查看 Service,找到 PORT(S) 列中的 3xxxx 端口

    kubectl get svc my-tomcat

    查看工作节点的 IP(通常是内网 IP)

    kubectl get nodes -o wide

在宿主机或者同局域网中,测试以下命令

复制代码
http://<任一节点IP>:<NodePort>
  1. yaml形式创建

    apiVersion: v1
    kind: Service
    metadata:
    name: my-tomcat-service # Service 名称
    namespace: default # 可选,默认命名空间
    spec:
    type: NodePort # Service 类型:NodePort
    selector:
    app: tomcat # 必须与 Pod 的标签匹配
    ports:
    - protocol: TCP
    port: 8080 # Service 对外暴露的端口(集群内通过此端口访问)
    targetPort: 8080 # Pod 中容器实际监听的端口
    nodePort: 30080 # 可选:指定 NodePort(范围 30000-32767),若不指定则自动分配

保存为my-tomcat.yaml,然后执行

复制代码
kubectl apply -f my-tomcat-svc.yaml

2.9 Volume存储

2.9.1 Volume 简介

Volume(存储卷) 是 Kubernetes 中用于在 Pod 内部实现数据持久化容器间共享数据 的核心机制。与容器生命周期不同,Volume 的生命周期与 Pod 绑定------即使容器重启,Volume 中的数据也不会丢失。

  1. 为什么需要 Volume?
  • 容器内的文件系统是临时的:容器重启后,原有数据会丢失。
  • 多个容器运行在同一个 Pod 中时,可能需要共享某些文件(如日志、配置)。
  • 某些应用(如数据库)必须将数据写入持久化存储,不能依赖内存或临时磁盘。

因此,Kubernetes 引入 Volume 来解决这些问题。

  1. Volume 的核心特点
特性 说明
生命周期绑定 Pod Volume 在 Pod 创建时挂载,在 Pod 删除时销毁(但部分类型如 PV 可独立存在)
支持多种后端类型 包括临时存储、节点本地存储、网络存储、云盘、配置数据等
容器间共享 同一个 Pod 中的多个容器可挂载同一个 Volume,实现文件共享
解耦存储与应用 应用无需关心底层存储细节,只需声明挂载点
  1. 常见 Volume 类型
类型 用途 是否持久
emptyDir 临时存储,Pod 内容器共享,Pod 删除即清空
hostPath 挂载宿主机目录到 Pod(仅单节点测试用) ⚠️ 半持久(依赖节点)
configMap / secret 挂载配置或敏感信息为文件 ❌(但内容由集群管理)
persistentVolumeClaim (PVC) 请求持久化存储(如云硬盘、NFS),生产推荐
nfs, cephfs, awsElasticBlockStore 直接使用特定后端存储(不推荐直接使用,建议通过 PVC)

💡 最佳实践 :生产环境中应使用 PersistentVolume (PV) + PersistentVolumeClaim (PVC) 模式,实现存储与 Pod 解耦。

  1. Volume 如何工作?
  • 在 Pod 的 spec.volumes 中定义一个或多个 Volume;

  • 在容器的 volumeMounts 中指定挂载路径;

  • 所有挂载了同一 Volume 的容器可读写相同目录。

    volumes:
    - name: cache-volume
    emptyDir: {}
    containers:
    - name: app
    volumeMounts:
    - name: cache-volume
    mountPath: /cache


2.9.2 NFS配置

1. 什么是NFS?

NFS(Network File System,网络文件系统)是一种分布式文件系统协议 ,允许你将远程服务器上的目录"挂载"到本地机器上,就像访问本地磁盘一样。

在 Kubernetes(k8s)中,NFS 常被用作一种共享、持久化、多读多写的存储后端,特别适合需要多个 Pod 同时读写同一份数据的场景(比如 WordPress 多副本、日志收集、共享配置等)。

2. NFS在k8s中的作用?

  • 持久化存储:Pod 删除后,数据保留在 NFS 服务器上。
  • 多 Pod 共享:多个 Pod(甚至跨节点)可同时挂载同一个 NFS 路径。
  • 读写支持 :支持 ReadWriteMany(RWX)访问模式(这是很多云盘不支持的!)。
  • 成本低:自建 NFS 服务器比云厂商存储便宜,适合私有集群。
  1. KFS配置

在k8s主节点上运行如下命令

复制代码
# 安装 NFS 服务器
sudo yum install -y nfs-utils

# 创建共享目录
sudo mkdir -p /nfs/data
sudo chmod -R 777 /nfs/data   # 测试用;生产环境建议用更安全的权限

# 配置 /etc/exports
sudo tee /etc/exports <<EOF
/nfs/data  *(rw,sync,no_subtree_check,no_root_squash)
EOF

# 启动 rpc 和 nfs 服务
sudo systemctl enable --now rpcbind
sudo systemctl enable --now nfs-server

# 重新加载 exports 配置
sudo exportfs -rav

# 开放防火墙(如果启用了 firewalld)
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --reload

在剩下的所有工作节点上运行如下命令

复制代码
# 安装 nfs 服务(CentOS/RHEL)
sudo dnf install -y nfs-utils

验证安装是否成功(在任意工作节点上手动挂载 NFS)

复制代码
# 创建测试目录
sudo mkdir -p /mnt/nfs-test

# 在其他的节点上挂载 NFS(替换为你的 NFS 服务器 IP 和路径)
sudo mount -t nfs 192.168.10.100:/nfs/data /mnt/nfs-test

# 查看是否挂载成功
df -h | grep nfs

# 输出中包含类似:
192.168.10.100:/nfs/data  100G  5.0G   95G   5% /mnt/nfs-test

# 测试读写
echo "test from node" | sudo tee /mnt/nfs-test/test.txt
cat /mnt/nfs-test/test.txt

# ✅ 能正常写入和读取,说明 NFS 服务端和网络正常。

2.9.3 PV & PVC

1. 什么是PV、PVC?

PV(PersistentVolume)和 PVC(PersistentVolumeClaim) 是 Kubernetes 中用于管理持久化存储的两个核心概念,它们将存储的提供存储的使用解耦。

PV(PersistentVolume)------ 存储的"供给方"

  • 集群管理员 创建。
  • 代表集群中的一块真实存储资源(如 NFS 目录、云硬盘、Ceph RBD 等)。
  • 集群级别的资源(不属于某个命名空间)。
  • 包含存储的详细信息:大小、访问模式(ReadWriteOnce / ReadWriteMany)、回收策略、后端类型等。

PVC(PersistentVolumeClaim)------ 存储的"需求方"

  • 应用开发者/用户 创建。
  • 是对存储的 申请(claim),声明"我需要多少存储、什么访问模式"。
  • 属于 命名空间级别 的资源。
  • Kubernetes 会自动将 PVC 与满足条件的 PV 绑定(bind)

其中,PVC可以被多个Pod引用 ,因此这三者的依赖关系就是NFS -> PV -> PVC -> 多Pod,通过这种关系,实现多系统资源共享(共享一个PVC)

2. 关键配置字段说明

PV 常用字段

复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 20Gi                     # 存储容量
  accessModes:                        # 访问模式(必选)
    - ReadWriteMany                   # 支持多 Pod 读写(NFS 用这个)
    # 其他选项:ReadWriteOnce(单节点读写)、ReadOnlyMany(多节点只读)
  persistentVolumeReclaimPolicy: Retain  # 回收策略
    # Retain:删除 PVC 后保留数据(手动清理)
    # Delete:删除 PVC 时自动删除 PV 和底层数据(云盘常用)
  nfs:                                # 存储后端类型(这里是 NFS)
    server: 192.168.40.133            # NFS 服务器 IP
    path: "/nfs/data"                 # 共享路径
  # 其他后端:awsElasticBlockStore, gcePersistentDisk, cephfs, hostPath 等

PVC 常用字段

复制代码
apiVerson: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
  namespace: default                  # 所在命名空间
spec:
  accessModes:
    - ReadWriteMany                   # 必须与 PV 的 accessModes 兼容
  resources:
    requests:
      storage: 10Gi                   # 申请的最小容量(必须 ≤ PV 容量)
  # 可选:指定 StorageClass(动态供给时用)
  # storageClassName: nfs-storage

⚠️ 注意:

  • PVC 的 accessModesstorage 必须被某个 PV 完全满足才能绑定;
  • 如果没有匹配的 PV,PVC 会处于 Pending 状态。

3. 使用流程(标准四步)

步骤 1:管理员创建 PV(或配置 StorageClass 实现动态供给)

复制代码
kubectl apply -f pv.yaml

步骤 2:开发者创建 PVC

复制代码
kubectl apply -f pvc.yaml

步骤 3:Kubernetes 自动绑定 PV ↔ PVC

复制代码
kubectl get pv,pvc
# STATUS 应为 Bound

步骤 4:Pod 通过 PVC 挂载存储

复制代码
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-pvc   # 引用 PVC 名称

2.9.4 Volume 常用示例

  1. 使用 emptyDir(临时共享)

    apiVersion: v1
    kind: Pod
    metadata:
    name: shared-pod
    spec:
    containers:

    • name: writer
      image: alpine
      command: ["/bin/sh", "-c"]
      args: ["echo 'Hello from writer' > /shared/data.txt && sleep 3600"]
      volumeMounts:
      • name: shared-data
        mountPath: /shared
    • name: reader
      image: alpine
      command: ["/bin/sh", "-c"]
      args: ["cat /shared/data.txt && sleep 3600"]
      volumeMounts:
      • name: shared-data
        mountPath: /shared
        volumes:
    • name: shared-data
      emptyDir: {}
  2. 使用 hostPath(仅开发/测试)

    volumes:

    • name: host-log
      hostPath:
      path: /var/log/myapp
      type: DirectoryOrCreate

⚠️ 注意:hostPath 依赖具体节点,不适合多节点集群或生产环境。

  1. 使用 PVC(生产推荐)

先创建 PVC:

复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

再在 Pod 中引用:

复制代码
volumes:
- name: data-storage
  persistentVolumeClaim:
    claimName: my-pvc
  1. 使用 NFS(通过 PV + PVC)

假设 NFS 服务器 IP 为 192.168.10.100,共享路径为 /nfs/data

步骤 1:创建 PersistentVolume(PV)

复制代码
# nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteMany          # NFS 支持多读多写!
  persistentVolumeReclaimPolicy: Retain  # 删除 PVC 后保留数据
  nfs:
    server: 192.168.10.100   # 替换为你的 NFS 服务器 IP
    path: "/nfs/data"        # 共享目录路径

步骤 2:创建 PersistentVolumeClaim(PVC)

复制代码
# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Gi

步骤 3:在应用 Pod 中使用 PVC

复制代码
# nginx-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-nfs
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: web-content
      mountPath: /usr/share/nginx/html
  volumes:
  - name: web-content
    persistentVolumeClaim:
      claimName: nfs-pvc

应用命令:

复制代码
kubectl apply -f nfs-pv.yaml
kubectl apply -f nfs-pvc.yaml
kubectl apply -f nginx-nfs.yaml

✅ 验证:多个 Pod 挂载同一 PVC 可共享文件,实现跨节点读写。

2.9.5 注意事项

💡 为什么推荐用 PV/PVC 而不是直接在 Pod 中写 nfs:

  • 解耦:Pod 不依赖具体 NFS 地址,便于迁移;
  • 复用:多个应用可申请同一类存储;
  • 管理:管理员控制存储资源,开发者只需申请(PVC)。
  • Volume 不是备份方案:即使使用 PVC,仍需额外做数据备份。
  • 不要直接使用云存储插件:应通过 PVC 抽象,提高可移植性。
  • Pod 删除 ≠ 数据删除:使用 PVC 时,即使 Pod 被删,数据仍保留在 PV 中(取决于回收策略)。
  • 权限问题 :容器内进程用户需有权限读写挂载目录,必要时设置 securityContext

2.9.6 调试技巧

复制代码
# 查看 Pod 挂载的 Volume
kubectl describe pod <pod-name>

# 进入容器查看挂载点
kubectl exec -it <pod-name> -- ls /mount-path

# 查看 PVC 状态
kubectl get pvc
kubectl describe pvc my-pvc

📌 总结 :Volume 是 Kubernetes 实现"有状态"能力的基础。对于无状态应用可用 emptyDir,对于数据库、文件服务等关键应用,务必使用 PVC + PV 实现真正的持久化存储。

2.10 ConfigMap

2.10.1 ConfigMap简介

1. 什么是ConfigMap

ConfigMap 是 Kubernetes(k8s)中用于存储非敏感配置数据的 API 对象 。它的核心作用是:将应用程序的配置(如环境变量、命令行参数、配置文件)与容器镜像解耦,实现"一次构建镜像,多环境部署"。

2. 为什么需要ConfigMap

在没有 ConfigMap 时,我们可能:

  • 把配置写死在代码或镜像里 → 换环境就要重新构建镜像
  • env 在 Pod 中硬编码 → 难维护、不安全

有了 ConfigMap:

  • 配置独立于镜像;
  • 同一个镜像可在 dev/test/prod 环境通过不同 ConfigMap 运行
  • 修改配置无需重建镜像(部分场景支持热更新)
  1. ConfigMap 能存什么?
  • 键值对(key-value) :如 database_url: mysql://...
  • 完整配置文件内容 :如 nginx.confapp.properties
  • 命令行参数片段
  • 非敏感数据 (⚠️ 敏感信息请用 Secret

🔒 注意:ConfigMap 不加密,不要存密码、密钥!

2.10.2 ConfigMap创建

方法 1:从字面量创建(适合少量 key-value)

复制代码
kubectl create configmap app-config \
  --from-literal=log_level=info \
  --from-literal=api_url=https://api.example.com

方法 2:从文件创建(适合配置文件)

复制代码
# 将 nginx.conf 文件内容存入 ConfigMap
kubectl create configmap nginx-config --from-file=nginx.conf

方法 3:从 YAML 文件定义(推荐,可版本控制)

复制代码
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  log_level: "info"
  api_url: "https://api.example.com"
  app.properties: |
    server.port=8080
    feature.enabled=true

2.10.3 ConfigMap使用

方式 1:作为环境变量

复制代码
env:
- name: LOG_LEVEL
  valueFrom:
    configMapKeyRef:
      name: app-config
      key: log_level

方式 2:作为容器启动命令参数

复制代码
args: ["--log-level", "$(LOG_LEVEL)"]
env:
- name: LOG_LEVEL
  valueFrom:
    configMapKeyRef:
      name: app-config
      key: log_level

方式 3:挂载为 Volume(适合配置文件)

复制代码
volumes:
- name: config-volume
  configMap:
    name: app-config

volumeMounts:
- name: config-volume
  mountPath: /etc/config   # 文件会出现在此目录下

挂载后:

  • /etc/config/log_level 内容是 info
  • /etc/config/app.properties 是完整配置文件

热更新支持吗?

  • 作为环境变量 :❌ Pod 创建时注入,修改 ConfigMap 不会更新已运行的 Pod
  • 挂载为 Volume :✅ 支持热更新(Kubelet 默认每 1 分钟同步一次)

💡 提示:若需立即生效,可滚动重启 Pod:

复制代码
kubectl rollout restart deployment/my-app

因此:ConfigMap 是 Kubernetes 的"配置中心",把非敏感配置从容器镜像中抽离出来,实现灵活、安全、可维护的应用部署。

2.11 Secret

2.11.1 Secret简介

1. 什么是Secret?

Secret 是 Kubernetes(k8s)中用于存储和管理敏感信息的 API 对象,比如密码、令牌(token)、SSH 密钥、TLS 证书等。

  1. 核心目标:避免将敏感数据硬编码在容器镜像、Pod 配置或代码中,从而提升安全性。

3. 与ConfigMap对比

特性 Secret ConfigMap
存储内容 敏感数据(密码、密钥、证书等) 非敏感配置(日志级别、URL、配置文件等)
存储方式 Base64 编码(不是加密!) 明文存储
安全性 更高(可配合 RBAC、加密 at rest) 无特殊保护
使用场景 数据库密码、API Key、私钥 应用配置、环境开关

⚠️ 注意:Secret 默认只是 Base64 编码,不是加密!

要真正加密,需启用 etcd 静态加密(Encryption at Rest)

4. Secret 能存什么?

  • 数据库用户名/密码
  • OAuth 访问令牌(Access Token)
  • Docker Registry 凭据(imagePullSecrets
  • TLS 证书和私钥(用于 HTTPS)
  • SSH 私钥
  • 任意需要保密的字符串

2.11.2 Secret创建

方法 1:从字面量创建(自动 Base64 编码)

复制代码
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='S3cr3tP@ss!'

方法 2:从文件创建(适合证书、密钥文件)

复制代码
kubectl create secret generic tls-secret \
  --from-file=tls.crt=./server.crt \
  --from-file=tls.key=./server.key

方法 3:通过 YAML 手动定义(需自己 Base64 编码)'

复制代码
# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=        # echo -n "admin" | base64
  password: UzNjcjN0UEBzcwEh  # echo -n "S3cr3tP@ss!" | base64

💡 type: Opaque 表示通用 Secret(最常用)

2.11.3 在Pod中使用Secret

1. 方式 1:作为环境变量(谨慎使用)

复制代码
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: password

风险 :环境变量可能被 ps、日志、调试工具泄露。仅用于兼容旧应用

方式 2:挂载为 Volume(✅ 推荐!)

复制代码
volumes:
- name: secret-volume
  secret:
    secretName: db-secret

volumeMounts:
- name: secret-volume
  mountPath: /etc/secrets
  readOnly: true

挂载后:

  • /etc/secrets/username 文件内容是 admin
  • /etc/secrets/password 文件内容是 S3cr3tP@ss!
  • 文件权限默认为 644,可通过 defaultMode 修改(如 0400

方式 3:拉取私有镜像(imagePullSecrets

复制代码
spec:
  imagePullSecrets:
  - name: regcred   # 这是一个 docker-registry 类型的 Secret
  containers:
  - name: my-app
    image: private-registry/my-app:latest

创建命令:

复制代码
kubectl create secret docker-registry regcred \
  --docker-server=my-registry.com \
  --docker-username=user \
  --docker-password=pass

总结:Secret 是 Kubernetes 专门用来安全传递敏感信息的机制,通过 Volume 挂载方式使用最安全,配合 RBAC 和 etcd 加密可满足生产安全要求。

2.12 Ingress

2.12.1 Ingress简介

1. Ingress是什么?

Ingress 是 Kubernetes 中管理外部访问集群内服务(Service)的 API 对象,主要用于 HTTP/HTTPS 流量的路由。

2. Ingress的核心作用?

将同一个公网 IP 和端口(如 80/443)的请求,根据 域名路径 转发到不同的后端 Service

  • shop.example.com → 电商服务
  • blog.example.com → 博客服务
  • example.com/api/ → API 服务

3. 注意事项

  • Ingress 本身不生效 ,需要部署 Ingress Controller(如 Nginx、Traefik、ALB)来实现实际流量转发。
  • 只支持 L7(应用层) ,不支持 TCP/UDP(那些用 Service 的 NodePortLoadBalancer)。

2.12.2 Ingress配置

1. 安装 Helm(只需要在master节点安装即可)

复制代码
# 下载 Helm 二进制文件(最新稳定版)
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3

# 给脚本执行权限
chmod +x get_helm.sh

# 运行安装脚本
sudo ./get_helm.sh

2. 验证安装

复制代码
helm version

# ✅ 正常输出类似:
version.BuildInfo{Version:"v3.14.0", GitCommit:"...", GitTreeState:"clean", GoVersion:"go1.21.5"}

3. 部署 Ingress Controller(在master节点操作,以 Nginx 为例)

复制代码
# 添加官方仓库(可选)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# 安装(Helm 方式)
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

等待几分钟,直到 Pod 和 LoadBalancer IP 就绪,执行以下命令验证

复制代码
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx   # 查看 EXTERNAL-IP

✅ 此时,Ingress Controller 已监听 80/443 端口,准备接收流量。

2.12.3 路由规则配置

  1. 首先确保有对应的Deployment和Service运行,假设部署的服务名为my-app

    my-app.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-app
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: my-app
    template:
    metadata:
    labels:
    app: my-app
    spec:
    containers:
    - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80

    apiVersion: v1
    kind: Service
    metadata:
    name: my-app-svc
    spec:
    selector:
    app: my-app
    ports:
    - protocol: TCP
    port: 80
    targetPort: 80

随后执行 kubectl apply -f my-app.yaml 进行部署

✅ 确保 my-app-svc 在 default 命名空间(或其他命名空间)中可访问。

  1. 创建Ingress资源

假设我们需要通过myapp.local进行访问

复制代码
# ingress-my-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
spec:
  rules:
  - host: myapp.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-svc
            port:
              number: 80

随后通过kubectl apply -f ingress-my-app.yaml 进行启用

  1. 随后在本机修改 /etc/hosts文件,添加

    <你的-master-node-IP> myapp.local

接着通过 curl http://myapp.local 验证是否成功

2.13 k8s网络模型

2.13.1 k8s网络中的通信类型

k8s网络中的主要通信类型有这四个

  • 同一Pod内的容器间通信
  • 各个Pod彼此间通信
  • Pod和Service间的通信
  • 集群外部流量和Servie之间的通信

2.13.2 k8s网络模型的核心要求

Kubernetes 对网络模型提出了以下基本要求,以支持上述通信类型:

  1. 所有 Pod 之间可直接通信
    无论是否在同一节点上,Pod 之间都应能通过 IP 地址直接访问,无需 NAT(网络地址转换)
  2. 所有节点与 Pod 之间可双向通信
    节点可以访问任意 Pod,Pod 也可以访问任意节点,且通信路径对称。
  3. 每个 Pod 拥有唯一的 IP 地址
    Pod 的 IP 在集群范围内是唯一的,生命周期内保持不变(直到被删除重建)。
  4. Service 提供稳定的虚拟 IP 和 DNS 名称
    Service 为一组 Pod 提供统一入口,即使后端 Pod 变化,Service 的 IP 和域名保持不变。

为实现这些要求,Kubernetes 本身不实现网络功能 ,而是依赖 CNI(Container Network Interface)插件,如 Flannel、Calico、Cilium 等。这些插件负责:

  • 为 Pod 分配 IP
  • 建立跨节点的网络隧道或路由
  • 实现 Service 的负载均衡(通常结合 kube-proxy)

💡 简单来说:Kubernetes 定义"要什么",CNI 插件决定"怎么做"

2.13.4 k8s各层网络模型

1. 同一 Pod 内的容器间通信

  • 通信形式 :通过 localhost(127.0.0.1) 直接通信。

  • 端口暴露

    • 容器共享同一个 网络命名空间(Network Namespace),因此共享 IP 和端口空间。
    • 一个容器监听 8080,另一个容器可通过 localhost:8080 访问。
  • 是否需要端口声明:不需要 Service 或暴露端口;只需在容器内正常监听即可。

  • ✅ 示例:

    复制代码
    containers:
      - name: app
        image: nginx
        ports: [{ containerPort: 80 }]
      - name: sidecar
        image: curl
        command: ["curl", "http://localhost"]  # 可直接访问 nginx

额外解释 :上述示例是 Sidecar(边车)模式 的 Pod 配置示例,主要有两个容器,主容器使用

镜像nginx和辅助容器使用镜像curl。辅助容器可以配合检查主容器的健康状态、日志情况等信息。

2. Pod 与 Pod 之间的通信

  • 通信形式 :通过 Pod IP + 容器端口 直接通信(跨节点也一样)。
  • 端口暴露
    • 每个 Pod 有唯一集群 IP(如 10.244.1.5)。
    • 目标 Pod 的容器必须在 containerPort 上监听(但该字段仅为文档说明,不强制暴露)。
  • 依赖组件:CNI 插件(如 Flannel)负责打通 Pod 跨节点路由。
  • 不能直接从集群外访问 Pod IP(除非使用 HostNetwork 或特殊路由)。
  • ✅ 示例:Pod A (10.244.1.5) 中运行 nginx:80 → Pod B 可直接 curl http://10.244.1.5

3. Pod 与 Service 之间的通信

  • 通信形式 :通过 Service 的 ClusterIP + Port 访问。

  • 端口暴露 (Service 定义中的关键字段):

    复制代码
    spec:
      ports:
        - port: 80          # Service 对外暴露的端口(其他 Pod 访问时用)
          targetPort: 8080  # 转发到后端 Pod 的实际端口
          protocol: TCP
    • port:Service 的虚拟端口(集群内通过 <ClusterIP>:port 访问)
    • targetPort:后端 Pod 容器实际监听的端口
  • 实现机制

    • kube-proxy 在每个节点上维护 iptables/ipvs 规则,将流量 DNAT 到后端 Pod。
    • DNS(CoreDNS)将 Service 名称解析为 ClusterIP。
  • ✅ 示例:my-app-svc.default.svc.cluster.local:80 → 被解析为 10.96.123.45:80 → 转发到某个 Pod 的 8080 端口。

4. 集群外部 ↔ Service 的通信

有三种主要方式,对应不同端口暴露策略:

方式 端口暴露形式 通信入口 适用场景
NodePort 在每个节点的 固定高端口(30000--32767) 上监听 http://<任意NodeIP>:<NodePort> 测试、裸金属集群
LoadBalancer 云厂商创建外部 LB,分配公网 IP http://<EXTERNAL-IP> 公有云环境
Ingress 复用 80/443 端口,基于 HTTP Host/Path 路由 http://myapp.example.com 生产 Web 应用
  • Ingress 特别说明
    • Ingress Controller 本身是一个 Pod + Service(通常为 NodePort 或 LoadBalancer)
    • 外部流量 → NodePort/LoadBalancer → Ingress Controller Pod → 根据规则转发到后端 Service

5. 总结

通信层级 源 → 目标 使用地址 端口类型 是否需 CNI 是否需 kube-proxy
容器 ↔ 容器(同 Pod) localhost 127.0.0.1 容器端口
Pod ↔ Pod Pod IP Pod IP 容器端口
Pod ↔ Service ClusterIP Service IP Service.port
外部 ↔ Service NodeIP / EXTERNAL-IP 节点 IP / 公网 IP NodePort / 80,443 ✅(间接)

2.14 k8s的工作流程

Kubernetes 采用 声明式 API + 控制循环 的架构,其基本工作流程如下:

  1. 用户提交期望状态
    用户通过 kubectl 或 YAML 文件向 API Server 提交资源定义(如 Deployment、Service 等),声明"希望系统达到什么状态"(例如:运行 3 个 Nginx Pod)。
  2. API Server 接收并验证请求
    • 所有操作必须经过 API Server(集群唯一入口)。
    • API Server 进行身份认证、授权和合法性校验。
  3. 持久化到 etcd
    验证通过后,API Server 将资源对象的期望状态 写入 etcd(分布式键值数据库),作为集群的"唯一真相源"。
  4. 控制器(Controller)监听变化
    • Controller Manager 中的各类控制器(如 Deployment Controller、ReplicaSet Controller)持续监听 etcd 中的资源变化。
    • 一旦发现实际状态 ≠ 期望状态(如 Pod 数量不足),控制器会创建/删除资源以"调和(Reconcile)"差异。
  5. 调度器(Scheduler)分配节点
    • 对于新创建的 Pod,Scheduler 根据资源需求、节点标签、亲和性等策略,选择一个合适的 Worker 节点
    • 调度结果写回 etcd。
  6. Kubelet 执行容器启动
    • 目标节点上的 Kubelet(节点代理)从 API Server 获取分配给本节点的 Pod 信息。
    • Kubelet 调用容器运行时(如 containerd 或 Docker)拉取镜像、创建并启动容器。
  7. 持续监控与自愈
    • Kubelet 持续上报 Pod 状态到 API Server。
    • 控制器不断比对"实际状态" vs "期望状态",自动修复异常(如重启崩溃的 Pod、补充缺失副本)。
  8. 服务发现与访问(可选)
    • kube-proxy 在每个节点上维护网络规则,实现 Service 的负载均衡。
    • 外部流量可通过 Ingress、NodePort 或 LoadBalancer 访问应用。

🔄 总结一句话:

用户声明"要什么" → Kubernetes 自动确保"是什么"始终等于"要什么"

3. 结语

通过本文的系统梳理,我们从 Docker 容器技术的基础概念、核心命令、镜像构建与私有仓库搭建,逐步深入到 Kubernetes 的集群部署、资源管理、网络通信与存储机制。Docker 为我们提供了轻量、可移植的应用封装能力,而 Kubernetes 则在此基础上实现了大规模容器化应用的自动化部署、弹性伸缩与自愈管理。二者相辅相成,共同构成了现代云原生应用的基石。

掌握这些知识,不仅意味着你能够高效地打包和运行单个服务,更具备了在生产环境中构建高可用、可扩展、易维护的分布式系统的能力。技术之路永无止境,但每一步扎实的实践,都是通向云原生世界的坚实阶梯。愿你在容器与编排的世界中,持续探索,不断进阶

相关推荐
努力也学不会java2 小时前
【Spring Cloud】 服务注册/服务发现
人工智能·后端·算法·spring·spring cloud·容器·服务发现
孤岛悬城2 小时前
64 K8s安全机制
kubernetes·云计算·k8s
fanruitian2 小时前
centos 安装minikube
docker·kubernetes·centos
Justin_192 小时前
K8s常见问题(4)
云原生·容器·kubernetes
噎住佩奇2 小时前
单节点 K8s 集群上部署 Longhorn
云原生·容器·kubernetes
编码如写诗2 小时前
【信创-k8s】麒麟V11使用containerd2.1.5全离线安装k8s1.32.11+KubeSphere
云原生·容器·kubernetes
徐先生 @_@|||2 小时前
YARN、YARN/K8s混合模式与Kubernetes分析对比
docker·云原生·容器·kubernetes
这周也會开心2 小时前
Docker Compose容器化部署
运维·docker·容器
Justin_193 小时前
K8s常见问题(5)
云原生·容器·kubernetes