# 部署

  • 可使用 kubeadm 命令部署 k8s 标准版。

  • 也可部署其它 k8s 发行版。它们在 k8s 的基础上封装了其它组件,比如 Web UI、网络插件。

    • minikube :用于部署测试用途的 k8s 。
    • Rancher :由 Rancher Labs 公司开源。
    • OpenShift :由 Red Hat 公司开源。
    • kubesphere :由青云公司开源。
    • KubeOperator :由飞致云公司开源。
  • 也可使用云平台托管的 k8s 发行版,不需要用户部署维护。

    • Elastic Kubernetes Service(EKS):由 AWS 云提供。
    • Azure Kubernetes Service(AKS):由 Azure 云提供。
    • Google Kubernetes Engine(GKE):由 Google 云提供。
    • Tencent Kubernetes Engine(TKE):由腾讯云提供。

# 版本

  • 2014 年,Google 公司开源了 k8s 项目,它借鉴了 Google 内部的大规模集群管理系统 Borg、Omega 。
  • 2015 年,Google 公司将 k8s 项目捐赠给 CNCF 基金会托管。
  • k8s 计划每年发布三四个子版本,更新一些 feature 。
    • 增加一个 feature 的一般流程:
      1. 在某个 k8s 版本,首次加入该 feature 的代码,标为 alpha 阶段,默认不启用。可以在启动 k8s 组件时,通过命令行参数 --feature-gates=feature1=true,feature2=true,... 启用。
      2. 在下一个 k8s 版本,将该 feature 标为 beta 阶段,默认启用,可以禁用。此时该 feature 已通过 alpha 试用,但还不稳定,可能发生不兼容变化。
      3. 再等一个 k8s 版本,将该 feature 标为 stable 阶段(又称为 GA ),不能禁用。
    • 删除一个 feature 的一般流程:
      1. 在某个 k8s 版本,将该 feature 标为 deprecated 状态,默认禁用,可以启用。
      2. 等一两个 k8s 版本之后,将该 feature 的代码从 k8s 删除。
    • feature 的版本号示例:
      v1        # GA 阶段,版本号为 v1
      v1beta1   # beta 阶段,版本号为 v1
      v1alpha1  # alpha 阶段,版本号为 v1
      
    • feature-gates 列表 (opens new window)

以下是对 k8s CHANGELOG (opens new window) 的摘要:

  • v1.18
    • 于 2020 年 3 月发布。
    • kube-apiserver 停止支持 apiVersion: apps/v1beta1apiVersion: apps/v1beta2 版本的所有 k8s 资源,请改用 apiVersion: apps/v1
  • v1.19
    • 于 2020 年 8 月发布。
    • 默认启用 EndpointSlices 功能。
    • [GA] 支持创建 Ingress
  • v1.20
    • 于 2020 年 12 月发布。
    • [deprecated] dockershim 模块,建议改用 containerd 或 CRI-O 作为 CRI 组件。
      • 如果继续使用 dockershim 模块,则 kubelet 启动时会打印一条告警日志。
  • v1.21
    • 于 2021 年 4 月发布。
    • [deprecated] PodSecurityPolicy ,建议改用 PSA 。
    • [beta] 优雅关闭节点(GracefulNodeShutdown):关机时自动终止 Pod ,最多等待 shutdownGracePeriod 时长。
  • v1.22
    • 于 2021 年 8 月发布。
    • 允许在节点上启用 Swap 。
  • v1.23
    • 于 2021 年 12 月发布。
    • [GA] 支持 IPv6
    • [GA] 支持给 Pod 挂载通用临时卷(generic ephemeral volumes),像 emptyDir 一样临时存储数据,但 volume 由 CSI 插件或其它程序提供。
  • v1.24
    • 于 2022 年 5 月发布。
    • beta 阶段的 API 不再默认启用。
    • [delete] dockershim 模块,不能继续使用。
    • [deprecated] Service 弃用配置参数 spec.loadBalancerIP ,建议改用 metadata.annotations 声明配置。
    • [GA] Job 增加配置参数 suspend
    • [GA] Service 增加配置参数 spec.allocateLoadBalancerNodePorts
  • v1.25
    • 于 2022 年 8 月发布。
    • [GA] 支持 Cgroup v2
    • [GA] 支持创建 Ephemeral Containers
    • [GA] PSA(Pod Security admission)是一个准入控制插件,用于在新建 Pod 时,检查其 securityContext 是否符合安全标准。
  • v1.26
    • 于 2022 年 12 月发布。
    • 修改 k8s 各组件的镜像仓库。从 Google 平台的 k8s.gcr.io ,改为 k8s 社区维护的 registry.k8s.io ,其后端 S3 存储在多个云平台,优化下载速度。
    • [GA] Service 增加配置参数 spec.internalTrafficPolicy 。
    • [GA] 改进 Service 自动分配 Cluster IP 的顺序,优先选用 --service-cluster-ip-range 范围中高位的 IP 。建议用户静态分配 IP 时,优先选用低位的 IP ,这样两者不容易冲突。
  • v1.27
    • 于 2023 年 4 月发布。
    • [Alpha] kubelet 增加配置参数 maxParallelImagePulls ,控制最多并行拉取多少个镜像。
  • v1.28
    • 于 2023 年 8 月发布。
    • [Alpha] 增加 sidecar 形式的 init 容器。
    • [GA] 异常关闭节点(Non-graceful node shutdown):允许用户给节点添加污点 node.kubernetes.io/out-of-service: NoExecute
  • v1.29
    • 于 2023 年 12 月发布。
    • 给 kubelet 增加配置参数 imageMaximumGCAge 。
    • [Alpha] kube-proxy 新增 nftables 代理模式。
  • v1.30
    • 于 2024 年 3 月发布。
    • 允许节点 swap 内存交换。
    • [GA] HPA 支持只监控某个容器的资源使用率,而不考虑 Pod 中其它容器。
  • v1.31
    • 于 2024 年 8 月发布。

# minikube

:一个命令行工具,用于部署单节点的 k8s 集群,常用于测试。

  • 可以在本机部署多个 k8s 集群。每个 k8s 集群位于一个容器内,包含多个进程。

# 部署

  1. 安装 docker

  2. 下载 minikube :

    wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
    sudo install minikube-linux-amd64 /usr/local/bin/
    
  3. 以非 root 用户部署 k8s :

    useradd leo
    usermod leo -G docker
    su - leo
    minikube start
    
  4. 在本机安装 kubectl ,或使用 minikube 内置的 kubectl :

    minikube kubectl -- get pods -A
    

# 命令

minikube
        start                             # 部署一个 k8s 集群
            -p <name>                     # --profile ,指定 k8s 集群的名称,默认为 minikube
            --driver docker               # 驱动,默认会自动选择
            --kubernetes-version v1.2.3   # k8s 版本。默认为最新的 stable 版本
        stop
        delete          # 删除当前 k8s 集群
            -p <name>   # 指定 k8s 集群的名称
            --all       # 删除所有 k8s 集群
        pause           # 暂停运行
        unpase

        profile         # 显示当前 k8s 集群的名称
            list        # 显示所有 k8s 集群
        status

# kubeadm

:k8s 官方提供的一个命令行工具,用于部署 k8s 标准版,不会安装 kubelet、kubectl、网络插件。

# 安装

  • 用 yum 安装:
    # 采用阿里的镜像源,因为谷歌的镜像源需要翻墙访问
    cat <<EOF > /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
    
    # 安装
    yum install -y kubeadm
    
    • 这会同时安装依赖的 kubelet、kubectl 。

# 命令

kubeadm
        version
        config        # 管理配置。这些配置会保存为一个名为 kubeadm-config 的 ConfigMap ,位于 kube-system 命名空间
          print       # 打印配置
            init-defaults
            join-defaults

        init          # 将本机初始化为主节点
        join          # 使本机连接到主节点,加入 k8s 集群
        reset         # 撤销 init、join 命令对本机的影响

        token         # 管理 token ,用于一个节点 join 主节点时的认证
          create
            --ttl     # 有效时长,过期则自动删除。默认为 24h
          delete <token>...
          list

# 部署

  1. 部署 k8s 时,主机需要满足以下条件:

    • 至少 2v CPU、2G RAM 。
      • 空载时,主节点的全部进程大概占用 500M 内存,而工作节点的 kubelet 占用 100M 内存。
    • 禁用 Swap 分区。
    • 每个主机的 hostname、MAC 地址不同。
    • 安装 docker 引擎。
      • dockerd 采用的 Cgroup 驱动默认为 cgroupfs ,而 kubelet 默认为 systemd 。因此需要修改 dockerd 的配置,并重启 dockerd :
        {
          "exec-opts": ["native.cgroupdriver=systemd"]
        }
        
    • 安装 kubelet ,并启动:
      systemctl start  kubelet
      systemctl enable kubelet
      
    • 主机的防火墙开通 TCP 端口 6443、10250 ,供不同主机的 k8s 组件之间通信。不过更建议关闭 firewalld 防火墙,避免不兼容 CNI 插件。
    • 在集群的至少一个主机上安装 kubeadm、kubectl ,用作客户端。
  2. 下载 Docker 镜像:

    kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers
    
  3. 在一个主机上执行以下命令,初始化为主节点:

    kubeadm init
                --config                            # 指定配置文件
                --kubernetes-version <string>       # k8s 版本。默认为最新的 stable 版本
                --image-repository registry.aliyuncs.com/google_containers  # 镜像仓库,默认为 k8s.gcr.io ,但它需要翻墙访问
                --node-name <name>                  # 指定当前节点名
                --pod-network-cidr 10.244.0.0/16    # Pod IP 的子网范围,也会被用于设置 cluster-cidr 。默认为空,不会分配 CIDR
                --service-cidr <string>             # Service IP 的子网范围,默认为 10.96.0.0/12
                --service-dns-domain <string>       # Service 的域名起点,默认为 cluster.local
    
    • 这会生成管理员的 kubeconfig 配置文件,将它拷贝到默认路径:
      mkdir -p ~/.kube
      cp /etc/kubernetes/admin.conf ~/.kube/config
      chmod -R 600 ~/.kube
      
  4. 在其它主机上执行以下命令,加入 k8s 集群:

    kubeadm join 10.0.0.1:6443
          --token ****** --discovery-token-ca-cert-hash sha256:******   # 加入集群时需要使用 token 认证
          --control-plane     # 加入之后成为控制平面节点,默认是工作节点
    
    • 至少需要部署一个主节点和一个工作节点。
    • 默认给主节点设置了污点,不允许用作工作节点,降低主节点故障的风险。可以移除污点:
      kubectl taint nodes --all node-role.kubernetes.io/master-
      
    • 建议部署 3~5 个主节点,实现 k8s 的高可用。
  5. 启用一种 CNI 网络插件:

    curl https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml | kubectl apply -f -
    

# Rancher

:一个 Web 网站,可以创建、托管多个 k8s 集群。

# 原理

  • 架构:

    • 先部署 Rancher server 。
    • 然后在一些主机上运行 Rancher agent ,部署 k8s 集群,或者控制已有的 k8s 集群。
      • 需要 agent 能通过网络单向连接到 server ,被 server 控制。不需要 server 能访问到 agent 的 IP 。
      • Rancher 可以托管多个 k8s 集群,称为下游集群。
        • 当 Rancher server 故障时,下游集群依然会正常运行。
  • Rancher 提供了多种 k8s 发行版:

    • RKE(Rancher Kubernetes Engine)
      • :一个 k8s 发行版。
      • 提供了一个命令行工具 rke ,用于部署 RKE 。它会以 docker 容器方式部署所有 k8s 组件。
    • k3s
      • :一个轻量级的 k8s 发行版。
      • 主节点只需运行 k3s server 进程,工作节点只需运行 k3s agent 进程。
      • 默认采用 sqlite3 作为数据库。
    • RKE2
      • :RKE 引擎的第二代,结合了 RKE1、k3s 的优点。
      • 与 RKE1 相比的差异:
        • 容器运行时采用 containerd ,而不是 docker 。
        • 以 systemd 方式部署 kubelet ,而不是 docker 容器。然后 kubelet 以 static pod 方式部署 apiserver、etcd 等 k8s 组件。
        • CNI 插件默认采用 calico ,而不是 canal 。
  • Rancher 会在下游集群中创建一些专用应用:

    Namespace Type Name Comment
    default service kubernetes 用于反向代理 apiserver ,默认地址为 https://10.43.0.1
    cattle-system deployment cattle-cluster-agent 用于供 Rancher 访问下游集群的 apiserver 。如果它不可用,则使用 cattle-node-agent
    cattle-system daemonset cattle-node-agent 用于管理 k8s Node ,比如升级 kubelet
    cattle-system daemonset kube-api-auth 用于对 RKE 的用户进行身份认证
    cattle-fleet-system deployment fleet-agent 用于编排下游集群,包含一些 k8s controller
    • Cattle 是 Rancher 的容器编排引擎,基于 docker-compose.yml 或 k8s YAML 文件。
    • Fleet 是一个独立于 Rancher 的项目,用于以 GitOps 方式编排大量 k8s 集群。

# 部署

  • 用 docker-compose 部署一个单节点的 Rancher :

    version: "3"
    
    services:
      rancher:
        container_name: rancher
        image: rancher/rancher:v2.8.1
        privileged: true
        restart: unless-stopped
        ports:
          - 80:80
          - 443:443
        volumes:
          - /etc/localtime:/etc/localtime:ro
          - ./data:/var/lib/rancher
          # - ./auditlog:/var/log/auditlog
    
    • 此时 Rancher 会在容器内运行一个 k3s 集群。
    • 可选给 Rancher 启用审计日志,类似于 kube-apiserver 的审计日志,需要添加以下环境变量:
      environment:
        AUDIT_LEVEL: 3            # 日志级别,默认为 0 。可以取值为 0、1、2、3 ,相当于 kube-apiserver 审计日志的 None、Metadata、Request、RequestResponse 级别
        AUDIT_LOG_MAXAGE: 10      # 每天轮换一次日志文件,最多保留最近几天的日志文件
        AUDIT_LOG_MAXSIZE: 100    # 每个日志文件最大多少 MB ,超过则轮换一次
        AUDIT_LOG_MAXBACKUP: 10   # 最多保留最近几个日志文件
      
  • 或者在 k8s 中用 helm 部署 Rancher ,可以部署成多节点,实现高可用。

# 用法

  • 在 Rancher 的 Cluster Management 页面,可以添加 k8s 集群让 Rancher 托管。

    • 从托管 k8s 中移除一个节点时,需要清空节点上的数据,否则重新添加该节点时可能出错。参考 官方文档 (opens new window)
  • 可通过 Rancher 的 Web 表单配置 k8s ,也可以通过一个 cluster.yml 文件进行配置,如下:

    name: test-k8s                                # k8s 集群名
    enable_cri_dockerd: false                     # 是否启用外部的 dockershim 模块,从而在 k8s v1.24 删除内置的 dockershim 模块之后,依然能使用 docker 容器引擎
    rancher_kubernetes_engine_config:
      private_registries:                         # 让 Rancher 部署 k8s 组件时采用自定义的镜像仓库
        - is_default: true
          url: harbor.test.com
          # user: ***
          # password: ***
      services:                                   # 配置各个 k8s 组件
    
        etcd:
          # backup_config:
          #   enabled: true
          #   interval_hours: 12                  # 每隔 12h 自动给 etcd 创建一个快照,从而允许用户回滚 k8s 集群
          #   retention: 6                        # 保留最近的 6 个快照。如果想保存更久的快照,可以手动执行 etcdctl 命令创建快照
          #   safe_timestamp: false
          #   timeout: 300
          # creation: 12h
          # extra_args:
          #   election-timeout: '5000'
          #   heartbeat-interval: '500'
          # gid: 0
          # retention: 72h
          # snapshot: false
          # uid: 0
    
        kube-api:
          # audit_log:                            # 默认启用了审计日志
          #   enabled: true
          #   configuration:
          #     path: /var/log/kube-audit/audit-log.json
          #   policy:
          #     apiVersion: audit.k8s.io/v1
          #     kind: Policy
          #     rules:
          #     - level: Metadata
          # event-ttl: 1h                         # event 的保留时长
          service_cluster_ip_range: 10.43.0.0/16
          service_node_port_range: 30000-32767
          # max-requests-inflight: 400            # apiserver 接收读请求的最大并发数(是指实时并发数,而不是平均 QPS )
          # max-mutating-requests-inflight: 200   # apiserver 接收写请求的最大并发数
    
        kube-controller:
          cluster_cidr: 10.42.0.0/16              # Pod IP 的子网范围
          service_cluster_ip_range: 10.43.0.0/16  # Service IP 的子网范围
          # extra_args:                           # 添加命令行参数
          #   node-cidr-mask-size: '24'           # 每个节点的子网掩码长度
          #   terminated-pod-gc-threshold: 12500  # 如果整个 k8s 集群中 terminated pod 数量达到该阈值,则触发一次垃圾收集,删除它们
          extra_binds:
            - /etc/localtime:/etc/localtime:ro    # 让 kube-controller 采用宿主机的时区,方便控制 CrontJob 的调度时间
          # kube-api-qps: 20                      # 限制向 apiserver 发送请求的速率,平均每秒的请求数
          # kube-api-burst: 30                    # 限制向 apiserver 发送请求的突发速率,短时间每秒的请求数
          # node-monitor-period: 5s               # node controller 每隔多久从 apiserver 获取一次各节点 kubelet 的状态
          # node-monitor-grace-period: 40s        # 如果持续一段时间,不能获取节点的状态,则标记为 Ready=Unknown
          # pod-eviction-timeout: 5m              # 如果继续持续一段时间节点的 Ready 条件为 False 或 Unknown ,则驱逐该节点上的 Pod
    
        kubelet:
          cluster_domain: cluster.local
          cluster_dns_server: 10.43.0.10
          # fail_swap_on: true                    # 如果节点启用了 swap 内存,则拒绝启动 kubelet
          extra_args:
            max-pods: 250                         # 每个节点上最多允许调度的 Pod 数,默认为 110 。除了该限制,还需考虑每个节点的 cluster_cidr 容量
            # pod-max-pids: <int>                 # 限制每个 Pod 使用的 PID 数量
            serialize-image-pulls: 'false'        # 是否同时只能拉取一个镜像,默认为 true
            # kube-api-qps: 50
            # kube-api-burst: 100
    
            # 节点压力驱逐
            eviction-hard: memory.available<5%,nodefs.available<5%,imagefs.available<5%,nodefs.inodesFree<5%  # 硬驱逐阈值,默认不存在
            # eviction-soft: memory.available<10%,nodefs.available<10%  # 软驱逐阈值,默认不存在
            # eviction-soft-grace-period: memory.available=1m,nodefs.available=1m,imagefs.available=1m,nodefs.inodesFree=1m   # 每个阈值持续满足一定时长之后,才触发软驱逐
            # eviction-max-pod-grace-period: 30       # 软驱逐终止 Pod 时的宽限期
            eviction-pressure-transition-period: 30s  # 每次解除节点压力的 condition 之前需要等待一定时长,避免在驱逐阈值上下波动 。默认为 5m
            # eviction-minimum-reclaim:               # 每次驱逐至少回收多少资源,避免频繁驱逐。默认为 0
            #   memory.available: 1Gi
            #   nodefs.available: 1Gi
    
            # 每隔 ContainerGCPeriod=1m 清理一次节点上的 terminated 容器(不包括不是由 kubelet 创建、管理的容器)
            # 建议每个 Pod 至少保留一个 terminated 容器,这样当容器异常终止时,可以查看日志、进容器排查原因
            # minimum-container-ttl-duration: 0        # 容器进入 terminated 状态之后超过该时长,才可能被 kubelet 删除。默认为 0
            # maximum-dead-containers-per-container: 1 # 每个 Pod 最多保留的 terminated 容器数。默认为 1 ,设置为 -1 则不限制
            # maximum-dead-containers: -1              # 整个 k8s 集群最多保留的 terminated 容器数。默认为 -1 ,表示不限制
    
            # 每隔 ImageGCPeriod=5m 清理一次节点上的镜像
            # image-gc-high-threshold: 85             # 一个百分数。当节点的磁盘使用率达到高水位时,开始清理未被使用的 Docker 镜像,从最旧的镜像开始删除,直到磁盘使用率降至低水位
            # image-gc-low-threshold: 80
            # imageMinimumGCAge: 2m                   # 如果一个镜像超过该时长未被使用,才允许被 gc 删除
            # imageMaximumGCAge: 0s                   # 如果一个镜像超过该时长未被使用,则即使磁盘未达到高水位,也会被 gc 删除。默认值为 0s ,表示禁用该功能
    
            # 设置每个节点保留的资源,剩下的资源才可分配给 pod
            kube-reserved: cpu=0.5,memory=500Mi                                   # 保留给 kubelet、容器运行时等 k8s 系统进程
            system-reserved: cpu=0.5,memory=500Mi,ephemeral-storage=10Gi,pid=1000 # 保留给 sshd 等系统进程
            # enforce-node-allocatable: pods          # 强行限制哪些 Cgroup 的可分配资源,默认为 pods 。可增加限制 pods,kube-reserved,system-reserved ,但可能导致系统服务被 OOM 杀死
            # kube-reserved-cgroup: /kubelet.slice    # 增加了 enforce-node-allocatable 限制时,需要声明 reserved-cgroup 。如果该 Cgroup 不存在,则需要手动创建,否则 kubelet 会启动失败
            # system-reserved-cgroup: /system.slice
    
            # 关于状态
            # node-status-update-frequency: 10s       # 每隔多久 kubelet 上报一次节点状态到 apiserver
            # global-housekeeping-interval: 1m        # 每隔多久 cAdvisor 采集一次全局监控指标,可以发现新容器
            # housekeeping-interval: 10s              # 每隔多久 cAdvisor 采集一次已有容器的监控指标
            # runtime-request-timeout: 2m             # API 请求的超时时间
            # volume-stats-agg-period: 1m             # 每隔多久计算所有 volume 的已用体积
    
  • Rancer 在 k8s 中增加了项目(project)的概念,用于对命名空间分组。

  • 可以在 Rancher 上创建多个用户,然后允许用户访问哪些下游集群、项目。

    • 这会自动在下游集群里创建用户、ClusterRoleBindings 。
    • 可以在 Rancher 网页上导出用户的 kubeconfig ,它访问 apiserver 时有两种方式:
      • 访问 Rancher 的 HTTP API ,通过 Rancher 用户认证之后,被反向代理到下游集群的 apiserver ,以 ServiceAccount 的身份进行操作。默认采用该方式,但 Rancher 可能代理耗时较久、故障。
      • 直接访问下游集群的 apiserver ,使用 k8s user 的身份,由 kube-api-auth 进行身份认证。建议采用该方式。
  • k8s 各组件之间使用自签名的 ssl 证书进行认证、加密通信。每隔几个月 ssl 证书会到期,需要重启续订。

    • 在 Rancher 的 Cluster Management 网页,可选择一个集群,轮换证书(Rotate Certificates)。这会自动生成新的证书,然后重启所有 k8s 组件。
    • Rancher v2.6.3 开始,会在 ssl 证书只剩 30 天有效期时,自动更新证书。
  • Rancher 的 Apps 页面提供了一些常见软件的 Helm Charts ,可以一键安装。例如:

    • Monitoring :包含了 Prometheus Operator、Prometheus Adapter、Grafana 等组件,安装之后会在 Rancher 网页上集成监控图表,不过比较简单,详细的监控图表还是要到 Grafana 看。
    • Istio
    • MySQL
  • 在 Rancher 的 Global Settings 页面,需要注意以下配置参数:

    auth-token-max-ttl-minutes              # 用户 token 的最大过期时间。设置为 0 则无限制
    auth-user-session-ttl-minutes           # 用户登录 Rancher Web 页面时,会创建一个临时 token ,设置过期时间
    kubeconfig-default-token-ttl-minutes    # 新建一个 kubeconfig 时,其中 token 的过期时间。不能超过 auth-token-max-ttl-minutes 时长
    
    server-url              # Rancher 的 URL 。所有 k8s 节点都需要通过该 URL 访问 Rancher ,从而被 Rancher 管理
    system-default-registry # docker 仓库的地址,用于下载 Rancher 本身各个组件的 docker 镜像