kubernetes——part3-5 核心概念 Service

一、 service作用

使用kubernetes集群运行工作负载时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务,Kubernetes中使用了Service来解决这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化 ,只要有Label,就可以让Service能够联系上Pod,把PodIP地址添加到Service对应的端点列表(Endpoints)实现对Pod IP跟踪,进而实现通过Service访问Pod目的。

  • 通过service为pod客户端提供访问pod方法,即可客户端访问pod入口
  • 通过标签动态感知pod IP地址变化等
  • 防止pod失联
  • 定义访问pod访问策略
  • 通过label-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)
  • 底层实现由kube-proxy通过userspace、iptables、ipvs三种代理模式

二、kube-proxy三种代理模式

  • kubernetes集群中有三层网络,一类是真实存在的,例如Node Network、Pod Network,提供真实IP地址;一类是虚拟的,例如Cluster Network或Service Network,提供虚拟IP地址,不会出现在接口上,仅会出现在Service当中

  • kube-proxy始终watch(监控)kube-apiserver上关于Service相关的资源变动状态,一旦获取相关信息kube-proxy都要把相关信息转化为当前节点之上的,能够实现Service资源调度到特定Pod之上的规则,进而实现访问Service就能够获取Pod所提供的服务

  • kube-proxy三种代理模式:UserSpace模式、iptables模式、ipvs模式

2.1 UserSpace模式

不再使用了解即可
userspace 模式是 kube-proxy 使用的第一代模式,该模式在 kubernetes v1.0 版本开始支持使用。

userspace 模式的实现原理图示如下:

在这里插入图片描述

kube-proxy 会为每个 Service 随机监听一个端口(proxy port),并增加一条 iptables 规则。所以通过 ClusterIP:Port 访问 Service 的报文都 redirect 到 proxy port,kube-proxy 从它监听的 proxy port 收到报文以后,走 round robin(默认) 或是 session affinity(会话亲和力,即同一 client IP 都走同一链路给同一 pod 服务),分发给对应的 pod。

由于 userspace 模式会造成所有报文都走一遍用户态(也就是 Service 请求会先从用户空间进入内核 iptables,然后再回到用户空间,由 kube-proxy 完成后端 Endpoints 的选择和代理工作),需要在内核空间和用户空间转换,流量从用户空间进出内核会带来性能损耗,所以这种模式效率低、性能不高,不推荐使用。

在这里插入图片描述

2.2 iptables模式

iptables 模式是 kube-proxy 使用的第二代模式,该模式在 kubernetes v1.1 版本开始支持,从 v1.2 版本开始成为 kube-proxy 的默认模式。

iptables 模式的负载均衡模式是通过底层 netfilter/iptables 规则来实现的,通过 Informer 机制 Watch 接口实时跟踪 Service 和 Endpoint 的变更事件,并触发对 iptables 规则的同步更新。

iptables 模式的实现原理图示如下:

在这里插入图片描述

通过图示我们可以发现在 iptables 模式下,kube-proxy 只是作为 controller,而不是 server,真正服务的是内核的 netfilter,体现在用户态的是 iptables。所以整体的效率会比 userspace 模式高。

在这里插入图片描述

2.3 ipvs模式

ipvs 模式被 kube-proxy 采纳为第三代模式,模式在 kubernetes v1.8 版本开始引入,在 v1.9 版本中处于 beta 阶段,在 v1.11 版本中正式开始使用。

ipvs(IP Virtual Server) 实现了传输层负载均衡,也就是 4 层交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器前充当负载均衡器。ipvs 可以将基于 TCP 和 UDP 的服务请求转发到真实服务器上,并使真实服务器上的服务在单个 IP 地址上显示为虚拟服务。

ipvs 模式的实现原理图示如下:

在这里插入图片描述
在这里插入图片描述

ipvs 和 iptables 都是基于 netfilter 的,那么 ipvs 模式有哪些更好的性能呢?

  • ipvs 为大型集群提供了更好的可拓展性和性能
  • ipvs 支持比 iptables 更复杂的负载均衡算法(包括:最小负载、最少连接、加权等)
  • ipvs 支持服务器健康检查和连接重试等功能
  • 可以动态修改 ipset 的集合,即使 iptables 的规则正在使用这个集合

ipvs 依赖于 iptables。ipvs 会使用 iptables 进行包过滤、airpin-masquerade tricks(地址伪装)、SNAT 等功能,但是使用的是 iptables 的扩展 ipset,并不是直接调用 iptables 来生成规则链。通过 ipset 来存储需要 DROP 或 masquerade 的流量的源或目标地址,用于确保 iptables 规则的数量是恒定的,这样我们就不需要关心有多少 Service 或是 Pod 了。

使用 ipset 相较于 iptables 有什么优点呢?iptables 是线性的数据结构,而 ipset 引入了带索引的数据结构,当规则很多的时候,ipset 依然可以很高效的查找和匹配。我们可以将 ipset 简单理解为一个 IP(段) 的集合,这个集合的内容可以是 IP 地址、IP 网段、端口等,iptables 可以直接添加规则对这个“可变的集合进行操作”,这样就可以大大减少 iptables 规则的数量,从而减少性能损耗。

举一个例子,如果我们要禁止成千上万个 IP 访问我们的服务器,如果使用 iptables 就需要一条一条的添加规则,这样会在 iptables 中生成大量的规则;如果用 ipset 就只需要将相关的 IP 地址(网段)加入到 ipset 集合中,然后只需要设置少量的 iptables 规则就可以实现这个目标。

下面的表格是 ipvs 模式下维护的 ipset 表集合:

设置名称成员用法
KUBE-CLUSTER-IP所有服务 IP + 端口在 masquerade-all=true 或 clusterCIDR 指定的情况下对 Service Cluster IP 地址进行伪装,解决数据包欺骗问题
KUBE-LOOP-BACK所有服务 IP + 端口 + IP解决数据包欺骗问题
KUBE-EXTERNAL-IP服务外部 IP + 端口将数据包伪装成 Service 的外部 IP 地址
KUBE-LOAD-BALANCER负载均衡器入口 IP + 端口将数据包伪装成 Load Balancer 类型的 Service
KUBE-LOAD-BALANCER-LOCAL负载均衡器入口 IP + 端口 以及externalTrafficPolicy=local接受数据包到 Load Balancer externalTrafficPolicy=local
KUBE-LOAD-BALANCER-FW负载均衡器入口 IP + 端口 以及loadBalancerSourceRanges使用指定的 loadBalancerSourceRanges 丢弃 Load Balancer 类型 Service 的数据包
KUBE-LOAD-BALANCER-SOURCE-CIDR负载均衡器入口 IP + 端口 + 源 CIDR接受 Load Balancer 类型 Service 的数据包,并指定 loadBalancerSourceRanges
KUBE-NODE-PORT-TCPNodePort 类型服务 TCP 端口将数据包伪装成 NodePort(TCP)
KUBE-NODE-PORT-LOCAL-TCPNodePort 类型服务 TCP 端口,带有externalTrafficPolicy=local接受数据包到 NodePort 服务,使用 externalTrafficPolicy=local
KUBE-NODE-PORT-UDPNodePort 类型服务 UDP 端口将数据包伪装成 NodePort(UDP)
KUBE-NODE-PORT-LOCAL-UDPNodePort 类型服务 UDP 端口,使用externalTrafficPolicy=local接受数据包到 NodePort 服务,使用 externalTrafficPolicy=local

2.4 iptables与ipvs对比

  • iptables

    • 工作在内核空间
    • 优点
      • 灵活,功能强大(可以在数据包不同阶段对包进行操作)
    • 缺点
      • 表中规则过多时,响应变慢,即规则遍历匹配和更新,呈线性时延
  • ipvs

    • 工作在内核空间
    • 优点
      • 转发效率高
      • 调度算法丰富:rr,wrr,lc,wlc,ip hash…
    • 缺点
      • 内核支持不全,低版本内核不能使用,需要升级到4.0或5.0以上。
  • 使用iptables与ipvs时机

    • 1.10版本之前使用iptables(1.1版本之前使用UserSpace进行转发)
    • 1.11版本之后同时支持iptables与ipvs,默认使用ipvs,如果ipvs模块没有加载时,会自动降级至iptables

三、 service类型

Service类型决定了访问Service的方法

3.1 service类型

  • ClusterIP

    • 默认,分配一个集群内部可以访问的虚拟IP
  • NodePort

    • 在每个Node上分配一个端口作为外部访问入口
    • nodePort端口范围为:30000-32767
  • LoadBalancer

    • 工作在特定的Cloud Provider上,例如Google Cloud,AWS,OpenStack
  • ExternalName

    • 表示把集群外部的服务引入到集群内部中来,即实现了集群内部pod和集群外部的服务进行通信

3.2 Service参数

  • port 访问service使用的端口

  • targetPort Pod中容器端口 (容器内的端口,例如nginx,80端口)

  • nodePort 通过Node实现外网用户访问k8s集群内service (30000-32767)(适用于nodeport模式)

四、 Service创建

Service的创建在工作中有两种方式,一是命令行创建,二是通过资源清单文件YAML文件创建。

4.1 ClusterIP类型

ClusterIP根据是否生成ClusterIP又可分为普通Service和Headless Service

Service两类:

  • 普通Service:

为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP), 实现集群内的访问。

  • Headless Service:

该服务不会分配Cluster IP, 也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的网络ID来访问,DNS会将headless service的后端直接解析为pod IP列表。

在这里插入图片描述

4.1.1 普通ClusterIP Service创建

4.1.1.1 命令行创建Service
  • 创建Deployment类型的应用
[root@master01 ~]# cat 01_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
  • 应用资源清单文件
[root@master01 ~]# kubectl apply -f 01_create_deployment_app_nginx.yaml
  • 验证Deployment类型的创建情况
[root@master01 ~]# kubectl get deployment.apps
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
nginx-server1   2/2     2            2           13s
  • 创建ClusterIP类型service与Deployment类型应用关联
命令创建service
[root@master01 ~]# kubectl expose deployment.apps nginx-server1 --type=ClusterIP --target-port=80 --port=80
输出
service/nginx-server1 exposed
说明
expose 创建service
deployment.apps 控制器类型
nginx-server1 应用名称,也是service名称
--type=ClusterIP 指定service类型
--target-port=80 指定Pod中容器端口
--port=80 指定service端口
4.1.1.2 通过资源清单文件创建Service
[root@master01 ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-smartimage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-svc
spec:type: ClusterIPports:- protocol: TCPport: 80targetPort: 80selector:app: nginx
[root@master01 ~]# kubectl  apply -f 02_create_deployment_app_nginx_with_service.yaml
  • 验证
查看service
[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    4d15h
nginx-svc    ClusterIP   10.101.153.50   <none>        80/TCP    3s
查看endpoints
[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                            AGE
kubernetes   192.168.122.30:6443                  4d15h
nginx-svc    172.16.189.74:80,172.16.235.150:80   8s
查看Pod
[root@master01 ~]# kubectl get pods -l app=nginx
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-77d4c485d8-gsrmq   1/1     Running   0          12s
nginx-server1-77d4c485d8-mmc52   1/1     Running   0          12s
4.1.1.3 访问
[root@master01 ~]# curl http://10.101.153.50:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
4.1.1.4 两个pod里做成不同的主页方便测试负载均衡
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-gsrmq -- /bin/bash
root@deployment-nginx-6fcfb67547-nv7dn:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# echo web1 > index.html
root@deployment-nginx-6fcfb67547-nv7dn:/usr/share/nginx/html# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-77d4c485d8-mmc52 -- /bin/bash
root@deployment-nginx-6fcfb67547-rqrcw:/# cd /usr/share/nginx/html/
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# echo web2 > index.html
root@deployment-nginx-6fcfb67547-rqrcw:/usr/share/nginx/html# exit
exit
4.1.1.5 测试
[root@master01 ~]# curl 10.101.153.50[root@master01 ~]# while true;do curl 10.101.153.50;sleep 1; done

4.1.2 Headless Service

  • 普通的ClusterIP service是service name解析为cluster ip,然后cluster ip对应到后面的pod ip
  • Headless service是指service name 直接解析为后面的pod ip
4.1.2.1 编写用于创建Deployment控制器类型的资源清单文件
[root@master01 ~]# cat 03_create_deployment_app_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-smartimage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
4.1.2.2 通过资源清单文件创建headless Service
编写YAML文件
命令
[root@master ~]# vim 04_headless-service.yml
apiVersion: v1
kind: Service
metadata:name: headless-servicenamespace: default
spec:type: ClusterIP     # ClusterIP类型,也是默认类型clusterIP: None     # None就代表是无头serviceports:                                # 指定service 端口及容器端口- port: 80                            # service ip中的端口protocol: TCPtargetPort: 80                      # pod中的端口selector:                             # 指定后端pod标签app: nginx                    # 可通过kubectl get pod -l app=nginx查看哪些pod在使用此标签
4.1.2.3 应用资源清单文件创建headless Service
命令
[root@master ~]# kubectl apply -f 04_headless_service.yml
输出
service/headless-service created
4.1.2.4 查看已创建的headless Service
命令
[root@master ~]# kubectl get svc
输出
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
headless-service   ClusterIP   None             <none>        80/TCP           2m18s
kubernetes         ClusterIP   10.96.0.1        <none>        443/TCP          5d9h
可以看到headless-service没有CLUSTER-IP,用None表示
4.1.2.5 DNS

DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析

headless service需要DNS来解决访问问题

DNS记录格式为: ..svc.cluster.local.

4.1.2.5.1 查看kube-dns服务的IP
命令
[root@master1 ~]# kubectl get svc -n kube-system输出
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.2      <none>        53/UDP,53/TCP,9153/TCP   5d9h
metrics-server   ClusterIP   10.105.219.44   <none>        443/TCP                  45h
查看到coreDNS的服务地址是10.96.0.2
4.1.2.5.2 在集群主机通过DNS服务地址查找无头服务的dns解析
命令
[root@master01 ~]# dig -t A headless-service.default.svc.cluster.local. @10.96.0.2输出
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.2 <<>> -t A headless-service.default.svc.cluster.local. @10.96.0.2
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31371
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;headless-service.default.svc.cluster.local. IN A #被解析域名;; ANSWER SECTION:
headless-service.default.svc.cluster.local. 30 IN A 10.224.235.147 #注意这里IP;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.2)
;; WHEN: Sun May 17 10:58:50 CST 2020
;; MSG SIZE  rcvd: 129
4.1.2.5.3 验证pod的IP
命令
[root@master ~]# kubectl get pod -o wide
输出
NAME                                READY   STATUS             RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
nginx-deployment-56bf6c9c8c-jmk7r   1/1     Running            0          35m   10.224.235.147   worker1   <none>           <none>
4.1.2.5.4 在集群中创建一个pod验证

创建一个镜像为busyboxplus:curl的pod,pod名称为bb2,用来解析域名

命令
[root@master01 ~]# kubectl run bbp --image=busyboxplus:curl -it[root@master01 ~]# kubectl run bbp --image=1.28 -it输出
If you don't see a command prompt, try pressing enter.解析域名
nslookup headless-service.default.svc.cluster.local.
访问命令
[ root@bbp:/ ]$ curl http://headless-service.default.svc.cluster.local.输出
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
[ root@bbp:/ ]$ exit
Session ended, resume using 'kubectl attach bbp -c bbp -i -t' command when the pod is running

4.2 NodePort类型

  • 创建资源清单文件
[root@master01 ~]# cat 05_create_nodeport_service_app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-applabels:app: nginx-app
spec:replicas: 2selector:matchLabels:app: nginx-apptemplate:metadata:labels:app: nginx-appspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-app
spec:type: NodePortselector:app: nginx-appports:- protocol: TCPnodePort: 30001port: 8060targetPort: 80
  • 应用资源清单文件
[root@master01 ~]# kubectl apply -f 05_create_nodeport_service_app.yaml
deployment.apps/nginx-app created
service/nginx-app created
  • 验证service创建
[root@master01 ~]# kubectl get deployment.apps
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app    2/2     2            2           26s[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          2d22h
nginx-app    NodePort    10.104.157.20    <none>        8060:30001/TCP   36s[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                       AGE
kubernetes   192.168.122.10:6443             2d22h
nginx-app    172.16.1.24:80,172.16.2.20:80   2m10s[root@master01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5826,fd=9))[root@worker01 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=4937,fd=11))[root@worker02 ~]# ss -anput | grep ":30001"
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=5253,fd=11))
[root@master01 ~]# kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
nginx-app-ffd5ccc78-cnwbx    1/1     Running   0          8m59s
nginx-app-ffd5ccc78-mz77g    1/1     Running   0          8m59s[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-cnwbx -- bash
root@nginx-app-ffd5ccc78-cnwbx:/# echo "nginx-app-1" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-cnwbx:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-app-ffd5ccc78-mz77g -- bash
root@nginx-app-ffd5ccc78-mz77g:/# echo "nginx-app-2" > /usr/share/nginx/html/index.html
root@nginx-app-ffd5ccc78-mz77g:/# exit
exit
  • 在与kubernetes 节点同一网络主机中访问k8s集群内service
[root@bogon ~]# curl http://192.168.10.12:30001
nginx-app-2
[root@bogon ~]# curl http://192.168.10.13:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.14:30001
nginx-app-1
[root@bogon ~]# curl http://192.168.10.15:30001
nginx-app-2

4.3 LoadBalancer

负载均衡,类似阿里云的slb

4.3.1 集群外访问过程

在这里插入图片描述

4.3.2 自建Kubernetes的LoadBalancer类型服务方案-MetalLB

(如果是kubeadm创建的k8s集群先执行第6部分)
MetalLB可以为kubernetes集群中的Service提供网络负载均衡功能。

MetalLB两大功能为:

  • 地址分配,类似于DHCP
  • 外部通告,一旦MetalLB为服务分配了外部IP地址,它就需要使群集之外的网络意识到该IP在群集中“存在”。MetalLB使用标准路由协议来实现此目的:ARP,NDP或BGP。
4.3.2.1 参考资料

参考网址: https://metallb.universe.tf/installation/

4.3.2.2 应用资源清单文件
资源清单文件下载:
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
4.3.2.3 准备metallb配置文件
[root@nginx metallb]# cat metallb-conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:namespace: metallb-systemname: config
data:config: |address-pools:- name: defaultprotocol: layer2addresses:- 192.168.10.90-192.168.10.100192.168.10.90-192.168.10.100是集群节点服务器IP同一段。
在master01节点应用资源清单文件
[root@master01 ~]# kubectl apply -f metallb-conf.yaml	
验证配置
# kubectl describe configmap config -n metallb-system
Name:         config
Namespace:    metallb-system
Labels:       <none>
Annotations:  <none>Data
====
config:
----
address-pools:
- name: defaultprotocol: layer2addresses:- 192.168.10.90-192.168.10.100Events:  <none>
4.3.2.4发布Service类型为LoadBalancer的Deployment控制器类型应用
创建Deployment控制器类型应用nginx-metallb及service,service类型为LoadBalancer[root@master01 ~]# vim 02_nginx-metabllb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-metallb
spec:selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginx-metallb1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80---
apiVersion: v1
kind: Service
metadata:name: nginx-metallb
spec:ports:- port: 8090protocol: TCPtargetPort: 80selector:app: nginxtype: LoadBalancer[root@master01 ~]# kubectl apply -f nginx.yaml
4.3.2.5 验证
[root@master01 ~]# kubectl get ns
NAME                   STATUS   AGE
default                Active   16d
kube-node-lease        Active   16d
kube-public            Active   16d
kube-system            Active   16d
kubernetes-dashboard   Active   13d
metallb-system         Active   130m
test1                  Active   12d
[root@master01 ~]# kubectl get pods -n metallb-system
NAME                         READY   STATUS    RESTARTS   AGE
controller-64f8f944d-qdf8m   1/1     Running   0          110m
speaker-cwzq7                1/1     Running   0          110m
speaker-qk5fb                1/1     Running   0          110m
speaker-wsllb                1/1     Running   0          110m
speaker-x4bwt                1/1     Running   0          110m[root@master01 ~]# kubectl get svc
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
kubernetes      ClusterIP      10.96.0.1       <none>           443/TCP          16d
nginx-metallb   LoadBalancer   10.105.239.69   192.168.10.90   8090:31372/TCP   106m[root@master01 ~]# ping 192.168.10.90
PING 192.168.10.90 (192.168.10.90) 56(84) bytes of data.
64 bytes from 192.168.10.90: icmp_seq=1 ttl=64 time=3.45 ms
64 bytes from 192.168.10.90: icmp_seq=2 ttl=64 time=0.040 ms
4.3.2.6 访问
[root@master01 ~]# curl http://192.168.122.90:8090
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>

在这里插入图片描述

注意:使用kubeadm部署kubernetes集群修改方法

如果在IPVS模式下使用kube-proxy,从Kubernetes v1.14.2开始,必须启用ARP模式。可以通过在当前集群中编辑kube-proxy配置来实现:
# kubectl edit configmap -n kube-system kube-proxy并设置:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:strictARP: true

4.4 ExternalName

4.4.1 ExternalName作用

  • 把集群外部的服务引入到集群内部中来,实现了集群内部pod和集群外部的服务进行通信
  • ExternalName 类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口
  • 还有一点要注意: 集群内的Pod会继承Node上的DNS解析规则。所以只要Node可以访问的服务,Pod中也可以访问到, 这就实现了集群内服务访问集群外服务

4.4.2 将公网域名引入

1, 编写YAML文件

 [root@master01 ~]# vim externelname.ymlapiVersion: v1
kind: Service
metadata:name: my-externalnamenamespace: default
spec:type: ExternalNameexternalName: www.baidu.com                  # 对应的外部域名为www.baidu.com

2, 应用YAML文件

 [root@master01 ~]# kubectl apply -f externelname.ymlservice/my-externalname created

3, 查看service

 [root@master01 ~]# kubectl get svc |grep extermy-externalname    ExternalName   <none>         www.baidu.com   <none>         69s

4, 查看my-service的dns解析

 [root@master01 ~]# dig -t A my-externalname.default.svc.cluster.local. @10.96.0.2; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t A my-externalname.default.svc.cluster.local. @10.2.0.2;; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31378;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;my-externalname.default.svc.cluster.local. IN A;; ANSWER SECTION:my-externalname.default.svc.cluster.local. 5 IN CNAME www.baidu.com.www.baidu.com.          5       IN      CNAME   www.a.shifen.com.www.a.shifen.com.       5       IN      A       14.215.177.38           解析的是百度的IPwww.a.shifen.com.       5       IN      A       14.215.177.39           解析的是百度的IP;; Query time: 32 msec;; SERVER: 10.2.0.2#53(10.96.0.2);; WHEN: Thu Nov 05 11:23:41 CST 2020;; MSG SIZE  rcvd: 245
 [root@master01 ~]# kubectl exec -it deploy-nginx-6c9764bb69-86gwj -- /bin/sh/ # nslookup www.baidu.com......Name:      www.baidu.comAddress 1: 14.215.177.39Address 2: 14.215.177.38/ # nslookup my-externalname.default.svc.cluster.local         ......Name:      my-externalname.default.svc.cluster.localAddress 1: 14.215.177.38Address 2: 14.215.177.39

解析此my-externalname.default.svc.cluster.local域名和解析www.baidu.com是一样的结果

4.4.3 不同命名空间访问

1, 创建ns1命名空间和相关deploy, pod,service

 [root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             name: ns1                                                     # 创建ns1命名空间
---
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-nginx                    namespace: ns1                                                # 属于ns1命名空间
spec:replicas: 1                                  selector:matchLabels:app: nginx                                template:                                        metadata:labels:app: nginx                             spec:containers:                              - name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: svc1                                # 服务名namespace: ns1                            # 属于ns1命名空间
spec:selector:app: nginxclusterIP: None                           # 无头serviceports:- port: 80                         targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:name: external-svc1namespace: ns1                            #  属于ns1命名空间
spec:type: ExternalNameexternalName: svc2.ns2.svc.cluster.local   # 将ns2空间的svc2服务引入到ns1命名空间[root@master1 ~]# kubectl apply -f ns1-nginx.ymlnamespace/ns1 createddeployment.apps/deploy-nginx createdservice/svc1 created

2, 创建ns2命名空间和相关deploy, pod,service

[root@master01 ~]# vim ns1-nginx.yml
apiVersion: v1                                                  
kind: Namespace                                                 
metadata:                                                             name: ns2                                                     # 创建ns2命名空间
---
apiVersion: apps/v1
kind: Deployment
metadata:name: deploy-nginx                    namespace: ns2                                                # 属于ns2命名空间
spec:replicas: 1                                  selector:matchLabels:app: nginx                                template:                                        metadata:labels:app: nginx                             spec:containers:                              - name: nginximage: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: svc2                                # 服务名namespace: ns2                            # 属于ns2命名空间
spec:selector:app: nginxclusterIP: None                           # 无头serviceports:- port: 80                         targetPort: 80                  
---
kind: Service
apiVersion: v1
metadata:name: external-svc1namespace: ns2                            #  属于ns2命名空间
spec:type: ExternalNameexternalName: svc1.ns1.svc.cluster.local   # 将ns1空间的svc1服务引入到ns2命名空间
 [root@master01 ~]# kubectl apply -f ns2-nginx.ymlnamespace/ns2 createddeployment.apps/deploy-nginx createdservice/svc2 createdservice/external-svc2 created

3, 在ns1命名空间的pod里验证

 [root@master01 ~]# kubectl get pods -n ns1NAME                            READY   STATUS    RESTARTS   AGEdeploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          8m10s
 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh/ # nslookup svc1......Name:      svc1Address 1: 10.3.166.140 deploy-nginx-6c9764bb69-g5xl8       IP与ns1里的podIP一致(见下面的查询结果)/ # nslookup svc2.ns2.svc.cluster.local.....Name:      svc2.ns2.svc.cluster.localAddress 1: 10.3.104.17 10-3-104-17.svc2.ns2.svc.cluster.local   IP与ns2里的podIP一致(见下面的查询结果)/ # exit
 [root@master01 ~]# kubectl get pods -o wide -n ns1NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE             NOMINATED NODE   READINESS GATESdeploy-nginx-6c9764bb69-g5xl8   1/1     Running   0          70m   10.3.166.140   192.168.122.13   <none>           <none>[root@master01 ~]# kubectl get pods -o wide -n ns2NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE             NOMINATED NODE   READI            NESS GATESdeploy-nginx-6c9764bb69-8psxl   1/1     Running   0          68m   10.3.104.17   192.168.122.14   <none>           <none>

反之,在ns2命名空间的pod里访问svc1.ns1.svc.cluster.local,解析的IP是ns1命名空间里的pod的IP(请自行验证)

4, 验证ns2中的pod的IP变化, ns1中的pod仍然可以使用svc2.ns2.svc.cluster.local访问

 [root@master01 ~]# kubectl get pod -n ns2NAME                            READY   STATUS    RESTARTS   AGEdeploy-nginx-6c9764bb69-8psxl   1/1     Running   0          81m[root@master01 ~]# kubectl delete pod deploy-nginx-6c9764bb69-8psxl -n ns2pod "deploy-nginx-6c9764bb69-8psxl" deleted                   因为有replicas控制器,所以删除pod会自动拉一个起来[root@master01 ~]# kubectl get pod -o wide -n ns2NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE             NOMINATED NODE   READINESS GATESdeploy-nginx-6c9764bb69-8qbz2   1/1     Running   0          5m36s   10.3.166.141   192.168.122.13   <none>           <none>pod名称变了,IP也变成了10.3.166.141

回到ns1中的pod验证

 [root@master01 ~]# kubectl exec -it -n ns1 deploy-nginx-6c9764bb69-g5xl8 -- /bin/sh/ # ping svc2.ns2.svc.cluster.local -c 2PING svc2.ns2.svc.cluster.local (10.3.166.141): 56 data bytes    解析的IP就是ns2中pod的新IP64 bytes from 10.3.166.141: seq=0 ttl=63 time=0.181 ms64 bytes from 10.3.166.141: seq=1 ttl=63 time=0.186 ms--- svc2.ns2.svc.cluster.local ping statistics ---2 packets transmitted, 2 packets received, 0% packet lossround-trip min/avg/max = 0.181/0.183/0.186 ms/ # exit

五、sessionAffinity

会话粘贴

设置sessionAffinity为Clientip (类似nginx的ip_hash算法,lvs的sh算法)

[root@nginx ~]# cat 02_create_deployment_app_nginx_with_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-server1
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: c1image: nginx:1.15-alpineimagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-svc
spec:type: ClusterIPports:- protocol: TCPport: 80targetPort: 80selector:app: nginx
[root@master01 ~]# kubectl apply -f 02_create_deployment_app_nginx_with_service.yaml
deployment.apps/nginx-server1 created
service/nginx-svc created
[root@master01 ~]# kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
nginx-server1-58845f75f4-9zlnw   1/1     Running   0          2m11s
nginx-server1-58845f75f4-ffqdt   1/1     Running   0          2m11s
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-9zlnw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-9zlnw:/# echo web1 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-9zlnw:/# exit
exit
[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-ffqdt bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx-server1-58845f75f4-ffqdt:/# echo web2 > /usr/share/nginx/html/index.html
root@nginx-server1-58845f75f4-ffqdt:/# exit
exit
[root@master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   16d
nginx-svc    ClusterIP   10.100.53.31   <none>        80/TCP    3m53s
[root@master01 ~]# curl http://10.100.53.31
web1
[root@master01 ~]# curl http://10.100.53.31
web2
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/nginx-svc patched[root@master01 ~]# curl 10.100.53.31
web1
多次访问,会话粘贴
设置回sessionAffinity为None
[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"None"}}'
service/my-service patched
测试
[root@master01 ~]# curl 10.100.53.31
web1
多次访问,回到负载均衡
或
[root@master01 ~]# while true;do curl 10.100.53.31;sleep 1; done
web1
多次访问,会话粘贴

六、修改为ipvs调度方式(拓展)

部署方式不同,修改方法不一样。

本次主要介绍使用kubeadm部署集群方式,二进制部署较为简单。

二进制部署修改:/etc/kubernetes/kube-proxy.yaml文件即可。

从kubernetes1.8版本开始,新增了kube-proxy对ipvs的支持,在kubernetes1.11版本中被纳入了GA.

6.1 修改为IPVS调度方式前升级内核

现使用Centos7u6发布版本,默认内核版本为3.10.0,使用kubernetes为1.18.0时,可升级内核版本至4.18.0或5.6.0版本。

在所有节点中安装,需要重启操作系统更换内核。以下升级方法供参考。

[root@localhost ~]# yum -y install perl[root@localhost ~]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org[root@localhost ~]# yum -y install https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm[root@localhost ~]# yum  --enablerepo="elrepo-kernel"  -y install kernel-ml.x86_64 
此处升级为5.0以上版本。[root@localhost ~]# grub2-set-default 0[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg[root@localhost ~]# reboot

6.2 修改kube-proxy的配置文件

[root@master01 ~]# kubectl edit configmap kube-proxy -n kube-system26     iptables:27       masqueradeAll: false28       masqueradeBit: 1429       minSyncPeriod: 0s30       syncPeriod: 30s31     ipvs:32       excludeCIDRs: null33       minSyncPeriod: 0s34       scheduler: ""	  # 可以在这里修改ipvs的算法,默认为rr轮循算法35       strictARP: false36       syncPeriod: 30s37     kind: KubeProxyConfiguration38     metricsBindAddress: 127.0.0.1:1024939     mode: "ipvs"	  # 默认""号里为空,加上ipvs

6.3 查看kube-system的namespace中kube-proxy有关的pod

[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-69mv6                           1/1     Running   6          2d18h
kube-proxy-jpc6c                           1/1     Running   4          4d16h
kube-proxy-kq65l                           1/1     Running   4          4d16h
kube-proxy-lmphf                           1/1     Running   5          4d16h

6.4 验证kube-proxy-xxx的pod中的信息

[root@master01 ~]# kubectl logs kube-proxy-jpc6c -n kube-system
W0517 00:55:10.914754       1 server_others.go:559] Unknown proxy mode "", assuming iptables proxy
I0517 00:55:10.923228       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 00:55:10.923264       1 server_others.go:186] Using iptables Proxier.
I0517 00:55:10.923567       1 server.go:583] Version: v1.18.2
I0517 00:55:10.923965       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_max' to 131072
I0517 00:55:10.924001       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 00:55:10.924258       1 conntrack.go:83] Setting conntrack hashsize to 32768
I0517 00:55:10.927041       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_established' to 86400
I0517 00:55:10.927086       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_tcp_timeout_close_wait' to 3600
I0517 00:55:10.927540       1 config.go:315] Starting service config controller
I0517 00:55:10.927556       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 00:55:10.927576       1 config.go:133] Starting endpoints config controller
I0517 00:55:10.927594       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 00:55:11.027749       1 shared_informer.go:230] Caches are synced for service config
I0517 00:55:11.027858       1 shared_informer.go:230] Caches are synced for endpoints config

6.5 重新启动kube-proxy

删除kube-proxy-xxx的所有pod,让它重新拉取新的kube-proxy-xxx的pod

[root@master01 ~]# kubectl delete pod kube-proxy-69mv6 -n kube-system
pod "kube-proxy-69mv6" deleted[root@master01 ~]# kubectl delete pod kube-proxy-jpc6c -n kube-system
pod "kube-proxy-jpc6c" deleted[root@master01 ~]# kubectl delete pod kube-proxy-kq65l -n kube-system
pod "kube-proxy-kq65l" deleted[root@master01 ~]# kubectl delete pod kube-proxy-lmphf -n kube-system
pod "kube-proxy-lmphf" deleted
[root@master01 ~]# kubectl get pods -n kube-system |grep kube-proxy
kube-proxy-2mk2b                           1/1     Running   0          2m23s
kube-proxy-5bj87                           1/1     Running   0          30s
kube-proxy-7qq9l                           1/1     Running   0          52s
kube-proxy-tjtqf                           1/1     Running   0          80s
随意查看其中1个或3个kube-proxy-xxx的pod,验证是否为IPVS方式了[root@master1 ~]# kubectl logs kube-proxy-tjtqf -n kube-system
I0517 02:32:26.557696       1 node.go:136] Successfully retrieved node IP: 192.168.122.32
I0517 02:32:26.557745       1 server_others.go:259] Using ipvs Proxier.
W0517 02:32:26.557912       1 proxier.go:429] IPVS scheduler not specified, use rr by default
I0517 02:32:26.560008       1 server.go:583] Version: v1.18.2
I0517 02:32:26.560428       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0517 02:32:26.561094       1 config.go:315] Starting service config controller
I0517 02:32:26.562251       1 shared_informer.go:223] Waiting for caches to sync for service config
I0517 02:32:26.561579       1 config.go:133] Starting endpoints config controller
I0517 02:32:26.562271       1 shared_informer.go:223] Waiting for caches to sync for endpoints config
I0517 02:32:26.662541       1 shared_informer.go:230] Caches are synced for service config
I0517 02:32:26.662566       1 shared_informer.go:230] Caches are synced for endpoints config

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/31902.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【脚本】Linux一键扩大虚拟内存的大小

Linux增加虚拟内存其实很简单 就那几个命令&#xff0c;free、mkswap、swapon 但是方便起见我写成了脚本 使用方法 进入你的目录&#xff0c; nano ./install_swap.sh 下面的脚本全文复制&#xff0c;粘贴进去之后&#xff0c;按ctrlx后按y保存 然后运行以下命令 sudo bash …

学习 MySQL 需要知道的 28 个小技巧

前言 随着信息技术的不断发展以及互联网行业的高速增长&#xff0c;作为开源数据库的MySQL得到了广泛的应用和发展。目前MySQL已成为关系型数据库领域中非常重要的一员。 无论是运维、开发、测试&#xff0c;还是架构师&#xff0c;数据库技术都是一个 必备加薪神器&#xff…

【Hive】Hive安装

Hive 第一章 Hive的基础知识 第二章 Hive安装 第三章 DDL&#xff08;Data Definition Language&#xff09;数据定义 第四章 DML&#xff08;Data Manipulation Language&#xff09;数据操作 第五章 Hive查询 第六章 Hive的基础知识 第七章 Hive函数 第八章 分区表和分桶表 …

6.聊天室环境安装 - Ubuntu22.04 - elasticsearch(es)的安装和使用

目录 介绍安装安装kibana安装ES客户端使用 介绍 Elasticsearch&#xff0c; 简称 ES&#xff0c;它是个开源分布式搜索引擎&#xff0c;它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自动发现&#xff0c;索引自动分片&#xff0c;索引副本机制&#xff0c;res…

蓝桥每日打卡--合根植物

#蓝桥#JAVA#合根植物 题目描述 w星球的一个种植园&#xff0c;被分成mn个小格子&#xff08;东西方向m行&#xff0c;南北方向n列&#xff09;。每个格子里种了一株合根植物。 这种植物有个特点&#xff0c;它的根可能会沿着南北或东西方向伸展&#xff0c;从而与另一个格子…

线性代数之矩阵特征值与特征向量的数值求解方法

文章目录 前言1. 幂迭代法&#xff08;Power Iteration&#xff09;幂法与反幂法求解矩阵特征值幂法求最大特征值编程实现补充说明 2. 逆幂迭代法&#xff08;Inverse Iteration&#xff09;移位反幂法 3. QR 算法&#xff08;QR Algorithm&#xff09;——稠密矩阵理论推导编程…

【Linux实践系列】:用c语言实现一个shell外壳程序

&#x1f525;本文专栏&#xff1a;Linux Linux实践项目 &#x1f338;博主主页&#xff1a;努力努力再努力wz 那么今天我们就要进入Linux的实践环节&#xff0c;那么我们之前学习了进程控制相关的几个知识点&#xff0c;比如进程的终止以及进程的等待和进程的替换&#xff0c;…

使用STM32CubeMX配置定时器中断实现LED每秒闪烁一次(STM32G070CBT6)

说明&#xff1a; 本案例采用的定时器3&#xff08;TIM3&#xff09;实现&#xff0c;使用其他定时器是一样配置。 如何新建一个工程以及如何配置LED的端口&#xff0c;请查看前面文章&#xff1a;使用STM32CubeMX实现LED灯每秒闪烁一次&#xff08;STM32G070CBT6单片机&…

2025年Draw.io最新版本下载安装教程,附详细图文

2025年Draw.io最新版本下载安装教程&#xff0c;附详细图文 大家好&#xff0c;今天给大家介绍一款非常实用的流程图绘制软件——Draw.io。不管你是平时需要设计流程图、绘制思维导图&#xff0c;还是制作架构图&#xff0c;甚至是简单的草图&#xff0c;它都能帮你轻松搞定。…

GStreamer —— 2.15、Windows下Qt加载GStreamer库后运行 - “播放教程 1:Playbin 使用“(附:完整源码)

运行效果 介绍 我们已经使用了这个元素&#xff0c;它能够构建一个完整的播放管道&#xff0c;而无需做太多工作。 本教程介绍如何进一步自定义&#xff0c;以防其默认值不适合我们的特定需求。将学习&#xff1a; • 如何确定文件包含多少个流&#xff0c;以及如何切换 其中。…

Python----数据可视化(Seaborn一:介绍,应用)

一、Seaborn的介绍 Seaborn 是一个基于 matplotlib 的 Python 库&#xff0c;对其进行了高级 API 的封装&#xff0c;使得作图更为方便和吸引人。尽管在大多数情况下&#xff0c;使用 Seaborn 就能够创建出美观的图表&#xff0c;但 matplotlib 提供了更高的灵活性和定制化的能…

小程序SSL证书过期怎么办?

SSL证书就像小程序的“安全锁”&#xff0c;一旦过期&#xff0c;用户访问时会被提示“不安全”&#xff0c;轻则流失客户&#xff0c;重则数据泄露&#xff01;作为企业负责人&#xff0c;如何快速解决证书过期问题&#xff1f;又该如何避免再次踩坑&#xff1f;这篇指南给你答…

Linux上位机开发实战(x86和arm自由切换)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;qt本身支持windows系统&#xff0c;也支持linux系统。不仅如此&#xff0c;qt除了支持传统的x86 cpu之外&#xff0c;还支…

Mysql的卸载安装配置以及简单使用

MySQL其它问题已经更新在&#xff1a;MySQL完善配置---可视化-CSDN博客 一、卸载 ①控制面板卸载 ②C盘隐藏项目>ProgramData>mysql相关文件夹&#xff0c;还有Program file下的MySQL文件夹 ③开始菜单栏搜索>服务&#xff0c;找到MySQL相关服务删除&#xff0c;如果再…

RabbitMQ之旅(1)

相信自己,终会成功 目录 主流MQ产品 1.kafaka 2.RocketMQ 3.RabbitMQ 在xshell上安装RabbitMQ RabbitMQ七种工作模式 1.简单模式 ​编辑 2.工作队列模式 3.发布/订阅模式 4.路由模式 5.通配符模式 6.RPC模式 AMQP.BasicProperties 设置消息属性的类 7.发布确认模…

基于Matlab的人脸识别的二维PCA

一、基本原理 传统 PCA 在处理图像数据时&#xff0c;需将二维图像矩阵拉伸为一维向量&#xff0c;这使得数据维度剧增&#xff0c;引发高计算成本与存储压力。与之不同&#xff0c;2DPCA 直接基于二维图像矩阵展开运算。 它着眼于图像矩阵的列向量&#xff0c;构建协方差矩阵…

el-pagination的使用说明

<el-paginationv-model:current-page"pageNo" //当前第几页v-model:page-size"pageSize" //每页显示多少条数据:page-sizes"[10, 20, 30]" //控制每页显示的条数:small"true" //控制分页器大小:disabled&quo…

Redis Redis介绍、安装 - Redis客户端

目录 redis是什么&#xff0c;他的应用场景是什么&#xff1f; Redis的一些主要特点和应用场景&#xff1a; redis的官方网站&#xff1a;Redis redis是键值型数据库&#xff1a;&#xff08;也就是key-value模式&#xff09;&#xff08;跟python的字典很像&#xff09; …

LWIP网络模型及接口简介(DAY 01)

目录 1.网络协议分层模型 2. LWIP三种编程接口 1.网络协议分层模型 其中各层级的封装与拆封过程 2. LWIP三种编程接口 LwIP 提供了三种编程接口&#xff0c;分别为 RAW/Callback API、NETCONN API、SOCKET API。它们的易用性从左到右依次提高&#xff0c;而执行效率从左到右依…

【Python 数据结构 14.邻接表】

希望你的眼睛可以一直笑&#xff0c;想要的都得到 —— 25.3.11 一、邻接表的概念 1.邻接表的定义 邻接表是一种表示图的数据结构。邻接表的主要概念是&#xff1a;对于图中的每个顶点&#xff0c;维护一个由与其相邻的顶点组成的列表。这个列表可以用数组、链表或其他数据结构…