K8s 集群环境搭建 - yaml 版本(一)

K8s 集群环境搭建 - yaml 版本(一)

文章目录

  • [K8s 集群环境搭建 - yaml 版本(一)](#K8s 集群环境搭建 - yaml 版本(一))
  • [一、k8s 集群架构](#一、k8s 集群架构)
  • 二、环境规划
    • [1. 集群类型](#1. 集群类型)
    • 2.环境准备
    • [3. k8s 集群搭建](#3. k8s 集群搭建)
  • [三、k8s 命令](#三、k8s 命令)
    • [1. 操作 NameSpace](#1. 操作 NameSpace)
    • [2. 操作 Pod](#2. 操作 Pod)
    • [3. 操作 Deployment](#3. 操作 Deployment)
    • [4. 操作 Service](#4. 操作 Service)
    • [5. 操作 Ingress](#5. 操作 Ingress)
    • [6. 操作 ConfigMap](#6. 操作 ConfigMap)
    • [7. 操作 Secret](#7. 操作 Secret)
  • [四、安装 harbor](#四、安装 harbor)
  • [五、配置 StorageClass](#五、配置 StorageClass)
    • [1. 集成 Minio](#1. 集成 Minio)
    • [2. 集成 NFS](#2. 集成 NFS)

一、k8s 集群架构

  • 工作方式:

    • N Master Node + N Worker Node:N主节点+N工作节点; N>=1,我们这里采用 1主节点 + 2工作节点的方式。
  • 组织架构图:

  • Control Plane(控制平面):是集群的 "大脑",负责决策和管理整个集群的状态。它由多个核心组件组成,每个组件各司其职又相互协作。

    • 作用:
      • 维护集群的期望状态。
      • 处理用户提交的配置。
      • 做出调度决策。
      • 监控并自动恢复异常。
  • Control Plane(控制平面)组件包含:

    • kube-apiserver:所有操作的统一入口,提供 RESTful API。

      • 唯一与 etcd 直接交互的组件。
      • 提供认证、授权、准入控制机制。
      • 支持资源的增删改查和监听。
      • 可水平扩展以提高性能。
      • 工作流程。
      • 接收客户端请求。
      • 验证请求合法性。
      • 读取 / 更新 etcd 中的数据。
      • 返回响应。
    • etcd:集群的数据库,存储所有集群状态信息。

      • 高可用的键值存储系统,基于 Raft 协议保证一致性,存储包括:配置信息、Pod 状态、Service 信息等。
    • kube-scheduler:负责 Pod 的调度决策。

      • 工作流程:预选 (Predicate):筛选出满足 Pod 基本要求的节点、优选 (Priority):对候选节点打分排序、绑定 (Bind):将 Pod 分配给得分最高的节点。
    • 调度的考量因素有:资源需求(CPU、内存、GPU 等)、节点亲和性与反亲和性、Pod 亲和性与反亲和性、污点与容忍度、数据局部性、优先级与抢占。

    • kube-controller-manager:运行各种控制器进程,维持集群状态。

      • 主要控制器:
        • 节点控制器:监控节点健康状态。
        • 副本控制器:维持 Pod 副本数量。
        • 端点控制器:管理 Service 与 Pod 的映射关系。
        • 服务账号控制器:管理服务账号和令牌。
        • 命名空间控制器:处理命名空间的生命周期。
        • 垃圾回收控制器:清理依赖资源。
    • cloud-controller-manager (可选):与云服务提供商集成。

  • Control Plane(控制平面)组件间协作流程,以创建一个 Deployment 为例:

    1. kubectl apply -f deployment.yaml 发送请求到 kube-apiserver
    2. API Server 将配置存入 etcd
    3. Deployment 控制器发现新资源,创建 ReplicaSet
    4. ReplicaSet 控制器创建相应数量的 Pod
    5. Scheduler 为每个 Pod 选择合适的节点
    6. 目标节点的 kubelet 接收到 Pod 配置并启动容器
    7. 所有状态变更通过 API Server 更新到 etcd
  • Node 组件包含:

    • kubelet:是运行在每个节点上的代理程序,负责让 Worker Node 与控制平面进行通信,主要是与 API Server 通信。它从 API Server 接收关于 Pod 的定义,并与容器运行时交互,以在 Pod 上运行相关容器,还承担着对运行容器的 Pod 进行资源监控、健康检查的职责。
    • kube-proxy:是一个网络代理,运行在控制面和 Worker 节点上,职责是动态更新和维护节点上的所有网络规则,抽象了 Pod 的网络细节,并将连接请求转发到 Pod 中的容器,通过 Service API 对象实现用户定义的转发规则。

二、环境规划

1. 集群类型

  • Kubernetes 集群大致分为两类:一主多从和多主多从。

    • 一主多从(单 master ):一个 Master 节点和多台 Node 节点,搭建简单,但是有单机故障风险,适合用于测试环境。

    • 多主多从(高可用):多台 Master 节点和多台 Node 节点,搭建麻烦,安全性高,适合用于生产环境。

  • 本次搭建是一主两从类型的集群。

2.环境准备

  1. Kubernetes 有多种部署方式,目前主流的方式有 kubeadm 、minikube 、二进制包。本次我们采用的是 kubeadm 安装的方式。

    • minikube:一个用于快速搭建单节点的 Kubernetes 工具。
    • kubeadm:一个用于快速搭建Kubernetes 集群的工具(可以用于生产环境)。
    • 二进制包:从官网上下载每个组件的二进制包,依次去安装(建议生产环境使用)。
  2. 三台云服务器:需要选择相同地域的服务器,如上海。不同地域的云服务器内网不互通,而 k8s 集群中,master 连接 woker 默认采用的内网连接,比如连接 master 连接 woker 的 10250 端口,通过此端口获取节点状态,下发容器操作指令等。

    角色 IP地址 操作系统 配置 hostname
    Master 192.168.245.20 veLinux 2.0 CentOS Compatible 64 bit 8核CPU,16G内存,40G硬盘 k8s-master
    Node1 192.168.245.19 veLinux 2.0 CentOS Compatible 64 bit 8核CPU,16G内存,40G硬盘 k8s-node1
    Node2 192.168.0.2 veLinux 2.0 CentOS Compatible 64 bit 4核CPU,8G内存,40G硬盘 k8s-node2
  3. 配置 k8s 集群的安全组。首先需要知道 k8s 集群中哪些端口提供。并且由谁提供。(其中一些端口视情况而定)

    节点角色 端口号 协议 方向 作用说明 必要性
    Master 节点
    6443 TCP 入站(Worker 访问) Kubernetes API Server 端口,所有集群组件(kubelet、kube-proxy 等)通过此端口与 Master 通信 必须开放
    2379-2380 TCP 入站(Master 内部 / 集群) etcd 数据库端口(2379 用于客户端通信,2380 用于集群节点间数据同步) 必须开放(单 Master 至少开放 2379)
    10250 TCP 入站(Worker 访问) kubelet 端口(Master 节点自身的 kubelet,用于节点状态上报) 必须开放
    10251 TCP 入站(内部) kube-scheduler 端口(调度器组件通信) 必须开放
    10252 TCP 入站(内部) kube-controller-manager 端口(控制器管理器通信) 必须开放
    10259 TCP 入站(内部) kube-scheduler 安全端口(HTTPS 通信) 必须开放
    10260 TCP 入站(内部) kube-controller-manager 安全端口(HTTPS 通信) 必须开放
    Worker 节点
    10250 TCP 入站(Master 访问) kubelet 端口,Master 通过此端口管理节点和 Pod(如调度、健康检查) 必须开放
    30000-32767 TCP 入站(外部访问) NodePort 类型 Service 暴露的端口范围,用于外部访问集群内服务(如应用端口) 按需开放(根据业务需求)
    10255 TCP 入站(可选) kubelet 只读端口(已过时,建议关闭,或仅用于调试) 不推荐开放
    10256 TCP 入站(可选) kube-proxy 健康检查端口 必须开放
    所有节点通用
    8472 UDP 网络插件(如 Flannel)的 VXLAN 通信端口(Calico 可能使用 4789) 必须开放(根据网络插件)
  4. 版本说明:

    • k8s 选择的版本是 1.24.9。k8s 1.24 版本之后正式移除了内置的 dockershim 组件。dockershim 是过去 Kubernetes 用于直接对接 Docker 引擎的桥接模块,由于 Docker 本身不原生支持 Kubernetes 的 CRI(容器运行时接口),需要通过 dockershim 进行协议转换。
    • 移除后,Kubernetes 不再直接支持 Docker 作为容器运行时 ------ 但这并不意味着完全不能用 Docker,而是需要额外的兼容层。但需要通过 cri-dockerd 工具(Docker 官方提供的 CRI 兼容层),实现 Docker 与 Kubernetes CRI 的对接。
    • 我这里也并有选择 cri-docker,而是采用了containerd。也是官方推荐的使用方式。
    • 选择的 containerd 版本为:containerd.io-1.6.15
    • Kubernetes 1.24.9 对 containerd.io(containerd 的官方包名)有明确的版本要求,需要满足 1.4.12+ 及以上版本,但建议使用更稳定的 1.5.x 或 1.6.x 版本(不建议使用过高版本如 1.7.x,可能存在兼容性风险)。根据 Kubernetes 官方文档,1.24 版本兼容的 containerd 最低版本为 1.4.12,推荐使用:1.5.x 系列(如 1.5.16+,稳定性经过验证),1.6.x 系列(如 1.6.15+,支持更多新特性)

3. k8s 集群搭建

  • 安装 k8s 之前需要将 swap 关闭。通过 free -m 可查看,需要 total、used、free 都是0。需要执行如下命令:

    java 复制代码
    # 将 SELinux 设置为 permissive 模式(相当于将其禁用)
    sudo setenforce 0
    sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
    
    #关闭swap
    swapoff -a  
    sed -ri 's/.*swap.*/#&/' /etc/fstab
  • 配置国内源,这里选择的阿里云:

    java 复制代码
    cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
    enabled=1
    gpgcheck=0
    repo_gpgcheck=0
    gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
    EOF
  • 安装 kubeadm kubectl kubelet (可以指定版本)

    java 复制代码
    yum -y install kubeadm-1.24.9 kubectl-1.24.9 kubelet-1.24.9
  • 安装 containerd

    java 复制代码
    wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
    sudo yum install -y containerd.io-1.6.15
  • 修改 containerd 配置。

    • 初始化 containerd 配置

      java 复制代码
      sudo containerd config default > /etc/containerd/config.toml
    • 修改 sandbox_image 和 SystemCgroup 配置:sudo vim /etc/containerd/config.toml

      java 复制代码
      registry.aliyuncs.com/google_containers/pause:3.9
    • 重启 containerd 使配置生效:

      java 复制代码
      sudo systemctl restart containerd
  • 加载ipvs模块:

    java 复制代码
    # 加载ipvs模块
    modprobe br_netfilter
    modprobe -- ip_vs
    modprobe -- ip_vs_sh
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- nf_conntrack_ipv4
    
    
    # 验证ip_vs模块
    lsmod |grep ip_vs
    ip_vs_wrr              12697  0 
    ip_vs_rr               12600  0 
    ip_vs_sh               12688  0 
    ip_vs                 145458  6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
    nf_conntrack          139264  2 ip_vs,nf_conntrack_ipv4
    libcrc32c              12644  3 xfs,ip_vs,nf_conntrack
    
    # 内核文件 
    cat <<EOF >  /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward=1
    vm.max_map_count=262144
    EOF
    
    # 生效并验证内核优化
    sysctl -p /etc/sysctl.d/k8s.conf
  • 修改 crictl下载镜像 默认端点:

    java 复制代码
    cat > /etc/crictl.yaml <<EOF
    runtime-endpoint: unix:///var/run/containerd/containerd.sock
    image-endpoint: unix:///var/run/containerd/containerd.sock
    timeout: 0
    debug: false
    pull-image-on-create: false
    EOF
    • 验证 运行crictl images list命令,不再报错 即可。
  • 初始化 master 节点:

    java 复制代码
    kubeadm init \
    	--apiserver-advertise-address=192.168.245.20 \
    	--control-plane-endpoint=k8s-master \
    	--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
    	--kubernetes-version v1.24.9 \
    	--service-cidr=10.96.0.0/16 \
    	--pod-network-cidr=192.168.0.0/16
  • 成功初始化:通过下图进行操作。woker 和 master 节点也可通过下图进行加入集群。

    java 复制代码
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
  • 如果令牌过期了,可重新获取令牌:

    java 复制代码
    kubeadm token create --print-join-command
  • 在 /opt 下载calico的yaml配置文件

    java 复制代码
    curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/calico.yaml
    sed -i 's/docker.io/swr.cn-north-4.myhuaweicloud.com\/ddn-k8s\/docker.io/g' calico.yaml
  • 构建镜像:

    java 复制代码
    kubectl apply -f calico.yaml
  • 可通过命令查看pod启动情况:一个 master 和两个 woker

    java 复制代码
    kubectl get pod -A
  • 如果pod启动失败,可通过命令查看日志。

    java 复制代码
    kubectl describe po [pod name] -n [namespace]
  • 如有问题,可参考我前面整理的文章,整理了很多错误的情况,踩了很多坑

三、k8s 命令

1. 操作 NameSpace

  • 获取所有 NameSpace

    java 复制代码
    kubectl get ns
  • 获取所有 NameSpace 的 pod

    java 复制代码
    kubectl get pods -A
  • 获取默认 NameSpace【default】的 pod

    java 复制代码
    kubectl get pods
  • 获取指定 NameSpace 的 pods

    java 复制代码
    kubectl get pod -n [NameSpace]
  • 删除指定 NameSpace(默认 default 不可删除)

    java 复制代码
    kubectl delete ns [NameSpace]
  • 创建 NameSpace

    java 复制代码
    kubectl create ns [NameSpace]

2. 操作 Pod

  • 查看 pod (默认 NameSpace 为 default 下的 pod)

    java 复制代码
    kubectl get pods
  • 查看 pod 详细信息

    java 复制代码
    kubectl get pod -owide
  • 查看指定 NameSpace 下的 pod

    java 复制代码
    kubectl get pod -n [NameSpace]
  • 查看 pod 的启动情况:

    java 复制代码
    kubectl describe pod [podName]
  • 通过配置文件的方式创建 pod

    java 复制代码
    kubectl apply -f [xx.yaml]
  • 删除通过配置文件创建的 pod

    java 复制代码
    kubectl delete -f [xx.yaml]
  • 直接删除 pod

    java 复制代码
    kubectl delete pod [podName] -n [namespace]
  • 强制删除 pod

    java 复制代码
    kubectl delete pod <pod-name> -n <namespace> --grace-period=0 --force
  • 查看 pod 的运行日志

    java 复制代码
    kubectl logs [podName]
  • 进入 pod

    java 复制代码
    kubectl exec -it [podName] -- /bin/bash

3. 操作 Deployment

  • 使 Pod 拥有多副本、自愈、扩缩容等能力。

  • 创建 Deployment 并指定容器

    java 复制代码
    kubectl create deployment [deployName] --image=[imageName]
  • 查看 deployment

    java 复制代码
    kubectl get [deployName]
  • 创建 deployment 并指定副本

    java 复制代码
    kubectl create deployment [deployName] --image=[imageName] --replicas=[count] 
  • 删除 deployment

    java 复制代码
    kubectl delete deploy [deployName]
  • 对 deployment 进行扩缩容

    java 复制代码
    kubectl scale deploy/[deployName] --replicas=[count]
  • 也可修改配置文件,从而修改 deployment

    java 复制代码
    kubectl edit deploy [deployName]
  • 对 deployment 中某个镜像进行滚动更新

    java 复制代码
    kubectl set image deploy/[deployName] nginx=nginx:1.16.1 --record
  • 滚动更新过程,查看整个过程

    java 复制代码
    kubectl get pod -w
  • 查看 deployment 历史版本记录

    java 复制代码
    kubectl rollout history deployment/[deployName]
  • 查看某个历史详情

    java 复制代码
    kubectl rollout history deployment/[deployName] --revision=[version]
  • 回滚到上个版本

    java 复制代码
    kubectl rollout undo deployment/[deployName]
  • 回滚到指定版本

    java 复制代码
    kubectl rollout undo deployment/[deployName] --to-revision=[version]

4. 操作 Service

  • Pod 的服务发现与负载均衡。

  • 默认暴露方式为 ClusterIP:只能在集群内访问。

  • NodePort:也可集群外访问,即任意一台集群内机器的IP 都可以在外用来访问服务。

  • 设置 Service 服务端口,映射 Deployment 端口,默认 type=ClusterIP,也可指定 type=NodePort

    java 复制代码
    kubectl expose deploy [deployName] --port=[servicePort] --target-port=[deployPort] --type=ClusterIP
  • 该配置对应 yaml 写法为:

    yaml 复制代码
    apiVersion: v1
    kind: Service
    metadata:
    	labels:
    		app: [deployName]
    	name:	[deployMent]
    spec:
    	selector:
    		app: my-dep
    	ports:
    	-	port: 8000
    		protocal: TCP
    		targetPort: 80
  • 其中 label 为标签,可通过命令查看 pod 所属标签

    java 复制代码
    kubectl get pod --show-labels
  • 获取 service

    java 复制代码
    kuebctl get svc

5. 操作 Ingress

  • Service 的统一网关入口

  • 创建 ingress

    java 复制代码
    kubectl apply -f xxx.yaml
  • 获取 ingress

    java 复制代码
    kubectl get ingress / kubectl get ing
  • 修改 ingress

    java 复制代码
    kubectl edit ing [ingressName]

6. 操作 ConfigMap

  • 查看所有 ConfigMap,默认 namespace 为 default

    java 复制代码
    kubectl get configmaps -n [namespace]
    // 简写
    kubectl get cm -n [namespace]
  • 查看 ConfigMap 的详细信息(包括数据内容)

    java 复制代码
    kubectl describe configmap [configmap名称]
    # 示例
    kubectl describe cm app-config
  • 以 YAML/JSON 格式查看完整定义

    java 复制代码
    # YAML 格式(常用)
    kubectl get configmap [configmap名称] -o yaml
    
    # JSON 格式
    kubectl get configmap [configmap名称] -o json
  • 查看其他命名空间的 ConfigMap

    java 复制代码
    kubectl get cm -n [namespace]
    # 示例:查看 kube-system 命名空间的 ConfigMap
    kubectl get cm -n kube-system
  • 过滤查看特定标签的 ConfigMap

    java 复制代码
    kubectl get cm -l [标签键=标签值]
    # 示例:查看标签为 app=nginx 的 ConfigMap
    kubectl get cm -l app=nginx

7. 操作 Secret

  • 查看命名空间下的所有 Secret(快速列表)

    java 复制代码
    kubectl get secrets -n [nameSpace]
  • 查看指定 Secret 的详细信息(包含编码后的内容)

    java 复制代码
    kubectl describe secret mysql-secret -n [nameSpace]
  • 查看 Secret 中编码后的具体值(需解码),Secret 的值存储为 base64 编码,若需查看明文(谨慎操作!),可使用以下命令解码:查看所有键的明文

    java 复制代码
    # 以 YAML 格式输出并解码所有值
    kubectl get secret mysql-secret -n [nameSpace] -o yaml | grep -v '^  apiVersion\|^  kind\|^  metadata' | awk '{print $0}' | base64 -d
  • 查看指定键的明文(推荐,更安全):

    java 复制代码
    # 查看 root-password 的明文
    kubectl get secret mysql-secret -n [nameSpace] -o jsonpath='{.data.root-password}' | base64 -d && echo

四、安装 harbor

  • 使用Harbor 私有镜像仓库。Harbor 是基于 Docker 容器运行的,它的安装和运行依赖于 Docker 环境。同时,还需要安装 Docker Compose,用于管理 Harbor 的多个容器组件。 为什么需要私有镜像仓库?

    • 提高镜像下载速度。
    • 节省网络带宽。
    • 确保镜像安全性。
    • 便于管理公司内部的容器镜像。
  • 从 Docker 20.10.3 版本开始,Docker 已经内置了 Compose 功能(通过 docker compose 命令),无需单独安装。你可以直接验证:docker compose version安装 docker

  • 下载 harbor:

    java 复制代码
    wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-offline-installer-v2.11.1.tgz
  • 解压安装包:

    java 复制代码
    tar xvf harbor-offline-installer-v2.8.3.tgz
  • 进入 harbor 后复制配置文件:

    java 复制代码
    cd harbor
    cp harbor.yml.tmpl harbor.yml
  • 配置 host 映射 vim /etc/hosts

    java 复制代码
    14.103.138.45 mortal.harbor.com
  • 编辑 harbor.yml:

    java 复制代码
    hostname: mortal.harbor.com
    # 修改 https 相关配置(使用 https)
    https:
      port: 443
      certificate: /data/cert/mortal.harbor.com.crt
      private_key: /data/cert/mortal.harbor.com.key
    
    # 修改管理员密码(建议修改)
    harbor_admin_password: Harbor131413
    
    # 修改数据存储路径(可选)
    data_volume: /data/harbor
    
    # 修改数据库密码(建议修改)
    database:
      password: root123
  • 启用 HTTPS,需要生成 SSL 证书:

    java 复制代码
    # 创建证书目录
    mkdir -p /data/cert
    cd /data/cert
    
    # 生成私钥
    openssl genrsa -out ca.key 4096
    
    # 生成证书
    openssl req -x509 -new -nodes -sha512 -days 3650 \
      -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=mortal.harbor.com" \
      -key ca.key \
      -out ca.crt
    
    # 生成服务器证书
    openssl genrsa -out mortal.harbor.com.key 4096
    openssl req -sha512 -new \
      -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=mortal.harbor.com" \
      -key mortal.harbor.com.key \
      -out mortal.harbor.com.csr
    
    # 生成 x509 v3 扩展文件
    cat > v3.ext <<-EOF
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1=mortal.harbor.com
    DNS.2=harbor
    DNS.3=hostname
    EOF
    
    # 使用 v3.ext 文件为域名生成证书
    openssl x509 -req -sha512 -days 3650 \
      -extfile v3.ext \
      -CA ca.crt -CAkey ca.key -CAcreateserial \
      -in mortal.harbor.com.csr \
      -out mortal.harbor.com.crt
  • 安装 Harbor:

    java 复制代码
    ./install.sh
    • harbor(v2.10) 对部分组件做了调整,主要变化如下:
      • 必须设置有效的主机名:不能使用 localhost 或 127.0.0.1,因为 Harbor 需要被外部客户端访问(如其他服务器、开发机等)
      • 正确配置方式:在 harbor.yml 中设置为服务器的实际 IP 地址(如 192.168.1.100)或可解析的域名(如 harbor.example.com)。
      • --with-trivy:仍支持此参数,若需要启用漏洞扫描功能,安装时需显式指定(因为 Trivy 不再默认安装)。`./install.sh --with-trivy # 启用漏洞扫描
      • --with-notary--with-chartmuseum:这两个参数已被移除,因为对应的组件(Notary 镜像签名、ChartMuseum Helm 仓库)已被弃用。镜像签名功能:Harbor 新版本推荐使用内置的 Cosign 替代 Notary,Helm 仓库功能:Harbor 已原生支持 Helm Chart 管理,无需依赖 ChartMuseum。
  • 安装成功:

  • 访问:https://ip/account/sign-in:


  • 这时候还需要再docker 上配置 harbor 的 SSL 证书,不然 docker push 推送镜像会报错如下错误:

    java 复制代码
    docker pull nginx:latest
    # 标记镜像
    docker tag nginx:latest mortal.harbor.com/library/nginx:v1
  • 尝试推送镜像至 harbor,报如下错误:

    java 复制代码
    docker push mortal.harbor.com/library/nginx:v1
  • 配置 SSL 证书:

    java 复制代码
    # 创建 Harbor 域名对应的证书目录(域名需与 Harbor 配置一致)
    sudo mkdir -p /etc/docker/certs.d/mortal.harbor.com
    # 复制 ca.crt
    cp ca.crt /etc/docker/certs.d/mortal.harbor.com/
  • 重启 docker

    java 复制代码
    # 重启 Docker
    systemctl restart docker
    # 重启所有容器
    docker restart $(docker ps -aq)
  • 登录 harbor:

    java 复制代码
    docker login mortal.harbor.com
  • 再次推送:成功

    java 复制代码
    docker push mortal.harbor.com/library/nginx:v1


  • 如果修改了 harbor.yml 配置文件,可通过如下命令生效:

    java 复制代码
    # 执行 prepare 脚本,根据 harbor.yml 生成新配置
    sudo ./prepare
    # 停止当前运行的 Harbor 服务
    sudo docker compose down
    # 启动 Harbor 服务(加载新配置)
    sudo docker compose up -d
  • 好需要配置 k8s 能够从 Harbor 行拉取镜像。主要配置 用户密码 和 ca.crt。

  • 配置 Harbor 的用户密码用于 k8s 拉取镜像。

    • 创建 secret:记住 secret 名称为:harbor-creds 。 在编写 yaml 文件拉取镜像时需要用到

      java 复制代码
      kubectl create secret docker-registry harbor-creds \
        --docker-server=mortal.harbor.com \
        --docker-username=admin \
        --docker-password=Harbor131413 \
        --namespace=mortal-system
    • 使用:

      java 复制代码
      imagePullSecrets: 
            - name: harbor-creds
    • 也可查看写创建的 secret:

  • 我们的 image 地址写的是 Harbor 的地址,且用的域名。在 k8s 创建 pod 时,可能会分配给 worker 节点进行创建并启动,所以需要再 k8s 集群所有节点上都需要设置 Harbor 域名的映射(/etc/hosts)。

  • 配置 ca.crt 证书,我们的k8s 版本是 1.24+,使用的是 containerd,所以需要所有k8s节点都改它的配置信息。

    • 在上述安装 Harbor 的时候,我们创建了 ca.crt 证书,我们需要将它给引用到 containerd 的配置中。

    • 查看 ca.crt 位置:

      java 复制代码
      find / -name "ca.crt" | grep -i harbor
    • 复制到我们新建的文件夹中,方便后续引用:

      java 复制代码
      sudo mkdir -p /etc/containerd/certs.d/mortal.harbor.com/
      cp /etc/docker/certs.d/mortal.harbor.com/ca.crt /etc/containerd/certs.d/mortal.harbor.com/
    • containerd 配置中引用:

      java 复制代码
      vi /etc/containerd/config.toml
      java 复制代码
      [plugins."io.containerd.grpc.v1.cri".registry.configs."mortal.harbor.com"]
          [plugins."io.containerd.grpc.v1.cri".registry.configs."mortal.harbor.com".tls]
            ca_file = "/etc/containerd/certs.d/mortal.harbor.com//ca.crt"
    • 效果如下:

    • 重启 containerd:

      java 复制代码
      systemctl restart containerd
    • 上述 所有 k8s 节点都需要配置。

五、配置 StorageClass

  • k8s 集群默认是没有 PV 的,需要我们自己编写 PV 配置文件,可以采用本地存储或者DFS。我这里采用 DFS 和 Minio 的结合使用。 DFS 提供 数据库、日志存储。 Minio 提供 文件存储。两种存储区别如下:
对比维度 MinIO NFS(Network File System)
存储类型 「对象存储」(Object Storage) 「文件存储」(File Storage)
核心协议 兼容 S3 API(HTTP/HTTPS) NFS 协议(基于 TCP/UDP)
数据组织方式 以「对象」为单位(Key-Value 结构,包含数据 + 元信息) 以「文件 / 目录」为单位(树形目录结构,如 /data/logs/2024.log)
访问方式 通过 API 调用(如 putObject/getObject) 像本地磁盘一样挂载(mount -t nfs),支持 POSIX 语义(如文件锁、权限控制)
适用数据 非结构化数据(图片、日志、备份、视频等) 结构化 / 半结构化数据(配置文件、应用日志、共享代码等需目录管理的数据)
K8s 集成方式 需通过 CSI 驱动(如 ch.ctrox.csi.s3-driver)模拟文件系统挂载,或直接通过 API 访问 需通过 nfs-client-provisioner 提供动态 PVC,支持直接挂载为文件系统

1. 集成 Minio

  • 使用 Minio 作为存储分为如下步骤:

    1. 安装 Minio

    2. 下载集成 Minio 所需的驱动并部署。

    3. 编写 PVC,测试 Minio 是否可用。

  • 在 Kubernetes 中,CSI 提供了一种标准的方式,用于与第三方存储供应商(如 NFS、AWS EFS、Ceph、GlusterFS、Minio 等)对接,实现存储卷的创建、挂载、卸载等操作。所以我们需要先安装 CSI。其中的镜像需要改成国内的,不然可能无法下载。或者安装这里的 CSI 应该也可以,未亲测

    • provisioner.yaml:

      java 复制代码
      registry.cn-hangzhou.aliyuncs.com/google_containers/csi-provisioner:v3.5.0
      swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ctrox/csi-s3:v1.2.0-rc.2
    • attacher.yaml:

      java 复制代码
      image: registry.cn-hangzhou.aliyuncs.com/google_containers/csi-attacher:v4.3.0
    • csi-s3.yaml:

      java 复制代码
      registry.cn-hangzhou.aliyuncs.com/google_containers/csi-node-driver-registrar:v2.8.0
      swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ctrox/csi-s3:v1.2.0-rc.2
  • 安装之后查看启动情况:kubectl get pod -A

  • 创建一个 Secret,存储 MinIO 集群的访问信息(用于 CSI 驱动连接 MinIO)。minio-secret.yaml,并进行部署:kubectl apply -f minio-secret.yaml

    java 复制代码
    # minio-secret.yaml
    apiVersion: v1
    kind: Secret
    metadata:
      name: minio-secret
      # Namespace depends on the configuration in the storageclass.yaml
      namespace: mortal-system
    stringData:
      # minio 的用户名密码
      accessKeyID: root
      secretAccessKey: root13141314
      # For AWS set it to "https://s3.<region>.amazonaws.com"
      endpoint: http://192.168.245.20:9000
      # If not on S3, set it to ""
      region: ""
  • 创建 PV:minio-storageclass.yaml,并进行部署:kubectl apply -f minio-storageclass.yaml。

    java 复制代码
    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: minio-sc
    provisioner: ch.ctrox.csi.s3-driver
    parameters:
      mounter: geesefs
      # you can set mount options here, for example limit memory cache size (recommended)
      options: "--memory-limit 1000 --dir-mode 0777 --file-mode 0666"
      # to use an existing bucket, specify it here:
      #bucket: some-existing-bucket
      csi.storage.k8s.io/provisioner-secret-name: minio-secret
      csi.storage.k8s.io/provisioner-secret-namespace: mortal-system
      csi.storage.k8s.io/controller-publish-secret-name: minio-secret
      csi.storage.k8s.io/controller-publish-secret-namespace: mortal-system
      csi.storage.k8s.io/node-stage-secret-name: minio-secret
      csi.storage.k8s.io/node-stage-secret-namespace: mortal-system
      csi.storage.k8s.io/node-publish-secret-name: minio-secret
      csi.storage.k8s.io/node-publish-secret-namespace: mortal-system
  • 查看部署的 PV:

  • 后续编写 pvc 时,volumeClaimTemplates 中的 storageClassName 需要写上述的 minio-sc 。比如编写一个 test.yaml

  • 部署后:kubectl apply -f test.yaml,在查看 pvc 是否是 bound 状态:kubect get pvc

  • 在申请完 PVC 之后就会创建对应的 PV 进行绑定,删除 PVC 之后,与之绑定的 PV 也会删除。

2. 集成 NFS

  • k8s 集成 NFS 步骤如下:

    1. 安装 NFS。
    2. 安装 nfs-client-provisioner。
    3. 测试。
  • k8s 集群中的所有节点(mater 和 worker)安装 NFS。

    java 复制代码
    sudo yum install nfs-utils -y
  • master 节点 新建共享目录:

    java 复制代码
    sudo mkdir /nfs_share
    sudo chmod 777 /nfs_share
  • 配置 NFS 权限:vim /etc/exports,添加如下内容:

    java 复制代码
    /nfs_share *(rw,sync,no_root_squash)
  • 使配置生效:

    java 复制代码
    sudo exportfs -a
  • master 启动 nfs 服务:

    java 复制代码
    sudo systemctl start nfs-server
    sudo systemctl enable nfs-server
  • 所有 Worker 节点启动 rpcbind

    java 复制代码
    sudo systemctl start rpcbind
    sudo systemctl enable rpcbind
  • 所有 Worker 节点挂载 Master

    java 复制代码
    sudo mount 192.168.245.20:/nfs_share /mnt
  • Master 安装 nfs-client-provisioner。先进行下载:

    java 复制代码
    wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/refs/tags/v4.0.2/deploy/deployment.yaml
    wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/refs/tags/v4.0.2/deploy/class.yaml
    wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/refs/tags/v4.0.2/deploy/rbac.yaml
  • 修改 deployment.yaml

    • image:替换为国内镜像。

      java 复制代码
      swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
    • ip 替换为 安装了 NFS 服务的IP地址。我这里是直接在 Master 节点安装的,所以直接用的 Master 节点的内网IP。

    • path 替换为需要共享的目录。

  • 安装:

    java 复制代码
    kubectl apply -f rbac.yaml
    kubectl apply -f deployment.yaml
    kubectl apply -f class.yaml
  • 新建 PVC 进行测试:test.yaml。其中 storageClassName 需要和 上面的 class.yaml 的 name 一致。

    java 复制代码
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: test-nfs-pvc
      namespace: mortal-system
    spec:
      accessModes:
        - ReadWriteMany  # NFS 支持多节点读写
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 1Gi
  • 部署并测试查看 PVC 是否为 bound 状态。

    java 复制代码
    kubectl apply -f test.yaml
  • 如果 NFS 布置在别的服务器上,需要配置安全组,开放端口:111 和 2049

相关推荐
终端行者4 小时前
K8s中部署Minio集群 如何部署minio集群
云原生·容器·kubernetes·1024程序员节
荣光波比4 小时前
Prometheus(二)—— 在K8s集群中部署Prometheus+Grafana+AlertManager实现全方位监控
kubernetes·grafana·prometheus
程序猿阿伟8 小时前
《3D手游云原生开发:关键难题突破日志》
3d·云原生
AKAMAI8 小时前
Akamai与Bitmovin:革新直播与点播视频流服务
人工智能·云原生·云计算
StarRocks_labs8 小时前
Kubernetes 场景下的 StarRocks 灾备体系:Cluster Snapshot 实践解析
starrocks·kubernetes·数据备份·存算一体架构·快照恢复机制
thinktik8 小时前
AWS EKS 计算资源自动扩缩之Fargate[AWS 海外区]
后端·kubernetes·aws
PellyKoo9 小时前
Docker容器中中文文件名显示乱码问题完美解决方案
运维·docker·容器
奥尔特星云大使10 小时前
Docker 拉取 MySQL 5.7 镜像、启动容器并进入 MySQL
数据库·mysql·docker·容器