【kubernetes系列】Kubernetes之Ingress

news/2024/11/24 9:26:16/

概述

从前面的学习,我们可以了解到Kubernetes暴露服务的方式目前常见的只有三种:LoadBlancer Service、NodePort Service、Ingress;而我们需要将集群内服务提供外界访问就会面临以下几个问题:

Pod 漂移问题
Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动启动一个新的,还可以进行动态扩容等。那么自然随着 Pod 的销毁和创建,Pod IP 也会动态变化;那么通过Pod IP去访问某个服务的话是不现实的,而且如果是多个pod实例,怎么做到负载均衡呢?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上。

端口管理问题
如果采用 NodePort 方式暴露服务需要的面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且很容易造成端口冲突,效率低,难以维护。这时,我们可以在前端部署一个Nginx Pod直接对内进行转发。因为Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了。

域名分配及动态更新问题
从上面的方法,采用 Nginx Pod 似乎已经解决了问题,但是其实这里面有一个很大缺陷:当每次有新服务加入又该如何修改 Nginx 配置呢??我们知道使用Nginx可以通过虚拟主机域名进行区分不同的服务,而每个服务通过upstream进行定义不同的负载均衡池,再加上location进行负载均衡的反向代理,在日常使用中只需要修改nginx.conf即可实现,那在K8S中又该如何实现这些配置呢???

假设后端的服务初始服务只有api,后面增加了web和docs服务,那么又该如何将这2个服务加入到Nginx Pod进行调度呢?总不能每次手动去修改nginx的相关配置然后重启nginx的pod吧!!此时 Ingress 出现了,Ingress 包含两大组件:Ingress Controller 和 Ingress。

Ingress是kubernetes中的一种资源对象,作用是定义请求如何转发到service的规则,简单的理解就是你原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;那么问题来了:”Nginx 该怎么处理?”

而Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后对它进行解析,按照它自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:

在这里插入图片描述

Ingress Controller的实现方式常见的有两种,nginx和traefik,工作架构如下,借用traefik官方的图:

ingress-5
ingress-5

通过设置可以将api.domain.com进来的流量路由到集群里api的pod上,你可以将domain.com/web流量路由到web的一组pod上(注意:ingress nginx是怎么识别那些Pod是那个应该加入那个upstream呢?这里就用到了service使用service的labels将一组服务关联起来,虽然创建了service但是ingress controller在解析service的是时候实际是解析到后面的Pod上。)

ingress-6
ingress-6

看起来按照nginx来理解转发是client——>nginx——>svc——>pod;
实际上转发是client—–>nginx——>pod,是直接负载到svc后面的Pod上面的

部署Ingress (以 nginx-ingress为例)

选择适合自己k8s集群版本的nginx-ingress,具体可以参考https://github.com/kubernetes/ingress-nginx/tree/controller-v1.8.1,大致如下:

Ingress-NGINX versionk8s supported versionAlpine VersionNginx VersionHelm Chart Version
v1.8.11.27,1.26, 1.25, 1.243.18.21.21.64.7.*
v1.8.01.27,1.26, 1.25, 1.243.18.01.21.64.7.*
v1.7.11.27,1.26, 1.25, 1.243.17.21.21.64.6.*
v1.7.01.26, 1.25, 1.243.17.21.21.64.6.*
v1.6.41.26, 1.25, 1.24, 1.233.17.01.21.64.5.*
v1.5.11.25, 1.24, 1.233.16.21.21.64.4.*
v1.4.01.25, 1.24, 1.23,1.223.16.21.19.10+4.3.0
v1.3.11.24, 1.23, 1.22, 1.21, 1.203.16.21.19.10+4.2.5
v1.3.01.24, 1.23, 1.22, 1.21, 1.203.16.01.19.10+4.2.3
v1.2.11.23, 1.22, 1.21, 1.20, 1.193.14.61.19.10+4.1.4
v1.1.31.23, 1.22, 1.21, 1.20, 1.193.14.41.19.10+4.0.19
v1.1.21.23, 1.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.18
v1.1.11.23, 1.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.17
v1.1.01.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.13
v1.0.51.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.9
v1.0.41.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.6
v1.0.31.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.5
v1.0.21.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.3
v1.0.11.22, 1.21, 1.20, 1.193.14.21.19.9+4.0.2
v1.0.01.22, 1.21, 1.20, 1.193.13.51.20.14.0.1

由于我的kubernetes版本比较老为1.19.16,按表看应该是nginx版本大于1.19.10的都可以
部署Ingress的步骤:(注意先后顺序,如果先执行了mandatory.yaml文件在执行service-nodeport.yaml文件使用kubectl logs -f 看ingress-controller的pod的日志会有很多报错信息)

1)下载Ingress-controller相关的yaml文件,并给Ingress-controller创建独立的名称空间命名为ingress-nginx;
2)按需修改下载的yaml文件
3)创建Ingress-controller的service,以实现接入集群外部流量;
4)部署Ingress-controller;
5)部署后端的服务,如nginx,并通过service进行暴露;
6)部署Ingress,编写规则,使Ingress-controller和后端服务的Pod组进行关联。

1)下载yaml文件

#部署nginx ingress服务的yaml文件
[root@k8s-m1 nginx-ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.0/deploy/mandatory.yaml
#用于暴露服务供外部用户访问
[root@k8s-m1 nginx-ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.0/deploy/provider/baremetal/service-nodeport.yaml

2)修改yaml文件
入口nginx-ingress的访问方式有两种

  • 可以用nodeport的方式暴露端口
  • 通过设置 hostNetwork为true直接使用宿主机的网络空间
#添加了nodeport的端口,主要为了固定端口
[root@k8s-m1 nginx-ingress]# cat  service-nodeport.yaml 
apiVersion: v1
kind: Service
metadata:name: ingress-nginxnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:type: NodePortports:- name: httpport: 80targetPort: 80protocol: TCPnodePort: 30080- name: httpsport: 443targetPort: 443protocol: TCPnodePort: 30443selector:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx

3)部署Ingress Nginx

[root@k8s-m1 nginx-ingress]# kubectl apply  -f service-nodeport.yaml -f mandatory.yaml 
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created#检查部署情况,pod是否正常,日志是否有报错等
[root@k8s-m1 nginx-ingress]# kubectl get po -n ingress-nginx 
NAME                                       READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-7c9bd444c-bhsvn   1/1     Running   0          113s
[root@k8s-m1 nginx-ingress]# kubectl logs -n ingress-nginx nginx-ingress-controller-7c9bd444c-bhsvn 

4)创建后端服务用于测试

[root@k8s-m1 nginx-ingress]# cat nginx-deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:name: my-nginxlabels:app: nginx
spec:selector:matchLabels:tier: frontendreplicas: 2template:metadata:labels:tier: frontendspec:containers:- name: nginx-gatewayimage: nginxports:- containerPort: 80
[root@k8s-m1 nginx-ingress]# cat nginx-svc.yml 
---
apiVersion: v1
kind: Service
metadata:name: nginx-service
spec:ports:- port: 80selector:tier: frontend[root@k8s-m1 nginx-ingress]# kubectl apply -f nginx-deployment.yml -f  nginx-svc.yml 

5)创建ingress
ingress资源定义格式查看

[root@k8s-m1~]# kubectl explain ingress

编写ingress的配置清单:

[root@k8s-m1 nginx-ingress]# cat my-nginx-ingress.yml 
apiVersion: extensions/v1beta1
kind: Ingress      
metadata:         name: ingress-frontedannotations:         kubernetes.io/ingress.class: "nginx"
spec:     rules: - host: nginx.margu.com    http:paths:       - path:       #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"backend:    #配置后端服务serviceName: nginx-serviceservicePort: 80  #注意端口要与之前svc里面的一致

进入ingress nginx的pod可以看到nginx的配置里面已经有根据ingress规则生成的相关配置信息,如下:

[root@k8s-m1 nginx-ingress]# kubectl exec -it -n ingress-nginx nginx-ingress-controller-7c9bd444c-bhsvn -- /bin/bash
www-data@nginx-ingress-controller-7c9bd444c-bhsvn:/etc/nginx$ cat nginx.conf|more## start server nginx.margu.comserver {server_name nginx.margu.com ;listen 80;set $proxy_upstream_name "-";location / {set $namespace      "default";set $ingress_name   "ingress-fronted";set $service_name   "nginx-service";set $service_port   "80";set $location_path  "/";rewrite_by_lua_block {balancer.rewrite()}header_filter_by_lua_block {}body_filter_by_lua_block {}log_by_lua_block {balancer.log()monitor.call()}

找一台非集群的机器,向hosts文件内添加域名nginx.margu.com设置到集群的任意一个node节点ip上(因为我们使用的是nodeport的方式暴露的ingress nginx,所以每个节点都会有端口暴露出来),打开浏览器访问nginx.margu.com即可发现集群内的nginx已经暴露在集群外。如下:

配置域名解析(Node节点IP),如我的环境以下任意一条域名解析都是可以的

192.168.2.140 nginx.margu.com
192.168.2.141 nginx.margu.com
192.168.2.142 nginx.margu.com

6)多个Ingress controllers:
如果环境中运行多个Ingress controllers,则需要kubernetes.io/ingress.class: "nginx"指定将ingress对象加入到那个Ingress

controllers中
metadata:name: fooannotations:kubernetes.io/ingress.class: "pre"

将以pre控制器作为目标,使它忽略其他种类控制器。

metadata:name: fooannotations:kubernetes.io/ingress.class: "pro"

将以pro控制器作为目标,使它忽略其他种类控制器。

Rewrite(重写):
必须条件:当集群中有多个Ingress controller时需要通过指定Ingress.class注释来确保您的Ingress只针对一个Ingress controller生效,并且的集群中必须运行着这个Ingress controller。ingress可以使用以下标签来控制重写,详情可参考官网https://kubernetes.github.io/ingress-nginx/examples/rewrite/

名称描述
nginx.ingress.kubernetes.io/rewrite-targetTarget URI where the traffic must be redirectedstring
nginx.ingress.kubernetes.io/ssl-redirectIndicates if the location section is only accessible via SSL (defaults to True when Ingress contains a Certificate)bool
nginx.ingress.kubernetes.io/force-ssl-redirectForces the redirection to HTTPS even if the Ingress is not TLS Enabledbool
nginx.ingress.kubernetes.io/app-rootDefines the Application Root that the Controller must redirect if it’s in / contextstring
nginx.ingress.kubernetes.io/use-regexIndicates if the paths defined on an Ingress use regular expressionsbool

7)配置无host字段ingress

[root@k8s-m1 nginx-ingress]# cat no-domain-ingress.yml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:name: no-domain-ingressannotations:kubernetes.io/ingress.class: "nginx"nginx.ingress.kubernetes.io/server-alias: "nginx.margu.com"nginx.ingress.kubernetes.io/use-regex: "true"   #支持nginx的rui的正则匹配
spec:rules:- http:paths: - path: /(.*)backend:serviceName: nginx-serviceservicePort: 80
[root@k8s-m1 nginx-ingress]# 

在配置中我们没有host字段,这将在ingress-nginx配置中会以如下形式展示,此种方式我们可以用IP或域名的方式访问,因为我们还配置了nginx.ingress.kubernetes.io/server-alias: “nginx.margu.com”,所以当我们用域名访问时用nginx.margu.com访问。
但是需要注意的是,在使用无域名的Ingress转发规则时,将默认使用HTTPS安全协议进行转发。如需使用非安全的HTTP,还需要额外调整Ingress Controller的相关配置,通常在一个安全的网络环境下使用。

        ## start server _server {server_name _ nginx.margu.com;listen 80 default_server reuseport backlog=4096;set $proxy_upstream_name "-";listen 443  default_server reuseport backlog=4096 ssl http2;# PEM sha: e177c1bdc45a48a1cd43a53bd559f8254c442ce7ssl_certificate                         /etc/ingress-controller/ssl/default-fake-certificate.pem;ssl_certificate_key                     /etc/ingress-controller/ssl/default-fake-certificate.pem;location ~* "^/(.*)" {set $namespace      "default";set $ingress_name   "no-domain-ingress";set $service_name   "nginx-service";set $service_port   "80";set $location_path  "/(.*)";

构建TLS站点

为了安全起见,我们一般都是要求客户端通过https进行访问,下面我们进行测试。注意:我们需要标准证书格式,不能将key+server+ca放在一个pem文件中。
1)准备证书

[root@k8s-m1 nginx-ingress]# openssl genrsa -out tls.key 2048 
Generating RSA private key, 2048 bit long modulus
.......+++
.......................................................................+++
e is 65537 (0x10001)
[root@k8s-m1 nginx-ingress]#  openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=nginx.margu.com

2)生成secret

[root@k8s-m1 nginx-ingress]# kubectl create secret tls nginx-ingress-secret --cert=tls.crt --key=tls.key
secret/nginx-ingress-secret created
[root@k8s-m1 nginx-ingress]# kubectl get secret
NAME                                  TYPE                                  DATA   AGE
nginx-ingress-secret                  kubernetes.io/tls                     2      8s
[root@k8s-m1 nginx-ingress]# kubectl describe secret nginx-ingress-secret 
Name:         nginx-ingress-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>Type:  kubernetes.io/tlsData
====
tls.crt:  1289 bytes
tls.key:  1679 bytes

3)ingress规则定义并部署

[root@k8s-m1 nginx-ingress]# cat  my-nginx-tls-ingress.yml 
apiVersion: extensions/v1beta1
kind: Ingress      
metadata:         name: ingress-frontedannotations:         kubernetes.io/ingress.class: "nginx"
spec:     tls:- hosts:- nginx.margu.comsecretName: nginx-ingress-secretrules: - host: nginx.margu.com    http:paths:       - path:       #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"backend:    #配置后端服务serviceName: nginx-serviceservicePort: 80[root@k8s-m1 nginx-ingress]# kubectl  apply -f my-nginx-tls-ingress.yml 
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.extensions/ingress-fronted-tls created
[root@k8s-m1 nginx-ingress]# kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME                  CLASS    HOSTS             ADDRESS   PORTS     AGE
ingress-fronted       <none>   *                           80        24m
ingress-fronted-tls   <none>   nginx.margu.com             80, 443   16s

4)访问测试:https://nginx.margu.com:30443
在这里插入图片描述

5)不想添加端口访问,改使用正常的80/443端口进行访问

#先删除开始nginx-ingress的nodeport暴露方式
[root@k8s-m1 nginx-ingress]# kubectl delete -f nginx-svc.yml #修改yaml,在template下面spec处添加hostNetwork和hostPID,如下
[root@k8s-m1 nginx-ingress]# vim mandatory.yaml spec:hostNetwork: truehostPID: trueserviceAccountName: nginx-ingress-serviceaccountcontainers:- name: nginx-ingress-controllerimage: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.23.0
......[root@k8s-m1 nginx-ingress]# kubectl apply  -f mandatory.yaml [root@k8s-m1 nginx-ingress]# kubectl get po -n ingress-nginx -o wide
NAME                                        READY   STATUS        RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
nginx-ingress-controller-554586bf4d-74pp2   1/1     Running       0          30s     192.168.2.142   k8s-m3   <none>           <none>
I

测试:此种方法只会在nginx-ingress 的pod所在节点上暴露端口80和443,所以在本地hosts中添加域名解析时需要注意IP地址。如上,需要解析到192.168.2.142这个IP地址。实际使用中,我们可以通过打标签的方式在多个节点部署nginx-ingess的示例,然后通过前端负载均衡器进行负载。

hosts:192.168.2.142 nginx.margu.com
在这里插入图片描述

Ingress Controller高可用

在实际使用中,为保证服务的高可用和负载均衡,我们往往需要部署多个nginx-ingress的pod,并使用haproxy+keepalived或者某些平台自带的负载均衡器进行负载。上面的例子里入口ingress-nginx使用的是nodePort的方式,Nodeport端口不是常用的web端口(但是可以修改Nodeport的范围改成web端口),如果当流量进来负载到某个node上的时候因为Ingress Controller的pod不在这个node上,会走这个node的kube-proxy转发到Ingress Controller的pod上,多转发了一次。(例如:我们Ingress Controller的pod在192.168.2.142上,但是域名解析的是192.168.2.140上,这个时候192.168.2.140这个node上的kube-proxy会把请求转发到192.168.2.142上)。故建议使用daemonset+nodeSelector的方式来ingress controller的Pod负载(每个Node节点一个ingress controller的Pod),并在前端添加使用一个负载均衡器。

不创建nginx svc,效率最高(不使用nodeport的方式进行暴露)。如果我们使用Nodeport的方式,流量是NodeIP->svc->ingress-controller(pod)这样的话会多走一层svc层,不管svc层是使用iptables还是lvs都会降低效率。如果使用hostNetwork的方式就是直接走Node节点的主机网络,唯一要注意的是hostNetwork下pod会继承宿主机的网络协议,也就是使用了主机的dns,会导致svc的请求直接走宿主机的上到公网的dns服务器而非集群里的dns server,需要设置pod的dnsPolicy: ClusterFirstWithHostNet即可解决

Ingress Controller部署方式:

  • daemonSet + nodeSeletor (一个Node节点运行一个Ingress Controller的Pod,当有多个Node的时候可以使用污点或者通过指定nodeSelector来指定部分主机来运行Ingress Controller的Pod)
  • deploy的方式部署多个ingress controller:设置replicas数量(不能大于node节点数) + nodeSeletor / podantifinity

使用 daemonSet + nodeSeletor 方式部署
1)创建一个名为ingress-nginx的service
首先我们要创建一个ingress-nginx的svc不然ingress nginx的log里会一直刷找不到ingress-nginx的svc不处理的话会狂刷log导致机器load过高,所以先创建一个同名的svc即可解决,例如创建一个不带选择器clusterip为None的。

[root@k8s-m1 nginx-ingress]#  cat ingress-nginx-no-clusterip-service.yaml
kind: Service
metadata:name: ingress-nginxnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:type: ClusterIPclusterIP: "None"ports:- name: httpport: 80targetPort: 80protocol: TCP- name: httpsport: 443targetPort: 443protocol: TCP[root@k8s-m1 nginx-ingress]#  kubectl get svc -n ingress-nginx
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
ingress-nginx   ClusterIP   None         <none>        80/TCP,443/TCP   20s

2)修改ingress-controller mandatory.yaml文件

apiVersion: apps/v1
kind: DaemonSet
metadata:name: nginx-ingress-controllernamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:selector:matchLabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxannotations:prometheus.io/port: "10254"prometheus.io/scrape: "true"spec:hostNetwork: truednsPolicy: ClusterFirstWithHostNetserviceAccountName: nginx-ingress-serviceaccount
·······[root@k8s-m1 nginx-ingress]# kubectl apply -f  mandatory.yaml [root@k8s-m1 nginx-ingress]# kubectl get pod -n ingress-nginx  -o wide 
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
nginx-ingress-controller-92rws   1/1     Running   0          4m35s   192.168.2.141   k8s-m2   <none>           <none>
nginx-ingress-controller-ffbww   1/1     Running   0          4m35s   192.168.2.142   k8s-m3   <none>           <none>
nginx-ingress-controller-qtnbg   1/1     Running   0          4m35s   192.168.2.140   k8s-m1   <none>           <none>

说明:修改部署方式为DaemonSet以及删除replicas副本集参数,新增 hostNetwork: true 和 dnsPolicy: ClusterFirstWithHostNet参数。我们可以看到Pod的IP就直接是Node节点的IP。

3)使用负载均衡器
使用平台自带的负载均衡器或者自己搭建一个haproxy+keepalived(后面分享)

最后,不同版本之间略有不同,请根据大致思路选择适合自己的版本。

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出


http://www.ppmy.cn/news/881427.html

相关文章

hive实战演练:手机流量统计

hive 本质上是一个 sql 解析引擎 &#xff0c;提供了一种类sql语言 hql 以便于使用&#xff0c;将我们熟悉的sql语言 转换成了 一个个map-reduce进程 需求 &#xff1a; 统计如下文件中 每个手机号使用流量的情况  待处理文件&#xff1a;http.dat 下载地址&#xff1a;h…

php 如何计算上网流量,手机流量是怎么计算上网流量的?

互联网时代&#xff0c;手机流量是我们生活中必不可少的一部分。但是包括小编本人的很多小伙伴&#xff0c;经常觉得自己每个月的流量使用情况都是很懵逼的。“我没怎么花流量啊&#xff0c;咋突然就告诉我剩余不足100M”“就刷了一会儿微博&#xff0c;短信提示就来了”… 到底…

2023-07-14力扣今日三题-赶上了

链接&#xff1a; 1419. 数青蛙 题意&#xff1a; 给定一个字符串&#xff0c;每个入口会顺序读入c r o a k 读完一个以后才能读入下一个&#xff0c;求要有多少个入口才能读完这个字符串&#xff0c;非法输入输出-1 解&#xff1a; 一共五个字符&#xff0c;且不重复&…

AF自动对焦的校正,需根据时机进行!

1.客户更换Lens或VCM可能需要重新调整AF Table 2.在某一距离对焦不良也需要重新调整AF参数 3.画面不清晰以及锐利度不好也有可能是AF的问题 因为AF取决于Lens&#xff0c;而Lens有DOF(景深)的范围&#xff0c;如果客户用很差的Lens或VCM 是无法调好的&#xff0c;AF跟程序有关系…

目标检测YOLO实战应用案例100讲-基于传感器融合的无人驾驶车辆目标检测与识别系统研究

目录 前言 2基于摄像头的目标检测与识别 2.1 YOLOv4目标检测模型 2.1.1卷积神经网络

相机内参fx,fy,cx,cy的方向问题,是否内参会因为标定板的方向或者拍摄方向而改变

一直在用相机内参的矩阵&#xff0c;最近忽然对它们fx,fy,cx,cy的方向产生了疑惑&#xff01; 我平时都是采用如下图所示的拍摄方式就行相机参数标定的 今天忽然需要标定竖着拍摄时的相机内参&#xff0c;拍摄图片方式如下图&#xff1a;请忽略标定板的方向&#xff0c;这里主要…

AFM测试图像假象及其应对

在做原子力显微镜AFM测试时&#xff0c;科学指南针检测平台工作人员在与很多同学沟通中了解到&#xff0c;好多同学对AFM测试不太了解&#xff0c;针对此&#xff0c;科学指南针检测平台团队组织相关同事对网上海量知识进行整理&#xff0c;希望可以帮助到科研圈的伙伴们&#…

AFM的工作模式(一)

在做原子力显微镜AFM测试时&#xff0c;科学指南针检测平台工作人员在与很多同学沟通中了解到&#xff0c;好多同学对AFM测试不太了解&#xff0c;针对此&#xff0c;科学指南针检测平台团队组织相关同事对网上海量知识进行整理&#xff0c;希望可以帮助到科研圈的伙伴们&#…