当前位置: 首页 > news >正文

kubernetes的Service与服务发现

kubernetes的Service与服务发现

  • 1 Service
    • 1.1 Service概念
    • 1.2 Service类型
      • 1.2.1 ClusterIP
      • 1.2.2 NodePort
      • 1.2.3 LoadBalancer
      • 1.2.4 ExternalName
      • 1.2.5 Headless
  • 2 CoreDNS
    • 2.1 CoreDNS概念
    • 2.2 CoreDNS插件架构
    • 2.3 CoreDNS在kubernetes下的工作原理
    • 2.4 Pod上的DNS解析策略
  • 3 Ingress
    • 3.1 Ingress的概念
    • 3.2 Ingress的类型
      • 3.2.1 Simple fanout
      • 3.2.2 Name based virtual hosting
      • 3.2.3 TLS
    • 3.3 Canary规则
    • 3.4 Ingress和LoadBalancer的区别

1 Service

1.1 Service概念

Service是kubernetes标准的API资源类型之一,存在于集群中的各节点之上,kubernetes会为它创建一个稳定不变且可用的 Cluster_IP,为pod提供固定的流量入口。

  • 服务发现:通过标签选择器,在同一名称空间下发现一组提供相同服务的pod,并筛选符合条件的pod
    • 实际上并非由Service资源自己完成,是由与Service同名的Endpoint或EndpointSlice资源及控制器完成的
    • 当创建一个Service时,Kubernetes会为该Service创建一个同名的Endpoints资源。这个Endpoints资源包含了一个或多个后端Pod的IP地址和端口号,是否有该pod取决于这个pod有没有通过readiness探针测试。当Service收到请求时,它会将请求转发给Endpoints中的后端Pod
    • EndpointSlice可以支持更大规模的集群
  • 四层负载均衡:这组筛选出来的pod的ip地址,将作为service的后端服务器,其流量调度规则是由运行在各工作节点的kube-proxy根据配置的模式生成,可以是iptables或ipvs
    • 客户端可以是来自集群之上的Pod,也可以是集群外部的其它端点
    • 该节点之上的进程,可通过该Service的Cluster IP进入(集群内部,东西向流量)
    • 该节点之外的端点,可经由该Service的NodePort进入(集群外部,南北向流量,两级调度)

Service资源主要是为了解决Pod在服务提供上的不足

  • Pod的 IP 具有动态性,当因为故障或重启而更换时,IP地址也会随之变化
  • Pod的 IP 只能在kubernetes集群内部访问

1.2 Service类型

在这里插入图片描述

1.2.1 ClusterIP

访问范围:集群内部
依赖条件:无
典型场景:微服务内部通信

支持Service_IP:Service_Port接入,Client --> Service_IP:Service_Port --> Pod_IP:Pod_Port

kind: Service
apiVersion: v1
metadata:name: demoapp-svc
spec:type: ClusterIP     	# 类型标识,默认即为ClusterIP;clusterIP: 10.97.72.1	# 建议不要指定,自动分配selector:app: demoapp		# 指定pod的标签,pod上必须有app=demoapp的标签ports:- name: http       	# 端口名称标识protocol: TCP    	# 协议,支持TCP、UDP和SCTPport: 80          	# Service的端口号targetPort: 80   	# 目标端口号,即后端端点提供服务的监听端口号
[root@master1 services]#kubectl create deployment demoapp --image=ikubernetes/demoapp:v1.0 --replicas=2 -n demo[root@master1 services]#kubectl get pods -n demo --show-labels 
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
demoapp-7c58cd6bb-2zbb8   1/1     Running   0          20s   app=demoapp,pod-template-hash=7c58cd6bb
demoapp-7c58cd6bb-t8dwm   1/1     Running   0          20s   app=demoapp,pod-template-hash=7c58cd6bb[root@master1 services]# kubectl get pods -o wide -n demo
NAME                      READY   STATUS    RESTARTS   AGE     IP            NODE             NOMINATED NODE   READINESS GATES
demoapp-7c58cd6bb-2zbb8   1/1     Running   0          3h19m   10.244.2.10   node1.wang.org   <none>           <none>
demoapp-7c58cd6bb-t8dwm   1/1     Running   0          3h19m   10.244.1.8    node2.wang.org   <none>           <none>[root@master1 services]#kubectl get services -n demo
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
demoapp-svc   ClusterIP   10.101.226.122   <none>        80/TCP    14s[root@master1 services]#kubectl get services -n demo demoapp-svc -o yaml
spec:internalTrafficPolicy: Cluster  #内部流量策略type: ClusterIP#创建自主式Pod测试,可以调度到两个节点上的pod
[root@master1 services]#kubectl run client-$RANDOM --image=ikubernetes/admin-box:v1.2 -it --restart=Never --rm --command -- /bin/sh
root@client-5400 ~# curl 10.101.226.122
ikubernetes admin-box:v1.2 !! ClientIP: 10.244.1.9,Servername: demoapp-7c58cd6bb-2zbb8,ServerIP: 10.244.2.10
root@client-5400 ~# curl 10.101.226.122
ikubernetes admin-box:v1.2 !! ClientIP: 10.244.1.9,Servername: demoapp-7c58cd6bb-t8dwm,ServerIP: 10.244.1.8#也能利用名字,注意要指定名称空间
root@client-5400 ~# curl demoapp-svc.demo

1.2.2 NodePort

访问范围:集群外部(通过节点)
依赖条件:节点需要有与外部通信的IP
典型场景:开发测试,临时访问

支持Node_IP:Node_Port接入,Client --> Node_IP:NodePort --> Pod_IP:Pod_Port,这里的Node_IP可以集群中任一节点

节点会监听一个端口与service的端口映射,这就是NodePort,一般会分配一个在30000-32767之间的端口

kind: Service
apiVersion: v1
metadata:name: demoappnamespace: demo
spec:type: NodePort		# 必须明确给出Service类型selector:app: demoappports:- name: httpprotocol: TCPport: 80targetPort: 80nodePort: 30080   	# 可选,为避免冲突,建议由系统动态分配# externalTrafficPolicy: Local
[root@master1 services]#kubectl get svc -n demo
NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
demoapp-clusterip-svc   ClusterIP   10.97.72.1     <none>        80/TCP         26m
demoapp-nodeport-svc    NodePort    10.96.45.106   <none>        80:32697/TCP   2s#集群内部
[root@master1 services]#kubectl run client-$RANDOM --image=ikubernetes/admin-box:v1.2 -it --restart=Never --rm --command -- /bin/sh
[root@client-3546 /]# curl 10.96.45.106
iKubernetes demoapp v1.0 !! ClientIP: 10.244.1.22, ServerName: demoapp-7c58cd6bb-9g92g, ServerIP: 10.244.1.20!
[root@client-3546 /]# curl 10.96.45.106
iKubernetes demoapp v1.0 !! ClientIP: 10.244.1.22, ServerName: demoapp-7c58cd6bb-mzgqk, ServerIP: 10.244.2.13!#集群外部,集群内部任一节点
[root@rocky8 ~]#curl 10.0.0.183:32697
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp-7c58cd6bb-mzgqk, ServerIP: 10.244.2.13!
[root@rocky8 ~]#curl 10.0.0.183:32697
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp-7c58cd6bb-9g92g, ServerIP: 10.244.1.20!

1.2.3 LoadBalancer

访问范围:集群外部(通过LB)
依赖条件:云平台支持
典型场景:生产环境对外暴露服务

由于NodePort不是正常服务的端口,比如用户访问nginx,只知道是80端口,但是我们是30080端口,用户就不知道了,所以直接让用户访问Node不现实,需要在集群外部多加一级代理LoadBalancer,将接入的流量转发至工作节点上的NodePort

支持通过外部的LoadBalancer的LB_IP:LB_Port接入,Client --> LB_IP:LB_PORT --> Node_IP:NodePort --> Pod_IP:Pod_Port

云服务商一般会提供一个负载均衡器,当集群创建一个LoadBalancer类型的service资源时,会自动帮我们关联一个负载均衡器,,生成 EXTERNAL-IP(LB_IP) 供外部客户端使用

若外部LB把流量转发给并非目标Pod所在的节点时,该节点就要把该流量转发给拥有这个pod的Node上,报文转发的路径中就会存在跃点,可以通过 externalTrafficPolicy.Local 设置外部LB只能把流量转发给运行有该Service关联的Pod的Node之上

kind: Service
apiVersion: v1
metadata:name: demoapp-loadbalancer-svc
spec:type: LoadBalancerselector:app: demoappports:- name: httpprotocol: TCPport: 80targetPort: 80
[root@master1 MetalLB]#kubectl get svc -n demo
NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
demoapp-clusterip-svc      ClusterIP      10.97.72.1      <none>        80/TCP         48m
demoapp-loadbalancer-svc   LoadBalancer   10.98.160.147   10.0.0.51     80:31179/TCP   15m
demoapp-nodeport-svc       NodePort       10.96.45.106    <none>        80:32697/TCP   21m[root@rocky8 ~]#curl 10.0.0.51
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.0, ServerName: demoapp-7c58cd6bb-9g92g, ServerIP: 10.244.1.20!
[root@rocky8 ~]#curl 10.0.0.51
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.1, ServerName: demoapp-7c58cd6bb-mzgqk, ServerIP: 10.244.2.13!

1.2.4 ExternalName

访问范围:集群内部
依赖条件:外部服务需要有DNS名称
典型场景:代理外部服务

DNS 重定向机制,用于将集群外部的服务引入到集群中,将集群内的服务名称映射到集群外的域名,通过externalName字段进行设置。当集群内的 Pod 访问这个服务时,DNS 解析会将服务名称解析为外部域名。

ServiceName --> external Service DNS Name

kind: Service
apiVersion: v1
metadata:name: externalname-redis-svc  #Service名称namespace: demo
spec:type: ExternalNameexternalName: redis.ik8s.io  #DNS解析的外部目标域名ports:- protocol: TCPport: 6379targetPort: 6379nodePort: 0selector: {}  #选择器部分为空,表示这个Service不与任何特定的Pod关联
[root@master1 services]#kubectl get pods -n demo
NAME                      READY   STATUS    RESTARTS   AGE
demoapp-7c58cd6bb-bldpv   1/1     Running   0          48s
demoapp-7c58cd6bb-bls8m   1/1     Running   0          48s[root@master1 services]#kubectl get svc -n demo 
NAME                     TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)    AGE
externalname-redis-svc   ExternalName   <none>       redis.ik8s.io   6379/TCP   15s[root@master1 services]#kubectl exec -it -n demo demoapp-7c58cd6bb-bldpv -- /bin/sh
[root@demoapp-7c58cd6bb-bldpv ~]# host -t A externalname-redis-svc
externalname-redis-svc.demo.svc.cluster.local is an alias for redis.ik8s.io.
redis.ik8s.io has address 1.2.3.4

1.2.5 Headless

访问范围:集群内部
依赖条件:无
典型场景:有状态应用,直接访问Pod

那些没有ClusterIP的Service则称为Headless Service,它们又可以为分两种情形

  • 有标签选择器的有状态应用,或者没有标签选择器但有着与Service对象同名的Endpoint资源。Service的DNS名称直接解析为后端各就绪状态的Pod的IP地址,各Pod IP相关PTR记录将解析至Pod自身的名称,不会解析至Service的DNS名称
  • 无标签选择器且也没有与Service对象同名的Endpoint资源,即ExternalName,Service的DNS名称将会生成一条CNAME记录,对应值由Service对象上的 spec.externalName 字段指定

范例:有标签选择器

kind: Service
apiVersion: v1
metadata:name: demoapp-headless-svc
spec:clusterIP: Noneselector:app: demoapp  #解析到这个标签下的后端各就绪状态的Pod的IP地址ports:- port: 80targetPort: 80name: http
[root@master1 ~]#kubectl get pods -n demo -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE             NOMINATED NODE   READINESS GATES
demoapp-7c58cd6bb-bldpv   1/1     Running   0          10m   10.244.1.4   node1.wang.org   <none>           <none>
demoapp-7c58cd6bb-bls8m   1/1     Running   0          10m   10.244.2.4   node2.wang.org   <none>           <none>[root@master1 services]#kubectl get svc -n demo 
NAME                     TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)    AGE
demoapp-headless-svc     ClusterIP      None         <none>          80/TCP     8s
externalname-redis-svc   ExternalName   <none>       redis.ik8s.io   6379/TCP   12m[root@master1 services]#kubectl exec -it -n demo demoapp-7c58cd6bb-bldpv -- /bin/sh
#解析至Pod自身的IP
[root@demoapp-7c58cd6bb-bldpv ~]# host -t A demoapp-headless-svc
demoapp-headless-svc.demo.svc.cluster.local has address 10.244.2.4
demoapp-headless-svc.demo.svc.cluster.local has address 10.244.1.4#反向解析至Pod自身的名称
[root@demoapp-7c58cd6bb-bldpv ~]# host -t PTR 10.244.1.4
4.1.244.10.in-addr.arpa domain name pointer 10-244-1-4.demoapp-headless-svc.demo.svc.cluster.local.

范例:没有标签选择器,但有着与Service对象同名的Endpoint资源

apiVersion: v1
kind: Endpoints
metadata:name: mysql-externalnamespace: default
subsets:
- addresses:			#指定集群外部的后端服务器的IP地址- ip: 172.29.9.51- ip: 172.29.9.52ports:				#定义Endpoints的端口映射- name: mysqlport: 3306protocol: TCP
---
apiVersion: v1
kind: Service
metadata:name: mysql-external	#必须与Endpoints一致namespace: default	#必须与Endpoints一致
spec:type: ClusterIPports:- name: mysqlport: 3306targetPort: 3306protocol: TCP
[root@master1 services]#kubectl get svc
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
mysql-external   ClusterIP   10.103.90.57   <none>        3306/TCP       17s[root@master1 services]#kubectl describe svc mysql-external 
Name:              mysql-external
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.103.90.57
IPs:               10.103.90.57
Port:              mysql  3306/TCP
TargetPort:        3306/TCP
Endpoints:         172.29.9.51:3306,172.29.9.52:3306	#这两个集群外部的服务器,与节点在同一网段,Pod就可以正常访问
Session Affinity:  None
Events:            <none>

2 CoreDNS

2.1 CoreDNS概念

CoreDNS是Kubernetes集群的必备附件(DNS服务器),负责为Kubernetes提供名称解析和服务发现,对于每个Service,自动生成一个或多个A、PTR和SRV(端口名称解析)记录,将Service的name与Service的Cluster_IP地址做一个DNS域名映射,可以基于名称的方式去访问该组Pod上的服务.

每个Service资源对象,在CoreDNS上都会自动生成一个遵循 “<service>.<ns>.svc.<zone>” 格式的名称,围绕该名称会生成一些DNS格式的资源记录

  • <service>:当前Service对象的名称
  • <ns>:当前Service对象所属的名称空间
  • <zone>:当前Kubernetes集群使用的域名后缀,默认为 “cluster.local”,是 Kubernetes 集群中所有域名的根域名

2.2 CoreDNS插件架构

CoreDNS是一种灵活、可扩展的 DNS 服务器,借助插件架构,允许用户根据需求自定义功能。与其他 DNS 服务器BIND、Knot、PowerDNS不同,CoreDNS 非常灵活,几乎所有功能都交给插件去实现。

默认的 CoreDNS 安装中包含了大约 30 个插件,还可以编译许多外部插件到 CoreDNS 中,以扩展其功能。

CoreDNS的插件可大致分为两类:

  • 负责处理请求的常规插件,这些插件才是插件链中的有效组成部分,例如errors、kubernetes和forward等,而他们又分为两类
    • 负责以某种方式处理请求的插件:这类插件不是区域数据源,它们的运行方式是在自身处理完成后,会将查询传递给下一个插件
    • 后端插件:用于配置区域数据的来源,例如etcd、file和kubernetes等
      • 这类插件通常要为其负责的区域生成最终结果,它要么能正常响应查询,要么返回NXDOMAIN
      • 但也可以使用fallthrough改变这种响应行为:未发现查询的目标资源记录时,将DNS查询请求转交给插件链中的下一个插件,随后终结于另一个后端插件,或再次由 fallthrough 改变这种行为
  • 不处理请求的特殊插件,它们仅用来修改Server或Server Block中的配置,例如health、tls、startup、shutdown和root等插件,这类插件不会作为服务器配置段的插件链中的有效组成部署

2.3 CoreDNS在kubernetes下的工作原理

CoreDNS 在 Kubernetes 中作为一个 Deployment 运行,通常会部署两个或多个副本以确保高可用性。它主要通过以下步骤工作:

  • 启动与配置:CoreDNS 读取 ConfigMap 配置文件,根据配置启动相应的插件。
  • 监听 DNS 请求:CoreDNS 监听来自 Kubernetes 集群内部的 DNS 请求。
  • 解析 DNS 请求:根据请求的类型,CoreDNS 调用相应的插件进行解析。
  • 返回解析结果:将解析结果返回给请求方。

2.4 Pod上的DNS解析策略

spec.dnsPolicy 设置

  • Default:Pod直接继承其所在节点的名称解析配置,就无法解析集群内部的服务,csi-nfs-driver默认使用
  • ClusterFirst:使用集群内部的CoreDNS服务进行域名解析。如果集群内的服务无法解析请求的域名,那么才将查询转发给从所在节点继承的上游名称服务器
  • ClusterFirstWithHostNet:专用于在设置了hostNetwork的Pod对象上使用的ClusterFirst策略。当Pod与宿主机共用同一个网络命名空间时,这类Pod无法访问集群内的服务,所以该策略让这类Pod可以利用集群的DNS服务进行域名解析
  • None:用于忽略Kubernetes集群的默认设定,而仅使用由dnsConfig自定义的配置

Pod内解析一个域名时,请求送到CoreDNS的Pod中的流程

1、DNS配置初始化

Pod启动时,kubelet根据集群DNS配置( --cluster-dns 参数)将CoreDNS的Service ClusterIP写入Pod的 /etc/resolv.conf 文件

2、DNS查询发起

应用程序发起域名查询(如my-service)

  • 若为非FQDN(如my-service),系统按search域依次补全(如my-service..svc.cluster.local)并尝试解析
  • 若为FQDN(如my-service.ns.svc.cluster.local),直接发送DNS请求

3、请求路由至CoreDNS服务

Pod的DNS客户端将请求通过UDP/TCP协议发送至nameserver指定的CoreDNS Service ClusterIP(如10.96.0.10)的53端口,然后节点上的kube-proxy实现流量转发,通过iptables/IPVS规则将目标为CoreDNS ServiceIP的流量负载均衡到后端CoreDNS Pod的Endpoint IP

4、CoreDNS处理请求

  • CoreDNS Pod接收请求后,根据配置(corefile)执行插件链
  • kubernetes插件:解析集群内Service、Pod域名,通过API Server查询Service/Pod的IP
  • forward插件:非集群域名(如baidu.com)转发至上游DNS(如节点/etc/resolv.conf中的外部DNS服务器
  • 返回解析结果:CoreDNS将解析后的IP地址按原路径返回至Pod,完成域名解析

Pod应用→ /etc/resolv.conf → CoreDNS Service → kube-proxy→ CoreDNS Pod→ API Server/外部DNS

3 Ingress

3.1 Ingress的概念

Service作为四层负载均衡,不支持基于URL等机制对HTTP/HTTPS协议进行高级路由、超时/重试、基于流量的灰度等高级流量治理机制,也难以将多个Service流量统一管理,所以有了Ingress作为七层负载均衡

  • 可配置域名和路径规则,为多个服务提供统一入口
  • 支持多种高级功能,如 TLS、路径重写等
  • 仅支持 HTTP 和 HTTPS

Ingress是Kubernetes上的标准API资源类型之一,由Ingress API和Ingress Controller共同组成

  • 前者负责以k8s标准的资源格式定义流量调度、路由等规则
  • 后者负责监视(watch)Ingress并生成自身的配置,并据此完成流量转发

Ingress Controller非为内置的控制器,需要额外部署(用户空间的代理进程),实现方案有很多,包括Ingress-Nginx、HAProxy、Envoy、Traefik、Gloo、Contour和Kong等

  • 通常以Pod形式运行于Kubernetes集群之上
  • 一般应该由专用的LB Service负责为其接入集群外部流量
  • Kubernetes支持同时部署二个或以上的数量的Ingress Controller,所以在创建Ingress资源时,应该指明其所属的Ingress Controller

Ingress、Ingress Controller和Service的关系

  • Ingress需要借助于Service资源来发现后端端点
  • Ingress Controller会基于Ingress的定义将流量直接发往其相关Service的后端端点,该转发过程并不会再经由Service进行
  • Client --> LB Service --> Ingress Controller Pod --> Upstream Service --> Upstream Pod
    • LB Service是NodePort类型或者是LoadBalancer类型
    • Upstream Service仅发挥服务发现功能,来发现后端Pod,并不需要负载均衡功能,这样做可以减少一层代理
    • 所以流量流向可以认为是Client --> LB Service --> Ingress Controller Pod --> Upstream Pod
  • 当然对那些未通过Ingress Controller进入的流量service会执行负载均衡

在这里插入图片描述

3.2 Ingress的类型

3.2.1 Simple fanout

在同一个FQDN下通过不同的URI完成不同应用间的流量分发

  • 基于单个虚拟主机接收多个应用的流量
  • 常用于将流量分发至同一个应用下的多个不同子应用,同一个应用内的流量由调度算法分发至该应用的各后端端点
  • 不需要为每个应用配置专用的域名

基于URI方式代理不同应用的请求时,后端应用的URI若与代理时使用的URI不同,则需要启用URL Rewrite完成URI的重写,Ingress-Nginx支持使用 “annotation nginx.ingress.kubernetes.io/rewrite-target” 注解

[root@master1 ~]#kubectl create deployment nginx --image=nginx:1.22-alpine --replicas=2 -n dev
[root@master1 ~]#kubectl create service clusterip nginx --tcp=80:80 -n dev
[root@master1 ~]#kubectl get ep -n dev
NAME      ENDPOINTS                       AGE
demoapp   10.244.1.57:80,10.244.2.53:80   56m
nginx     10.244.1.58:80,10.244.2.54:80   10s#有个问题:location映射的时候,请求前面带上/demoapp或/nginx,代理的时候也会带上
#即client --> web.wu.com/demoapp --> demoapp:80/demoapp
#但是我们应该想的是代理到后端是demoapp:80/
#所以Ingress-Nginx支持使用“annotation nginx.ingress.kubernetes.io/rewrite-target”注解进行URI的重写
#下面例子是仅将请求的path简单重写为另一个path[root@master1 ~]#kubectl create ingress demoapp-nginx --rule="web.wu.com/demoapp/*"=demoapp:80 --rule="web.wu.com/nginx/*"=nginx:80 --class=nginx --annotation nginx.ingress.kubernetes.io/rewrite-target="/" -n dev --dry-run=client -o yaml > ingress-simple-fanout.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/rewrite-target: /creationTimestamp: nullname: demoapp-nginxnamespace: dev
spec:ingressClassName: nginxrules:- host: web.wu.comhttp:paths:- backend:service:name: demoappport:number: 80path: /demoapp/pathType: Prefix- backend:service:name: nginxport:number: 80path: /nginx/pathType: Prefix
status:loadBalancer: {}[root@master1 ~]#kubectl apply -f ingress-simple-fanout.yaml[root@master1 ~]#kubectl describe ingress -n dev demoapp-nginx 
Name:             demoapp-nginx
Labels:           <none>
Namespace:        dev
Address:          10.0.0.52
Ingress Class:    nginx
Default backend:  <default>
Rules:Host        Path  Backends----        ----  --------web.wu.com  /demoapp/   demoapp:80 (10.244.1.57:80,10.244.2.53:80)/nginx/     nginx:80 (10.244.1.58:80,10.244.2.54:80)
Annotations:  nginx.ingress.kubernetes.io/rewrite-target: /  #URL重写
Events:Type    Reason  Age                 From                      Message----    ------  ----                ----                      -------Normal  Sync    70s (x2 over 103s)  nginx-ingress-controller  Scheduled for sync[root@rocky8 ~]#vim /etc/hosts
10.0.0.52 demoapp.wu.com web.wu.com[root@rocky8 ~]#curl web.wu.com/demoapp/
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.52, ServerName: demoapp-7c58cd6bb-h6vqs, ServerIP: 10.244.1.57![root@rocky8 ~]#curl web.wu.com/nginx/
<title>Welcome to nginx!</title>[root@rocky8 ~]#curl web.wu.com/demoapp/version
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.52, ServerName: demoapp-7c58cd6bb-h6vqs, ServerIP: 10.244.1.57!root@rocky8 ~]#curl web.wu.com/nginx/version
<title>Welcome to nginx!</title>#上面有个问题:/*的话,什么路径都能匹配到根上,所以有更复杂的写法
#下面例子是将请求的path重写为另一个path的命令,移除客户请求时使用的path前缀[root@master1 ~]#kubectl create ingress demoapp-nginx --rule="web.wu.com/demoapp(/|$)(.*)"=demoapp:80 --rule="web.wu.com/nginx(/|$)(.*)"=nginx:80 --class=nginx --annotation nginx.ingress.kubernetes.io/rewrite-target='/$2' -n dev --dry-run=client -o yaml > ingress-simple-fanout.yaml#默认这么写pathType为Exact,Exact不支持正则表达式,会报错
#需要手动指定pathType为ImplementationSpecific,表示由具体的Ingress Controller决定如何处理路径(NGINX 支持正则表达式)[root@master1 ~]#kubectl apply -f ingress-simple-fanout.yaml[root@rocky8 ~]#curl web.wu.com/demoapp
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.52, ServerName: demoapp-7c58cd6bb-k7w4j, ServerIP: 10.244.2.53![root@rocky8 ~]#curl web.wu.com/demoapp/version
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>#client --> web.wu.com/demoapp/hostname --> demoapp:80/hostname
[root@rocky8 ~]#curl web.wu.com/demoapp/hostname
ServerName: demoapp-7c58cd6bb-k7w4j

3.2.2 Name based virtual hosting

为每个应用使用一个专有的主机名,并基于这些名称完成不同应用间的流量转发

  • 每个FQDN对应于Ingress Controller上的一个虚拟主机的定义
  • 同一组内的应用的流量,由Ingress Controller根据调度算法完成请求调度

基于FQDN名称代理不同应用的请求时,需要事先准备好多个域名,且确保对这些域名的解析能够到达Ingress Controller

[root@master1 ~]#kubectl create ingress demoapp-nginx --rule="demoapp.wu.com/(.*)"=demoapp:80 --rule="nginx.wu.com/(.*)"=nginx:80 --class=nginx --annotation nginx.ingress.kubernetes.io/rewrite-target='/$1' -n dev --dry-run=client -o yaml > ingress-name-based-virtual-hosting.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/rewrite-target: /$1creationTimestamp: nullname: demoapp-nginxnamespace: dev
spec:ingressClassName: nginxrules:- host: demoapp.wu.comhttp:paths:- backend:service:name: demoappport:number: 80path: /(.*)pathType: Exact  #改成ImplementationSpecific- host: nginx.wu.comhttp:paths:- backend:service:name: nginxport:number: 80path: /(.*)pathType: Exact
status:loadBalancer: {}[root@rocky8 ~]#vim /etc/hosts
10.0.0.52 demoapp.wu.com nginx.wu.com[root@rocky8 ~]#curl demoapp.wu.com
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.52, ServerName: demoapp-7c58cd6bb-h6vqs, ServerIP: 10.244.1.57![root@rocky8 ~]#curl demoapp.wu.com/hostname
ServerName: demoapp-7c58cd6bb-k7w4j[root@rocky8 ~]#curl nginx.wu.com
<title>Welcome to nginx!</title>[root@rocky8 ~]#curl nginx.wu.com/version
<head><title>404 Not Found</title></head>

3.2.3 TLS

Ingress也可以提供TLS通信机制,但仅限于443/TCP端口

  • 若TLS配置部分指定了不同的主机,则它们会根据通过SNI TLS扩展指定的主机名
    • 前提:Ingress控制器支持SNI在同一端口上复用
  • TLS Secret必须包含名为tls.crt和 的密钥tls.key,它们分别含有TLS的证书和私钥

基于TLS的Ingress要求事先准备好专用的 “kubernetes.io/tls” 类型的Secret对象

启用tls后,该域名下的所有URI默认为强制将http请求跳转至https,若不希望使用该功能,可以使用如下注解选项:--annotation nginx.ingress.kubernetes.io/ssl-redirect=false

链接:github or gitee

[root@master1 wordpress]#kubectl create namespace blog
[root@master1 wordpress]#kubectl apply -f mysql-ephemeral/ -n blog
[root@master1 wordpress]#kubectl apply -f wordpress-apache-ephemeral/ -n blog#创建私钥
[root@master1 wordpress]#(umask 077; openssl genrsa -out blog.wu.com.key 2048)#创建自签名证书
[root@master1 wordpress]#openssl req -new -x509 -key blog.wu.com.key -out blog.wu.com.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=blog.wu.com[root@master1 wordpress]#kubectl create secret tls blog.wu.com --cert=./blog.wu.com.crt --key=./blog.wu.com.key -n blog#创建常规的虚拟主机代理规则,同时将该主机定义为TLS类型
#tls指定的是用来配置https主机的证书和私钥的名字,即secret.tls的名字
[root@master1 wordpress]#kubectl create ingress wordpress --rule='blog.wu.com/*=wordpress:80,tls=blog.wu.com' --class=nginx -n blog#做好域名解析后,浏览器访问blog.wu.com

3.3 Canary规则

Ingress Nginx Annotations支持的Canary规则

  • nginx.ingress.kubernetes.io/canary-by-header:基于该Annotation中指定Request Header进行流量切分,适用于灰度发布以及A/B测试

    • 在请求报文中,若存在该Header且其值为always时,请求将会被发送到Canary版本
    • 若存在该Header且其值为never时,请求将不会被发送至Canary版本
    • 对于任何其它值,将忽略该Annotation指定的Header,并通过优先级将请求与其他金丝雀规则进行优先级的比较
  • nginx.ingress.kubernetes.io/canary-by-header-value:基于该Annotation中指定的Request Header的值进行流量切分,标头名称则由前一个Annotation(nginx.ingress.kubernetes.io/canary-by-header)进行指定

    • 请求报文中存在指定的标头,且其值与该Annotation的值匹配时,它将被路由到Canary版本
    • 对于任何其它值,将忽略该Annotation
  • nginx.ingress.kubernetes.io/canary-by-header-pattern

    • 同canary-by-header-value的功能类似,但该Annotation基于正则表达式匹配Request Header的值
    • 若该Annotation与canary-by-header-value同时存在,则该Annotation会被忽略
  • nginx.ingress.kubernetes.io/canary-weight:基于服务权重进行流量切分,适用于蓝绿部署或灰度发布,权重范围0 - 100按百分比将请求路由到Canary Ingress中指定的服务

    • 权重为 0 意味着该金丝雀规则不会向Canary入口的服务发送任何请求
    • 权重为100意味着所有请求都将被发送到 Canary 入口
  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 cookie 的流量切分,适用于灰度发布与 A/B 测试

    • cookie的值设置为always时,它将被路由到Canary入口
    • cookie的值设置为 never时,请求不会被发送到Canary入口
    • 对于任何其他值,将忽略 cookie 并将请求与其他金丝雀规则进行优先级的比较

规则的应用次序

  • Canary规则会按特定的次序进行评估
  • 次序:canary-by-header -> canary-by-cookie -> canary-weight

Canary规则策略

  • 基于服务权重的流量切分:假如在生产上已经运行了A应用对外提供服务,此时开发修复了一些Bug,需要发布A1版本将其上线,但是我们又不希望直接的将所有流量接入到新的A1版本,而是希望将10%的流量进入到A1中,待A1稳定后,才会将所有流量接入进来,再下线原来的A版本。
  • 基于用户请求头Header的流量切分:由于基于权重的发布场景比较粗糙,无法限制具体的用户访问行为。我们有时候会有这样的需求,比如我们有北京、上海、深圳这三个地区的用户,已经有A版本的应用为这三个地区提供服务,由于更新了需求,我们需要发布A1应用,但是我们不想所有地区都访问A1应用,而是希望只有深圳的用户可以访问,待深圳地区反馈没问题后,才开放其他地区。

3.4 Ingress和LoadBalancer的区别

特性IngressLoadBalancer
定义集群内外部流量的路由入口,基于URL路径和主机名路由流量云负载均衡器,自动为Service创建外部负载均衡器
使用场景微服务架构、基于URL路由的流量管理、集群内多个服务共用入口简单的将服务暴露到外部网络,提供公网访问
支持的协议HTTP/HTTPSHTTP/HTTPS 或 TCP/UDP(依赖云提供商的负载均衡器)
负载均衡通过Ingress Controller(如NGINX)提供云服务商自动创建的负载均衡器,流量转发到NodePort或TargetPort
SSL/TLS 支持✅ 支持SSL/TLS配置,提供HTTPS加密✅ 需要配置SSL证书(通常由云提供商管理)
是否依赖外部云平台❌ 不依赖云平台,集群内部处理✅ 依赖云平台的负载均衡器(如AWS ELB, GCP L4/L7等)
成本❌ 无额外成本(Kubernetes原生功能)💸 会根据云服务商收费
扩展性与灵活性✅ 可以在Ingress规则中灵活配置路由、路径重写、重定向✅ 基本上由云服务商管理,适合简单的服务暴露需求

相关文章:

kubernetes的Service与服务发现

kubernetes的Service与服务发现 1 Service1.1 Service概念1.2 Service类型1.2.1 ClusterIP1.2.2 NodePort1.2.3 LoadBalancer1.2.4 ExternalName1.2.5 Headless 2 CoreDNS2.1 CoreDNS概念2.2 CoreDNS插件架构2.3 CoreDNS在kubernetes下的工作原理2.4 Pod上的DNS解析策略 3 Ingr…...

python打卡day28

类的简单复习 知识点回顾&#xff1a; 类的定义pass占位语句类的初始化方法类的普通方法类的继承&#xff1a;属性的继承、方法的继承 类就是对属性和方法的封装&#xff0c;一个常见的类的定义包括了&#xff1a; 关键字class类名语法固定符号冒号(:)一个初始化函数__init__(…...

【学习心得】英伟达的诸多显卡性能对比

型号 CUDA核心 显存容量 算力&#xff08;FP32/TFLOPS&#xff09; A100 6912 HBM2e/80G 19.49 A800 6912 HBM2e/80G 19.49 H100 14592 HBM3/80G 51.22 H800 14592 HBM3/80G 51.22 T4 4352 GDDR6/16G 8.14 P40 3840 GDDR5/24G 11.76 L40 18176 G…...

使用Pinia持久化插件-persist解决刷新浏览器后数据丢失的问题

文章目录 一、现象二、原因三、解决&#xff1a;使用Pinia持久化插件-persist安装persistpinia中使用persist插件在创建定义状态时配置持久化 四、参考资料 一、现象 登录成功后&#xff0c;能正常看到文章分类的数据&#xff0c;但只要刷新浏览器就提示服务异常 二、原因 P…...

mysql中4种扫描方式和聚簇索引非聚簇索引【爽文一篇】

目录 一 mysql的聚簇索引&非聚簇索引 1.1 数据表 1.2 聚簇索引 1.3 非聚簇索引 1.4 覆盖索引 二 mysql的4种扫描查询 2.1 全表扫描 2.2 索引扫描 2.3 覆盖索引扫描 2.4 回表扫描 2.5 总结 三 mysql的回表查询详解 3.1 回表查询 一 mysql的聚簇索引&非聚簇…...

交流学习 | 江西同为科技有限公司赴海尔总部考察交流

2025年4月8日至9日&#xff0c;江西同为科技有限公司在江西省科技装备商会的带领下&#xff0c;以蔡文君经理为代表&#xff0c;一行人赴山东青岛海尔总部开展两天的考察交流活动。本次考察不仅深入剖析了海尔企业的前沿技术与管理理念&#xff0c;更促进了行业内科技创新、商业…...

AGI大模型(20):混合检索之rank_bm25库来实现词法搜索

1 混合检索简介 混合搜索结合了两种检索信息的方法 词法搜索 (BM25) :这种传统方法根据精确的关键字匹配来检索文档。例如,如果您搜索“cat on the mat”,它将找到包含这些确切单词的文档。 基于嵌入的搜索(密集检索) :这种较新的方法通过比较文档的语义来检索文档。查…...

QT调用Halcon查询所有摄像头名称

QT软件中的测试代码 //获取当前连接的所有设备信息实例HTuple hv_general, hv_ValueList;InfoFramegrabber("DirectShow", "device", &hv_general, &hv_ValueList);qDebug()<<QString::fromUtf8(hv_general.S().Text());//Value list for de…...

16 C 语言布尔类型与 sizeof 运算符详解:布尔类型的三种声明方式、执行时间、赋值规则

1 布尔类型 1.1 布尔类型概述 布尔类型用于表示逻辑上的真&#xff08;true&#xff09;和假&#xff08;false&#xff09;两种状态&#xff0c;是编程中条件判断和逻辑运算的基础。在 C 语言中&#xff0c;布尔值的表示方式随着标准的发展而不断完善。 1.2 布尔类型的三种声…...

配置ssh服务-ubuntu到Windows拷贝文件方法

背景&#xff1a; 在工作中&#xff0c;需要频繁从ubuntu到Windows拷贝文件&#xff0c;但有时间总是无法拷出&#xff0c;每次重启虚拟机又比较麻烦并且效率较低。可以使用scp服务进行拷贝&#xff0c;不仅稳定而且高效&#xff0c;现将配置过程进行梳理&#xff0c;以供大家参…...

使用ts-node搭建typescript运行环境

目录 首先安装好node.js 安装typescript 安装ts-node 创建一个typescript文件 使用ts-node运行typescript文件 首先安装好node.js 安装typescript npm install typescript4.7.4 -g 安装ts-node npm install ts-nodev10.8.1 -g 创建一个typescript文件 文件名为app.ts&a…...

如何深入学习MATLAB的高级应用?

文章目录 要深入学习 MATLAB 的高级应用&#xff0c;需要在掌握基础语法后&#xff0c;系统性地学习特定领域的工具箱和算法&#xff0c;并通过实战项目提升能力。以下是分阶段的学习路径和资源推荐&#xff1a; 一、深化核心技能 高级矩阵运算与线性代数 matlab % 稀疏矩阵处…...

英汉 “语言” 初印象:符号背后的文化底色​

英汉 “语言” 初印象&#xff1a;符号背后的文化底色​ ​ 原始尺寸更换图片 ​​ 在生活里&#xff0c;我们每天都会进行各式各样的交流&#xff0c;或许不曾留意&#xff0c;汉语和英语这两种极具代表性的语言&#xff0c;从最简单的问候语中就能展现出它们独特的文化内…...

C语言_编译全攻略_从原理到实战的深度解析

在 C 语言开发中,编译是连接源代码与可执行程序的关键桥梁。理解编译过程不仅能提升开发效率,更能帮助我们定位内存泄漏、性能瓶颈等深层次问题。本文将从编译原理出发,结合 GCC 工具链,带你掌握 C 语言编译的核心技术。 一、编译流程底层原理 1. 编译四阶段详解 预处理…...

AGI大模型(21):混合检索之混合搜索

为了执行混合搜索,我们结合了 BM25 和密集检索的结果。每种方法的分数均经过标准化和加权以获得最佳总体结果 1 代码 先编写 BM25搜索的代码,再编写密集检索的代码,最后进行混合。 from rank_bm25 import BM25Okapi from nltk.tokenize import word_tokenize import jieb…...

Vue3学习(组合式API——ref模版引用与defineExpose编译宏函数)

目录 一、ref模版引用。 &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;核心基本步骤。(以获取DOM、组件为例) &#xff08;3&#xff09;案例&#xff1a;获取dom对象演示。 <1>需求&#xff1a;点击按钮&#xff0c;让输入框聚焦。 &#xff08;4&…...

Zephyr OS 中的 FIFO 接口应用介绍

目录 概述 1 FIFO的接口函数 1.1 K_FIFO_DEFINE函数 1.2 k_fifo_init函数 1.3 k_fifo_put函数 1.4 k_fifo_get 函数 1.5 k_fifo_is_empty 函数 2 应用验证 2.1 UART中使用FIFO范例 2.2 生产-消费类型范例 3 注意事项 3.1 内存管理 3.2 线程安全边界 概述 Zephy…...

前端基础之CSS

基本语法规范 引入方式 1.内部引入 <style>p{color:blue ;font-size:30px;}</style> 2.行级引入 <p style "color : green ;font-size : 40px;">hello ,wyx</p><p>hello , wyx1</p><h1>hello , wyx2</h1> 3.外…...

【Linux网络】DNS与ICMP

DNS(Domain Name System) DNS是一整套从域名映射到IP的系统。 DNS背景 TCP/IP使用IP地址和端口号来确定网络上的一台主机的一个程序。但是IP地址不方便记忆。 于是人们发明了一种叫主机名的东西&#xff0c;是一个字符串&#xff0c;并且使用hosts文件来描述主机名和IP地址的…...

第二十七天打卡

一些函数 for i in range(2, 10000):if is_prime(i):print(i) if ...: 这是 Python 里的条件判断语句&#xff0c;当 is_prime(i) 的返回值为 True 时&#xff0c;就会执行 if 语句块里的代码。 func.__name__ 的作用 func.__name__ 是 Python 中函数对象的一个特殊属性&am…...

38-日语学习小程序

系统功能特点&#xff1a; 技术栈: springBootVueMysqlUni-app 功能点: 用户端 管理员端 用户端: 1.首页: 轮播图展示、N2词汇列表、网站公告列表 2.学习模块: 有五十音图 词汇 语法 3.社区模块: 可进行发帖 也可查看帖子进行回复 可查看小组 4.我的: N2词汇(点击查看详情…...

信贷风控笔记6——风控常用指标(面试准备14)

一、PSI&#xff1a; 1.计算过程&#xff1a;变量分箱10-20箱&#xff1b;统计各分箱内样本占比&#xff1b; 算各个分箱的index&#xff08;实际占比-预期占比&#xff09;*ln&#xff08;实际占比/预期占比&#xff09;&#xff1b; 将各分箱index求和得PSI 2.情况分类&…...

UDP三种通信方式

单播&#xff08;Unicast&#xff09; 单播是最常见的通信方式&#xff0c;数据从一个发送方传输到一个特定的接收方。发送方将数据包发送到接收方的IP地址和端口号&#xff0c;接收方通过监听指定的端口接收数据。单播适用于一对一的通信场景。 import java.net.DatagramPac…...

Windows运维工具批处理版

测试环境&#xff1a;windows10 必看&#xff1a; 1.新建记事本&#xff0c;另存为&#xff1a;文件类型所有文件&#xff0c;文件名运维.bat&#xff0c;编码ansi&#xff0c;复制代码&#xff0c;保存&#xff0c;双击运行 2.有的功能需要输入管理员密码&#xff0c;如果没…...

无需配置光猫,使用网管交换机配合路由器的IPTV功能实现单线复用

一、背景 弱电箱和电视柜只预留了一根网线&#xff0c;路由器放在电视柜&#xff0c;想实现既可以上网又可以正常观看iptv&#xff0c;本文提供了一种方法。 二、准备工作 1、带iptv功能的路由器&#xff1b;2、水星sg105pro网管交换机&#xff1b;3、网线若干&#xff1b; …...

Elasticsearch 官网阅读之 Term-level Queries

Term-level Queries 参考&#xff1a;https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-exists-query 一、Term Query Term Query 是 term 精准查询。需要注意的是&#xff0c;在进行 Term Query 的时候&#xff0c;要避免 text 类型的字段&#x…...

医疗大模型技术演进与行业应用全景

摘要 本文系统梳理医疗大模型技术架构的三大演进阶段,深度解析Transformer架构优化、多模态融合、模型压缩等核心技术突破。结合Google Med-PaLM、启真医疗大模型等16个典型行业案例,揭示医疗大模型在诊断辅助、药物研发、医院管理等九大场景的应用成效。基于权威评测数据,…...

【软考 McCabe度量法】

McCabe度量法&#xff08;McCabe’s Cyclomatic Complexity&#xff09;是由Thomas McCabe提出的一种用于衡量程序模块环路复杂性的软件度量方法。它通过分析代码的控制流结构来评估程序的复杂度&#xff0c;帮助开发者识别难以维护或测试风险较高的代码区域。 一、McCabe度量法…...

LabVIEW光谱信号仿真与数据处理

在光谱分析领域&#xff0c;LabVIEW 凭借其图形化编程、丰富函数库及强大数据处理能力&#xff0c;成为高效工具。本案例将介绍如何利用 LabVIEW 仿真光谱信号&#xff0c;并对实际采集的光谱数据进行处理&#xff0c;涵盖信号生成、数据采集、滤波、分析及显示等环节。 ​ 一…...

从零开始认识 Node.js:异步非阻塞的魅力

Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境&#xff0c;用于在服务器端运行 JavaScript 代码。它的设计目标是让开发者能够用 JavaScript 构建高性能、可扩展的网络应用。以下是关于 Node.js 的详细介绍&#xff1a; 1. 核心特点 事件驱动与非阻塞 I/O&…...

ECMAScript 2018(ES2018):异步编程与正则表达式的深度进化

1.版本背景与发布 发布时间&#xff1a;2018年6月&#xff0c;由ECMA International正式发布&#xff0c;标准编号为ECMA-262 9th Edition。历史意义&#xff1a;作为ES6之后的第三次年度更新&#xff0c;ES2018聚焦于异步编程、正则表达式和对象操作的标准化&#xff0c;推动…...

【gitee 初学者矿建仓库】

简易的命令行入门教程: Git 全局设置: git config --global user.name "你的名字"触摸 git config --global user.email "你的邮箱"创建 git 仓库: mkdir codestore cd codestore git init -b "main" touch README.md # 选择运行 git add REA…...

Java 类和对象

文章目录 类和对象实例化对象this构造和初始化封装访问修饰限定符包自定义包 static代码块 类和对象 Java当中一切皆对象对象是什么呢&#xff1f; 比如是一个人&#xff0c;手机等怎么描述对象呢&#xff1f; 可以用类描述对象&#xff0c;可以理解类为一个模版&#xff0c;用…...

湖北理元理律师事务所:科学债务管理模型构建实录

债务问题本质是资源错配问题。湖北理元理律师事务所基于400案例的司法大数据&#xff0c;提炼出一套“三阶九步”债务管理模型&#xff0c;本文从技术视角解析其运作逻辑与实操价值。 模型架构&#xff1a;从诊断到执行的全周期管理 阶段一&#xff1a;债务体检&#xff08;1…...

JavaScript vs Python 用于 Web Scraping(2025):终极对比指南

1. 引言 在不断发展的 Web Scraping 领域&#xff0c;选择合适的编程语言对于项目的成功至关重要。虽然 JavaScript 和 Python 在 2025 年仍然是 Web Scraping 领域的热门选择&#xff0c;但它们各自具备不同的优势和挑战。 本指南将深入分析 JavaScript 和 Python 的核心特性…...

数据结构day3

一、gdb调试 gcc -g main.c linklist.c // 对两个.c文件进行编译,生成 a.out 文件 gdb a.out //调试可执行文件 a.out b linklist.c:36 // 在该.c文件第 36 行设置断点 r // 运行程序,但会在断点前停…...

VSCode launch.json 配置参数详解

使用 launch.json 配置调试环境时&#xff0c;会涉及到多个参数&#xff0c;用于定义调试器的行为和目标执行环境。以下是一些常用的配置参数&#xff1a; 1、"type" &#xff1a;指定调试器的类型&#xff0c;例如 "node" 表示 Node.js 调试器&#xff0…...

[已解决] LaTeX “Unicode character“ 报错 (中文字符处理)

问题&#xff1a; 写 LaTeX 文档&#xff0c;特别是包含中文时&#xff0c;经常遇到类似下图的 “Unicode character XXXXXX” 报错 (X) Unicode character 本 (U672C) LaTeX [行 xx, 列 x] (X) Unicode character 报 (U62A5) LaTeX [行 xx, 列 x] ...这通常意味着我们的 LaTe…...

c++成员函数返回类对象引用和直接返回类对象的区别

c成员函数返回类对象引用和直接返回类对象的区别 成员函数直接返回类对象&#xff08;返回临时对象&#xff0c;对象拷贝&#xff09; #include <iostream> class MyInt { public:int value;//构造函数explicit MyInt(int v0) : value(v){}//加法操作,返回对象副本&…...

python项目参考文献

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

Go语言实现链式调用

在 Go 语言中实现链式调用&#xff08;Method Chaining&#xff09;&#xff0c;可以通过让每个方法返回对象本身&#xff08;或对象的指针&#xff09;来实现。这样每次方法调用后可以继续调用其他方法。 示例&#xff1a;实现字符串的链式操作 假设你想对一个字符串连续执行…...

深入解析SpringMVC:从入门到精通

上文了解到SpingBoot的相关知识&#xff0c;此文开启Sping家族下的新篇章 1. 什么是SpringWebMVC&#xff1f; 官方对于SpringMVC的描述是这样的&#xff1a; 什么是Servlet呢? Servlet 是⼀种实现动态页面的技术.准确来讲Servlet是⼀套JavaWeb开发的规范&#xff0c;或者说…...

Java-Collections类高效应用的全面指南

Java-Collections类高效应用的全面指南 前言一、Collections 类概述二、Collections 类的基础方法2.1 排序操作2.1.1 sort方法2.1.2 reverse方法2.1.3 shuffle方法 2.2 查找与替换操作2.2.1 binarySearch方法2.2.2 max和min方法2.2.3 replaceAll方法 三、Collections 类的高级应…...

微软家各种copilot的AI产品:Github copilot、Microsoft copilot

背景 大家可能听到很多copilot&#xff0c;比如 Github Copilot&#xff0c;Microsoft Copilot、Microsoft 365 Copilot&#xff0c;有什么区别 Github Copilot&#xff1a;有网页版、有插件&#xff08;idea、vscode等的插件&#xff09;&#xff0c;都是面向于程序员的。Mi…...

JAVA EE_HTTP

为什么意气风发的少年&#xff0c;总是听不进去别人的劝解。 ​​​​​​​ ​​​​​​​ ----------陳長生. ❀主页&#xff1a;陳長生.-CSDN博客❀ &#x1f4d5;上一篇&#xff1a;JAVA EE_网络原理_数据链路层-CSDN博客 1.HTTP 1.1.HTTP是什么 H…...

SEO 优化实战:ZKmall模板商城的 B2C商城的 URL 重构与结构化数据

在搜索引擎算法日益复杂的今天&#xff0c;B2C商城想要在海量信息中脱颖而出&#xff0c;仅靠优质商品和营销活动远远不够。ZKmall模板商城以实战为导向&#xff0c;通过URL 重构与结构化数据优化两大核心策略&#xff0c;帮助 B2C 商城实现从底层架构到搜索展示的全面升级&…...

使用HtmlAgilityPack采集墨迹天气中的天气数据

需要解析对应的HTML源码&#xff1a; <div class"left"><div class"wea_alert clearfix"><ul><li><a href "https://tianqi.moji.com/aqi/china/jiangxi/hukou-county" >< span class"level level_2&qu…...

广和通L610模块通过AT指令访问服务器方案:嵌赛使用

实现步骤及关键点&#xff1a; 网络连接配置 ATCGDCONT1,"IP","APN名称" // 设置APN ATCGACT1,1 // 激活PDP上下文 ATCGATT1 // 附着GPRS网络 HTTP协议支持验证 L610支持HTTP客户端功能&#xff0c;关键指…...

nodejs快速入门到精通1

参考 nodejs快速入门到精通 菜鸟教程-nodejs nodejs官方文档 原因 视频免费 资料收费 笔记还是自己写吧 安装 nodejs官网 windows下&#xff1a; #查看nodejs版本 node -v #查看npm版本 npm -v #设置npm为淘宝镜像源 npm config set registry https://registry.npmmirror.…...

Linux下软件安装

一、软件安装方式 在 Linux 系统中&#xff0c;常见的软件安装方式有以下几种&#xff1a; 包管理器安装&#xff08;如 yum、apt&#xff09; 这是最便捷的安装方式&#xff0c;通过系统自带的包管理器从官方软件源下载并安装软件。 # CentOS/RHEL系统使用yum安装 yum insta…...