1、k8s 概念
1.1、基本概念
Kubernetes 是谷歌开源的基于容器技术的分布式架构方案,用于管理容器化的工作负载和服务,促进声明式配置和自动化。
Kubernetes 的功能有
- 服务发现和负载均衡:使用 ip 地址或 dns 名称来暴露容器,并实现负载均衡分配网络流量
- 部署和回滚:通过配置文件描述容器的期望状态,支持回滚到指定部署版本
- 弹性伸缩:可根据指标配置自动伸缩策略,以应对突发流量
- 容器配额管理:允许为每个容器指定所需的CPU和内存
- 故障发现和自我修复:监控容器的运行状态,并尝试重启替换状态异常的容器
- 密钥和配置管理:secret 和 configMap,两种资源来分别管理密钥信息和配置信息
- 支持多种数据卷类型:例如:本地存储、公有云提供商、分布式存储系统等
1.2、基本术语
Pod
pod:最小可部署单元,调度的最小基本单位,代表集群上正在运行的一个进程。
k8s 为每个 pod 分配唯一的 pod ip,每个 pod 有一个 pause 容器( 根容器)。pod 内的多个容器,共享 pause 容器的 ip 和 volume;同时 pause 容器的状态代表整个 pod 的状态。
Label
label:kv 键值对,通过给指定资源对象绑定 label 来实现对资源对象的分组管理。
通过 label 为资源对象贴上相对应的标签,然后通过 Label Selector(标签选择器)查询和筛选拥有某些 label 的资源对象。
例如:
# 标签选择器
selector:
# 1、标签匹配
matchLabels:
app: myweb # 选择标签 key-app,value-myweb 资源
# 2、表达式匹配
matchExpressions:
# 选择标签 key-tier, value-in (frontend, backend)
- {key: tier, operator: In, values: [frontend,backend]}
# 或使用以下写法,操作:In, NotIn, Exists and DoesNotExist
- key: tier
operator: In
values: ["frontend","backend"]
RC
Repliacation Controller,RC 副本控制器。保持 pod 的副本数量与预期数量一致。deployment 内部包含该功能,所以不推荐使用。
RS
Replica Set,RS 副本控制器。RC 的升级版本,区别在于:
- RC 的 Label Selector 仅支持基于等式的表达式,RS 的 Label Selector 可以支持基于集合的表达式。
- 在线编辑后,RS 自动更新 pod,RC 不会自动更新现有 pod。
Deployment
deployment:部署,副本控制器,用于更好的解决 pod 的部署、升级、回滚等问题。内部会自动创建 RS 用于pod 的副本控制。
deployment 相较于 RC/RS 具有以下优势:
- deployment 资源对象会自动创建 RS 资源对象来完成部署,对 deployment 的修改并发布会产生新的 RS 资源对象,为新的发布版本服务。
- 支持查看部署进度,以确定部署操作是否完成
- 更新 deployment,会触发部署从而更新 pod
- 支持 pause | resume 操作,暂停后修改不会触发发布,恢复后发布新的 deployment
- 支持回滚操作
- 支持重新启动操作,触发 pod 更新。
- 自动清理不需要的 RS
StatefulSet
StatefulSet:管理有状态应用的 pod,例如 Kafka 集群、Mysql 集群、MongoDB集群等。与无状态的服务不同的是:无论怎么调度,每个 pod 都有一个永久不变的ID。
面向无状态的应用:RC、Deployment、DaemonSet、Job等。
DaemonSet
副本控制器,每个节点只运行一个 pod 副本。区分 deployment 多副本。
应用:每个节点上运行集群守护进程、日志收集守护进程和监控守护进程。
Service
Service:微服务,将运行在一组 pods 上的应用程序公开为网络服务。通过 service 资源对象定义一个 service 的访问入口地址 。前端应用通过访问这个入口,从而访问其背后的一组有 pod 副本组成的集群实例。service 所针对的目标 pods 集合通常通过 label selector来确定。service 一旦被定义,就被分配了一个不可变更的 cluster ip,在整个 service的生命周期内,该 ip 地址都不会发生改变。
Namespace
namespace:命名空间,提供资源隔离。通过命名空间可以将同一个集群中的资源划分为相互隔离的组。同一命名空间下的资源名称必须唯一,但是不同命名空间下的资源名称可以一样。
其他概念
- Resource:k8s 是一个高度自动化的资源控制系统,大部分概念都可以看作资源对象。
- HPA:Horizontal Pod Autoscale,pod 横向自动伸缩。根据目标 pod 的负载变化,针对性调整目标 pod 的副本数量。
- Job:工作任务
- Volume:数据卷
- ConfigMap:管理非机密的配置项的数据
- Secret:管理密钥数据
2、k8s 架构
2.1、k8s 节点
k8s 集群由 master 节点和 node 节点组成
- master 节点:集群控制节点,为集群做出全局决策,不运行任何工作负载。
- node 节点:集群工作 worker 节点
2.2、k8s 组件
master 节点运行 master 组件 + node 组件,node 节点只运行 node 组件。
2.2.1、master 组件
- kube-controller-manager:负责运行控制器进程。包括节点控制器、任务控制器、端点控制器、副本控制器、服务账户和令牌控制器。
- kube-scheduler:负责监视新创建的、未指定运行节点的 pod,并选择节点来运行 pod。
- kube-apiserver:负责公开 k8s API,处理接受请求的工作,支持高可用部署。
- etcd:兼顾一致性与高可用的键值数据库,用来保存 k8s 集群数据。
2.2.2、node 组件
- kubelet:节点代理,监视分配给节点的 pod
- kube-proxy:网络代理,维护节点上的网络规则,允许 pod 网络通信
- docker:运行容器,例:docker engine + cri-dockerd
3、k8s 集群安装配置
3.1、docker
首先安装并运行 docker。参考文章:Docker: 容器与镜像
在 docker 运行时安装 cri-dockerd
cri-dockerd 安装
# 下载
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.6/cri-dockerd-0.2.6.amd64.tgz
# 解压到 /tmp 目录
tar -zxvf cri-dockerd-0.2.6.amd64.tgz -C /tmp
# 安装
sudo cp /tmp/cri-dockerd/cri-dockerd /usr/bin/
cri-dockerd 配置
# 获取源码
git clone https://github.com/Mirantis/cri-dockerd.git
# 将源码中systemd配置文件拷贝到相应目录
sudo cp cri-dockerd/packaging/systemd/* /etc/systemd/system/
# 配置
sudo vim /etc/systemd/system/cri-docker.service
# 在 [Service] ExecStart 配置项添加:
# --network-plugin 自定义容器网络
# --pod-infra-container-image 根容器镜像
[Service]
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.7
启动服务
# 重新加载配置
sudo systemctl daemon-reload
# 设置为开机自启动
sudo systemctl enable cri-docker
# 启动服务
sudo systemctl start cri-docker
# 检查服务状态
sudo systemctl status cri-docker
3.2、主机环境调整
修改节点 docker 的 cgroup driver
由于 k8s 中 kubelet 组件默认使用的 cgroupdriver 为 systemd,所以将 docker 的 cgroup driver 为 systemd。
sudo vim /etc/docker/daemon.json
# 增加配置内容
"exec-opts": [
"native.cgroupdriver=systemd"
]
# 重新加载配置并重启 docker 服务
sudo systemctl daemon-reload
sudo systemctl restart docker
关闭防火墙
sudo systemctl stop firewalld
sudo systemctl disable firewalld
禁用 Selinux
# 查看 selinux 状态
sudo apt install selinux-utils
getenforce
# 禁用
sudo setenforce 0
禁用 swap
# 禁用交换区
sudo swapoff -a
# 打开文件注释交换区定义
sudo vim /etc/fstab
# /swap.img none swap sw 0 0
# 查看交换区
free
# 显示
交换: 0 0 0
修改主机名
# 1、增加主机名与本机ip映射
sudo vim /etc/hosts
# 2、修改系统主机名
# 修改主机名
sudo hostnamectl set-hostname k8s-master1
# 查看主机名
hostname
3.3、安装 kube 工具
# 1、更新包管理索引
sudo apt-get update
# 支持 https 访问
sudo apt-get install -y apt-transport-https ca-certificates curl
# 2、下载 gpg 秘钥
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
# 3、设置 k8s 镜像源
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# 查看设置好的镜像源
ls /etc/apt/sources.list.d/
# 4、更新apt软件索引,并查看相关软件的可用版本
sudo apt-get update
apt-cache madison kubelet kubeadm kubectl
# 5、安装指定版本
# sudo apt-get install -y kubelet=<VERSION_STRING> kubeadm=<VERSION_STRING> kubectl=<VERSION_STRING>
sudo apt-get install -y kubelet=1.24.1-00 kubeadm=1.24.1-00 kubectl=1.24.1-00
# 6、锁定软件版本(防止自动升级)
sudo apt-mark hold kubelet kubeadm kubectl
# 7、检查kubelet状态
systemctl status kubelet
# 卸载
sudo apt-get remove kubelet kubectl kubeadm
3.4、Master 节点初始化
生成默认配置文件
kubeadm config print init-defaults > init.default.yaml
修改配置文件
vim init.default.yaml
# 1、修改节点IP地址
localAPIEndpoint.advertiseAddress: 192.168.88.132
# 2、修改套接字
nodeRegistration.criSocket: unix:///var/run/cri-dockerd.sock
# 3、修改节点名称
nodeRegistration.name: k8s-master1
# 4、修改镜像仓库地址为国内开源镜像库
imageRepository: registry.aliyuncs.com/google_containers
# 5、修改版本号
kubernetesVersion: 1.24.1
# 6、增加 podSubnet。安装 flannel 网络插件,必须在集群初始化时指定 pod 地址
# 10.244.0.0/16 为 flannel 组件 podSubnet 默认值,集群与组件配置保持一致。
networking.podSubnet: 10.244.0.0/16
拉取相关镜像
sudo kubeadm config images pull --config=init.default.yaml
初始化集群
# 通过配置文件初始化集群,建议选择配置文件初始化
sudo kubeadm init --config=init.default.yaml
初始化成功,返回提示信息:根据当前用户的类型,二选其一,执行相应的操作
普通用户执行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
root 用户执行
export KUBECONFIG=/etc/kubernetes/admin.conf
source /etc/profile
查看集群状态
# 查看 pod
kubectl get pod -A
# 查看节点
kubectl get node
# 查看所有组件
kubectl get cs
添加 pod 网络组件
下载 flannel 网络组件定义文件 到本地,也可以将文件内容拷贝到本地新建的 flannel.yml 文件
---
kind: Namespace
apiVersion: v1
metadata:
name: kube-flannel
labels:
pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
- apiGroups:
- "networking.k8s.io"
resources:
- clustercidrs
verbs:
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: flannel
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: flannel
subjects:
- kind: ServiceAccount
name: flannel
namespace: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: flannel
namespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-flannel
labels:
tier: node
app: flannel
data:
cni-conf.json: |
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-flannel-ds
namespace: kube-flannel
labels:
tier: node
app: flannel
spec:
selector:
matchLabels:
app: flannel
template:
metadata:
labels:
tier: node
app: flannel
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
hostNetwork: true
priorityClassName: system-node-critical
tolerations:
- operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni-plugin
#image: flannelcni/flannel-cni-plugin:v1.1.2 #for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.2
command:
- cp
args:
- -f
- /flannel
- /opt/cni/bin/flannel
volumeMounts:
- name: cni-plugin
mountPath: /opt/cni/bin
- name: install-cni
#image: flannelcni/flannel:v0.20.2 #for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel:v0.20.2
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conflist
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
#image: flannelcni/flannel:v0.20.2 #for ppc64le and mips64le (dockerhub limitations may apply)
image: docker.io/rancher/mirrored-flannelcni-flannel:v0.20.2
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: EVENT_QUEUE_DEPTH
value: "5000"
volumeMounts:
- name: run
mountPath: /run/flannel
- name: flannel-cfg
mountPath: /etc/kube-flannel/
- name: xtables-lock
mountPath: /run/xtables.lock
volumes:
- name: run
hostPath:
path: /run/flannel
- name: cni-plugin
hostPath:
path: /opt/cni/bin
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
应用资源
kubectl apply -f kube-flannel.yml
开启 kube-proxy 的 ipvs 模式
# 修改 mode: "ipvs"
kubectl edit -n kube-system cm kube-proxy
# 重启kube-proxy 守护进程
kubectl rollout restart -n kube-system daemonset kube-proxy
3.5、node 节点初始化
下列步骤同上
- 环境安装:docker,cri-dockerd,kubeadm、kubelet、kubectl 等工具
- 节点环境修改:修改 docker 的 cgroup driver,关闭防火墙,禁用 selinux,禁用 swap
将节点添加到集群
# master 节点执行
kubeadm token create --print-join-command
# 获得加入集群的命令
# 在命令上附加参数 --cri-socket unix:///var/run/cri-dockerd.sock,指定容器套接字
# 例如:
sudo kubeadm join 192.168.88.132:6443 --token 0dl98k.x44gmzyqy4b9h5gt --discovery-token-ca-cert-hash sha256:707002c5b13f2adc0facaf6e7b514b72dc0f8e7085925988daf5e99caf77a9c9 --cri-socket unix:///var/run/cri-dockerd.sock
3.6、重置节点
# 重置节点
sudo kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock
sudo rm -rf /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni/etc/cni/net.d $HOME/.kube/config
sudo ipvsadm --clear
# 删除网络
sudo ifconfig cni0 down
sudo ip link delete cni0
4、k8s 集群升级
升级 k8s 集群到 1.25 版本。
4.1、升级 Master 节点
kubeadm 升级
# 更新包管理器
sudo apt-get update
# 查看可用版本
apt-cache madison kubeadm
# 解除 kubeadm 软件包保留状态
sudo apt-mark unhold kubeadm
# 安装
sudo apt-get install -y kubeadm=1.25.5-00
# 设置为保留,即不自动更新
sudo apt-mark hold kubeadm
# 验证版本
kubeadm version
验证升级计划
# 验证升级计划
sudo kubeadm upgrade plan
返回的信息包括:检查可升级的版本,并查看需要手动升级的部分。
节点升级
1、升级 master 组件
根据升级计划,执行指定版本的升级命令,例如:v1.25.5
sudo kubeadm upgrade apply v1.25.5
2、升级 node 组件
2.1 & 2.2、调度保护 | 排空节点
开启调度保护,并将节点上除守护进程之外的其他进程调度到其他节点,不影响正常使用。
kubectl drain <nodename> --ignore-daemonsets
# 腾空节点
kubectl drain k8s-master1 --ignore-daemonsets
# 查看节点
kubectl get pod -A # pod状态:pending
kubectl get node # 节点状态:SchedulingDisabled
2.3、node 组件升级
# 组件升级
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.25.5-00 kubectl=1.25.5-00
sudo apt-mark hold kubelet kubectl
# 重启 kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet
2.4、解除保护
kubectl uncordon <nodename>
kubectl uncordon k8s-master1
4.2、升级 node 节点
kubeadm 升级
# 更新包管理器
sudo apt-get update
# 查看可用版本
apt-cache madison kubeadm
# 解除 kubeadm 软件包保留状态
sudo apt-mark unhold kubeadm
# 安装
sudo apt-get install -y kubeadm=1.25.5-00
# 设置为保留,即不自动更新
sudo apt-mark hold kubeadm
# 验证版本
kubeadm version
节点升级
sudo kubeadm upgrade node
# master 节点操作:腾空节点,开启调度保护
kubectl drain <nodename> --ignore-daemonsets
# node 组件升级
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.25.5-00 kubectl=1.25.5-00
sudo apt-mark hold kubelet kubectl
# 重启 kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# master 节点操作:解除调度保护
kubectl uncordon <nodename>
5、kubectl 常用命令
5.1、准备工作
5.1.1、kubectl 命令补全
# 安装命令自动补全插件
sudo apt-get install -y bash-completion
echo "source <(kubectl completion bash)" >> ~/.bashrc
source ~/.bashrc
5.1.2、安装 metric-server
metric-server 用于获取节点指标。
从 metrics server 获取 components.yaml 文档,并修改两处:
spec.template.containers.args
字段中添加--kubelet-insecure-tls
选项,不验证客户端证书。spec.template.containers.image
字段替换为registry.aliyuncs.com/google_containers/metrics-server:v0.6.2
5.2、kubectl 语法
kubectl [command] [TYPE] [NAME] [flags]
- command:指定对资源的操作。
- TYPE:指定资源类型。资源类型不区分大小写,可以指定单数、复数或缩写形式
- NAME:指定资源名称。资源名称区分大小写,若省略名称,则显示所有资源的详细信息。
- flags:指定可选的参数
具体命令使用可以通过 -h
来查看
5.3、基础操作命令
# 创建资源
kubectl create -f FILENAME
# 创建服务,通过现有资源对象的配置信息将新的 service 与原有资源背后的 pod做关联
kubectl expose
# 在集群中使用指定镜像启动容器
kubectl run
# 为对象设置功能特性:env, img, resources, select
kubectl set SUBCOMMAND
# 显示资源文档说明
kubectl explain RESOURC
# 显示资源信息
kubectl get
# 修改服务器线上资源(已部署)
kubectl edit (RESOURCE/NAME | -f FILENAME)
# 删除资源
kubectl delete
# 更新资源的标签
kubectl label
# 更新资源所关联的注解
kubectl annotate
5.4、应用部署命令
# 显示目前版本与将要应用的版本之间的差异
kubectl diff -f FILENAME
# 将新的配置应用到资源上,旧的配置不改变
kubectl apply -f FILENAME
# 将新的配置已替换的方式应用到资源上,旧的配置覆盖
kubectl replace -f FILENAME
# 管理资源的上线
kubectl rollout SUBCOMMAND
# 查看历史修订版本和配置
kubectl rollout history (TYPE NAME | TYPE/NAME) [flags]
# 暂停标记的资源,目前仅支持 deployment 资源对象
kubectl rollout pause RESOURCE
# 恢复暂停的资源
kubectl rollout resume RESOURCE
# 重启资源对象
kubectl rollout restart RESOURCE
# 查看发布状态
kubectl rollout status (TYPE NAME | TYPE/NAME) [flags]
# 回滚之前的版本
kubectl rollout undo (TYPE NAME | TYPE/NAME) [flags]
# 伸缩容,设置 pod 的副本数
kubectl scale
# 创建自动缩放器,自动选择和设置在 k8s 集群集中运行的 pod 数。
kubectl autoscale
5.5、集群管理命令
# 显示节点或 pod 的资源(cpu/memory)使用情况
kubectl top
# 标记节点为不可调度
kubectl cordon <nodename>
# 标记节点为可调度的
kubectl uncordon <nodename>
# 腾空指定节点
kubectl drain <nodename>
# 更新节点污点。
# 污点 taint 和容忍度 toleration 相互配合,可以避免 pod 被分配到不合适的节点。
kubectl taint
5.6、故障排除和调试
# 显示某个资源或某组资源的详细信息
kubectl describe
# 输出 pod 中某容器的日志
kubectl logs
# 连接到一个正在运行的容器
kubectl attach
# 在容器中执行相关命令
kubectl exec
# 将一个或者多个本地端口转发到 pod
kubectl port-forward
# 代理网关
kubectl proxy
# 将文件和目录拷入/拷出容器
kubectl cp
# 创建用于排查工作负载和节点故障的调试会话
kubectl debug