# 部署
可使用 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 的一般流程:
- 在某个 k8s 版本,首次加入该 feature 的代码,标为 alpha 阶段,默认不启用。可以在启动 k8s 组件时,通过命令行参数
--feature-gates=feature1=true,feature2=true,...
启用。 - 在下一个 k8s 版本,将该 feature 标为 beta 阶段,默认启用,可以禁用。此时该 feature 已通过 alpha 试用,但还不稳定,可能发生不兼容变化。
- 再等一个 k8s 版本,将该 feature 标为 stable 阶段(又称为 GA ),不能禁用。
- 在某个 k8s 版本,首次加入该 feature 的代码,标为 alpha 阶段,默认不启用。可以在启动 k8s 组件时,通过命令行参数
- 删除一个 feature 的一般流程:
- 在某个 k8s 版本,将该 feature 标为 deprecated 状态,默认禁用,可以启用。
- 等一两个 k8s 版本之后,将该 feature 的代码从 k8s 删除。
- feature 的版本号示例:
v1 # GA 阶段,版本号为 v1 v1beta1 # beta 阶段,版本号为 v1 v1alpha1 # alpha 阶段,版本号为 v1
- feature-gates 列表 (opens new window)
- 增加一个 feature 的一般流程:
以下是对 k8s CHANGELOG (opens new window) 的摘要:
- v1.18
- 于 2020 年 3 月发布。
- kube-apiserver 停止支持
apiVersion: apps/v1beta1
和apiVersion: 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 集群位于一个容器内,包含多个进程。
# 部署
安装 docker
下载 minikube :
wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/
以非 root 用户部署 k8s :
useradd leo usermod leo -G docker su - leo minikube start
在本机安装 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
# 部署
部署 k8s 时,主机需要满足以下条件:
- 至少 2v CPU、2G RAM 。
- 空载时,主节点的全部进程大概占用 500M 内存,而工作节点的 kubelet 占用 100M 内存。
- 禁用 Swap 分区。
- 每个主机的 hostname、MAC 地址不同。
- 安装 docker 引擎。
- dockerd 采用的 Cgroup 驱动默认为 cgroupfs ,而 kubelet 默认为 systemd 。因此需要修改 dockerd 的配置,并重启 dockerd :
{ "exec-opts": ["native.cgroupdriver=systemd"] }
- dockerd 采用的 Cgroup 驱动默认为 cgroupfs ,而 kubelet 默认为 systemd 。因此需要修改 dockerd 的配置,并重启 dockerd :
- 安装 kubelet ,并启动:
systemctl start kubelet systemctl enable kubelet
- 主机的防火墙开通 TCP 端口 6443、10250 ,供不同主机的 k8s 组件之间通信。不过更建议关闭 firewalld 防火墙,避免不兼容 CNI 插件。
- 在集群的至少一个主机上安装 kubeadm、kubectl ,用作客户端。
- 至少 2v CPU、2G RAM 。
下载 Docker 镜像:
kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers
在一个主机上执行以下命令,初始化为主节点:
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
- 这会生成管理员的 kubeconfig 配置文件,将它拷贝到默认路径:
在其它主机上执行以下命令,加入 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 的高可用。
启用一种 CNI 网络插件:
curl https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml | kubectl apply -f -
# Rancher
:一个 Web 网站,可以创建、托管多个 k8s 集群。
- 官方文档 (opens new window)
- 采用 Golang 语言开发。
# 原理
架构:
- 先部署 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 。
- RKE(Rancher Kubernetes Engine)
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 镜像