一、K3S 集群部署
1 | # 关闭防火墙 |
1 | # 将k3s二进制文件移动到/usr/local/bin目录,并添加执行权限 |
运行环境
- 最低运行要求
- 内存: 512MB / CPU: 1 核心
- K3s版本:v1.25.0+k3s1
- 集群规划
主机名 IP地址 配置 系统 网络 k8s - master 192.168.66.52 内存:4G CPU:4核(8逻辑核心) 硬盘:20G ubuntu20.04 vmware bridge模式 k8s-worker1 192.168.66.53 k8s-worker2 192.168.66.54
1.准备工作
需要在每台机器上执行如下命令:
- 关闭防火墙
- 设置selinux(需要联网): 安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。https://www.cnblogs.com/call-me-dasheng/p/15888546.html
1
sudo ufw disable
1
2yum install -y container-selinux selinux-policy-base
yum install -y https://rpm.rancher.io/k3s/latest/common/centos/7/noarch/k3s-selinux-0.2-1.el7_8.noarch.rpm
2.下载安装包
下载安装脚本**install.sh**
:https://get.k3s.io/
下载**k3s**
二进制文件:k3s
下载必要的image:离线安装需要的image文件
这些文件都可以在github仓库中获取:https://github.com/k3s-io/k3s
3.执行安装脚本
将k3s二进制文件移动到/usr/local/bin目录,并添加执行权限
1
2mv k3s /usr/local/bin
chmod +x /usr/local/bin/k3s将镜像移动到/var/lib/rancher/k3s/agent/images/目录(无需解压)
1
2mkdir -p /var/lib/rancher/k3s/agent/images/
cp ./k3s-airgap-images-amd64.tar.gz /var/lib/rancher/k3s/agent/images/
在k8s-master节点执行:
1
2
3
4
5
6
7
8
9#修改权限
chmod +x install.sh
#离线安装
INSTALL_K3S_SKIP_DOWNLOAD=true ./install.sh
#安装完成后,查看节点状态
kubectl get node
#查看token
cat /var/lib/rancher/k3s/server/node-token
#K106e06c1493d4fc3b4941c85d6dbfdaf7140a7e660ca8b6f849f89ff480c4ed418::server:5af23e94c7de63baa6372e9c1ba58e3c在k8s-worker1和k8s-worker2节点执行
1
2
3
4INSTALL_K3S_SKIP_DOWNLOAD=true \
K3S_URL=https://192.168.66.52:6443 \
K3S_TOKEN=K106e06c1493d4fc3b4941c85d6dbfdaf7140a7e660ca8b6f849f89ff480c4ed418::server:5af23e94c7de63baa6372e9c1ba58e3c \
./install.sh
虚拟网卡 cni0
k8s内部的虚拟网络:
master
1 | cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 |
slave1
1 | cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 |
slave2
1 | cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 |
排查错误
如果安装或启动不成功,可能有以下几个原因:
- 时间不统一
- IP有冲突,请为每个主机分配不同的IP
- 主机名(hostname)重复,请为每个主机设置不同的主机名
- 网卡的MAC有冲突,复制虚拟机时,请为所有网卡重新生产MAC地址
参考文档:
https://k3s.io/
https://rancher.com/docs/k3s/latest/en/
https://rancher.com/docs/k3s/latest/en/quick-start/
https://rancher.com/docs/k3s/latest/en/installation/airgap/
二、镜像加速
由于kubernetes从V1.24
版本开始默认使用**containerd**
作为容器服务,需要修改**containerd**
的配置文件,才能让Pod的镜像使用镜像加速器。
配置文件路径一般为**/etc/containerd/config.toml**
,详见阿里云镜像加速。
在K3s中配置镜像仓库
K3s 会自动生成containerd的配置文件**/var/lib/rancher/k3s/agent/etc/containerd/config.toml**,不要直接修改这个文件,k3s重启后修改会丢失。
为了简化配置,K3s 通过**/etc/rancher/k3s/registries.yaml**文件来配置镜像仓库,K3s会在启动时检查这个文件是否存在。
我们需要在每个节点上新建/etc/rancher/k3s/registries.yaml文件,配置内容如下:
1 | mirrors: |
重启每个节点
1 | systemctl restart k3s |
查看配置是否生效。
1 | cat /var/lib/rancher/k3s/agent/etc/containerd/config.toml |
三、创建和管理Pod
1 | # 创建一个pod:mynginx, 使用镜像nginx |
创建管理Deployment(部署)与ReplicaSet(副本集)
Deployment是对ReplicaSet和Pod更高级的抽象。
它使Pod拥有多副本,自愈,扩缩容、滚动升级等能力。
ReplicaSet(副本集)是一个Pod的集合。
它可以设置运行Pod的数量,确保任何时间都有指定数量的 Pod 副本在运行。
通常我们不直接使用ReplicaSet,而是在Deployment中声明。
创建deployment和replicaset
1 | #创建deployment,部署3个运行nginx的Pod |
Pod自愈功能
1 | # 删除其中一个pod |
Pod缩放功能
手动缩放
1
2
3
4
5
6
7
8
9
10
11#将副本数量调整为5
kubectl scale deployment/nginx-deployment --replicas=5
kubectl get deploy
[root@k3s-master52 ~]# kubectl get replicaset --watch
NAME DESIRED CURRENT READY AGE
nginx-deploy-855866bb46 5 5 5 23m
nginx-deploy-855866bb46 3 5 5 23m
nginx-deploy-855866bb46 3 5 5 23m
nginx-deploy-855866bb46 3 3 3 23m
nginx-deploy-855866bb46 5 3 3 23m自动缩放
自动缩放通过增加和减少副本的数量,以保持所有 Pod 的平均 CPU 利用率不超过 75%。
自动伸缩需要声明Pod的资源限制,同时使用 Metrics Server 服务(K3s默认已安装)。
本例仅用来说明
kubectl autoscale
命令的使用,完整示例参考:HPA演示
1 | #自动缩放 |
滚动更新
1 | #查看版本和Pod |
版本回滚
1 | #查看历史版本 |
四、Service 服务
- Service将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
- Service为一组 Pod 提供相同的 DNS 域名,并且在它们之间进行负载均衡。
- 服务发现:Kubernetes 为 Pod 提供分配了IP 地址,但IP地址可能会发生变化。集群内的容器可以通过service名称访问服务,而不需要担心Pod的IP发生变化。
Kubernetes Service 定义了这样一种抽象:
逻辑上的一组可以互相替换的 Pod,通常称为微服务。
Service 对应的 Pod集合 通常是通过选择算符来确定的。
举个例子,在一个Service中运行了3个nginx的副本。这些副本是可互换的,我们不需要关心它们调用了哪个nginx,也不需要关注 Pod的运行状态,只需要调用这个服务就可以了。
创建与访问Service对象
创建Service时根据type取值不同,服务暴露的方式和范围不同
●ClusterIP:将服务公开在集群内部。kubernetes会给服务分配一个集群内部的 IP,集群内的所有主机都可以通过这个Cluster-IP访问服务。集群内部的Pod可以通过service名称访问服务。
●NodePort:通过每个节点的主机IP 和静态端口(NodePort)暴露服务。 集群的外部主机可以使用节点IP和NodePort访问服务。
●ExternalName:将集群外部的网络引入集群内部。
●LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。
ClusterIP
集群内的所有主机都可以通过这个Cluster-IP访问服务。集群内部的Pod可以通过service名称访问服务。
1 | # 创建服务, 指定deploy为作为提供服务的抽象,port为pod端口, |
NodePort
每个节点的主机IP 和静态端口(NodePort)暴露服务。 集群的外部主机可以使用节点IP和NodePort访问服务。
1.NodePort端口是随机的,范围为:30000-32767。
2.集群中每一个主机节点的NodePort端口都可以访问。
3.如果需要指定端口,不想随机产生,需要使用配置文件来声明。
**命名空间(Namespace)**是一种资源隔离机制,将同一集群中的资源划分为相互隔离的组。
命名空间可以在多个用户之间划分集群资源(通过资源配额)。
- 例如我们可以设置开发、测试、生产等多个命名空间。
同一命名空间内的资源名称要唯一,但跨命名空间时没有这个要求。
命名空间作用域仅针对带有名字空间的对象,例如 Deployment、Service 等。
这种作用域对集群访问的对象不适用,例如 StorageClass、Node、PersistentVolume 等。
Kubernetes 会创建四个初始命名空间:
**default**
默认的命名空间,不可删除,未指定命名空间的对象都会被分配到default中。**kube-system**
Kubernetes 系统对象(控制平面和Node组件)所使用的命名空间。**kube-public**
** **自动创建的公共命名空间,所有用户(包括未经过身份验证的用户)都可以读取它。通常我们约定,将整个集群中公用的可见和可读的资源放在这个空间中。**kube-node-lease**
** ** 租约(Lease)对象使用的命名空间。每个节点都有一个关联的 lease 对象,lease 是一种轻量级资源。lease对象通过发送心跳,检测集群中的每个节点是否发生故障。使用
kubectl get lease -A
查看lease
对象
1 | # 获取所有namespace的所有Pod |
五、Namespace命名空间
使用多个命名空间
- 命名空间是在多个用户之间划分集群资源的一种方法(通过资源配额)。
- 例如我们可以设置开发、测试、生产等多个命名空间。
- 不必使用多个命名空间来分隔轻微不同的资源。
- 例如同一软件的不同版本: 应该使用标签 来区分同一命名空间中的不同资源。
- 命名空间适用于跨多个团队或项目的场景。
- 对于只有几到几十个用户的集群,可以不用创建命名空间。
- 命名空间不能相互嵌套,每个 Kubernetes 资源只能在一个命名空间中。
管理命名空间
1 | #创建命名空间 |
切换当前命名空间
1 | #查看当前上下文 |
六、声明式对象配置(YAML)
:::info
云原生的代表技术包括:
■容器
■服务网格
■微服务
■不可变基础设施
■声明式API
:::
管理K8S对象的方式
:::danger
●命令行指令
例如,使用kubectl命令来创建和管理 Kubernetes 对象。
命令行就好比口头传达,简单、快速、高效。
但它功能有限,不适合复杂场景,操作不容易追溯,多用于开发和调试。
:::
:::danger
●声明式配置
kubernetes使用yaml文件来描述 Kubernetes 对象。
声明式配置就好比申请表,学习难度大且配置麻烦。
好处是操作留痕,适合操作复杂的对象,多用于生产。
:::
常用命令缩写
名称 | 缩写 | Kind |
---|---|---|
namespaces | ns | Namespace |
nodes | no | Node |
pods | po | Pod |
services | svc | Service |
deployments | deploy | Deployment |
replicasets | rs | ReplicaSet |
statefulsets | sts | StatefulSet |
YAML规范
- 缩进代表上下级关系
- 缩进时不允许使用Tab键,只允许使用空格,通常缩进2个空格
**:**
键值对,后面必须有空格**-**
列表,后面必须有空格**[ ]**
数组**#**
注释**|**
多行文本块**---**
表示文档的开始,多用于分割多个资源对象
1 | group: |
配置对象
在创建的 Kubernetes 对象所对应的 yaml文件中,需要配置的字段如下:
● ** apiVersion **
- Kubernetes API 的版本
● **kind**
- 对象类别,例如Pod、Deployment、Service、ReplicaSet等
● **metadata **
- 描述对象的元数据,包括一个 name 字符串、UID 和可选的 namespace
● **spec **
- 对象的配置
掌握程度:
■不要求自己会写
■找模版
■能看懂
■会修改
■能排错
使用yaml定义一个Pod
Pod配置模版
1 | apiVersion: v1 |
使用yaml文件管理对象
1 | #创建对象 |
标签
标签(Labels) 是附加到对象(比如 Pod)上的键值对,用于补充对象的描述信息。
标签使用户能够以松散的方式管理对象映射,而无需客户端存储这些映射。
由于一个集群中可能管理成千上万个容器,我们可以使用标签高效的进行选择和操作容器集合。
:::info
键的格式:
- 前缀(可选)/名称(必须)。
有效名称和值:
- 必须为 63 个字符或更少(可以为空)
- 如果不为空,必须以字母数字字符([a-z0-9A-Z])开头和结尾
- 包含破折号-、下划线_、点.和字母或数字
:::
label配置模版1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: v1
kind: Pod
metadata:
name: label-demo
labels: #定义Pod标签
environment: test
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22
ports:
- containerPort: 801
2
3
4
5
6
7
8
9
10
11
12
13
14
15[root@k3s-master52 yaml]# vim label-pod.yaml
[root@k3s-master52 yaml]# [root@k3s-master52 yaml]# kubectl apply -f label-pod.yaml
pod/label-demo created
[root@k3s-master52 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deploy-855866bb46-clg2r 1/1 Running 0 5h32m app=nginx-deploy,pod-template-hash=855866bb46
nginx-deploy-855866bb46-8rdbn 1/1 Running 0 5h28m app=nginx-deploy,pod-template-hash=855866bb46
nginx-deploy-855866bb46-qwtvj 1/1 Running 0 5h1m app=nginx-deploy,pod-template-hash=855866bb46
my-nginx 1/1 Running 0 3m5s <none>
label-demo 1/1 Running 0 11s app=nginx,environment=test
# 按标签显示
[root@k3s-master52 yaml]# kubectl get pod -l environment=test,app=nginx
NAME READY STATUS RESTARTS AGE
label-demo 1/1 Running 0 48s
选择器 创建Service
标签选择器 可以识别一组对象。标签不支持唯一性。
标签选择器最常见的用法是为Service选择一组Pod作为后端。
1 | apiVersion: v1 |
1 | [root@k3s-master52 yaml]# kubectl apply -f my-service.yaml |
目前支持两种类型的选择运算:基于等值的和基于集合的。
多个选择条件使用逗号分隔,相当于**And(&&)**运算。
等值选择
1
2
3
4selector:
matchLabels: # component=redis && version=7.0
component: redis
version: 7.0集合选择
1
2
3
4selector:
matchExpressions: # tier in (cache, backend) && environment not in (dev, prod)
- {key: tier, operator: In, values: [cache, backend]}
- {key: environment, operator: NotIn, values: [dev, prod]}
参考资料:
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/kubernetes-objects/
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/object-management/
https://kubernetes.io/docs/reference/kubectl/#resource-types
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/labels/
七、金丝雀发布
:::info
金丝雀部署(canary deployment)也被称为灰度发布。
早期,工人下矿井之前会放入一只金丝雀检测井下是否存在有毒气体。
采用金丝雀部署,你可以在生产环境的基础设施中小范围的部署新的应用代码。
一旦应用签署发布,只有少数用户被路由到它,最大限度的降低影响。
如果没有错误发生,则将新版本逐渐推广到整个基础设施。
:::
部署过程
部署V1版本 nginx-deployment-v1
发布v1版本的应用,镜像使用nginx:1.22
,数量为 3。
- 创建Namespace
- 创建Deployment
- 创建外部访问的Service
1 | apiVersion: v1 |
1 | # 创建yaml文件,配置服务内容 |
部署V2版本 nginx-deployment-canary
创建Canary Deployment
发布新版本的应用,镜像使用docker/getting-started,数量为 1。
1 | apiVersion: apps/v1 |
1 | # 发布服务新版本 |
局限性
按照 Kubernetes 默认支持的这种方式进行金丝雀发布,有一定的局限性:
- 不能根据用户注册时间、地区等请求中的内容属性进行流量分配
- 同一个用户如果多次调用该 Service,有可能第一次请求到了旧版本的 Pod,第二次请求到了新版本的 Pod
在 Kubernetes 中不能解决上述局限性的原因是:Kubernetes Service 只在 TCP 层面解决负载均衡的问题,并不对请求响应的消息内容做任何解析和识别。如果想要更完善地实现金丝雀发布,可以考虑Istio灰度发布。
参考文档:
https://www.infoq.cn/article/lei4vsfpiw5a6en-aso4
https://kuboard.cn/learning/k8s-intermediate/workload/wl-deployment/canary.html