88 docker 环境下面 前端A连到后端B + 前端B连到后端A

2024-02-06 08:28

本文主要是介绍88 docker 环境下面 前端A连到后端B + 前端B连到后端A,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

呵呵 最近出现了这样的一个问题, 我们有多个前端服务, 分别连接了对应的后端服务, 前端A -> 后端A, 前端B -> 后端B 

但是 最近的时候 却会出现一种情况就是, 有些时候 前端A 连接到了 后端B, 前端B 连接到了 后端A  

我们 前端服务使用 nginx 提供前端 html, js, css 的服务, 对于前端业务中的请求, 也是使用的 nginx 来代理到真实的后端服务上面, 后端服务 我们就假定为普通的 tomcat 服务器, 前后端服务都是部署在 docker 上面

然后 就给人造成一种 数据跑掉了的错觉, 呵呵 也是引起了我们同事 使用系统的很大的疑惑, 然后 搞出了一些 "我的数据 再和我做迷藏", "我的数据从成都跑到北京去了" 之类的笑话 

然后 你一去检查服务的配置, 等等, 你发现 前端配置, 后端配置 都没得问题, 我最开始以为是 nginx 运行时加载的配置 被修改了?, 加载在内存的配置 和 实际的配置文件不一致?, 但是 实际 看了一下, 发现配置是 没有问题的 

对于这个问题 还是很好奇的, 当然 后面也做了一些 探索, 也有一些 初步的推断, 然后 今天的时候[1114] 尝试在本地复现一下这个问题, 也发现了一些 和自己开始的判断 不一样的一些地方 

let's go 

问题特征

这个问题的出现 和 消失有这样的一些特征 

1. 所有的前端, 后端配置都是正常的, 但是 实际接口返回的数据 就是不一样 

2. 出现了这个问题之后, 重启一下 前端服务 之后, 前端服务就正常了 

3. 一般是后端代码更新了之后, jenkins 自动发版之后 会出现这个问题 

前端容器中 也缺少 ping 之类的网络工具, 造成排查的时候 还是存在一些 障碍 

问题inspect

最开始 想要处理这个问题, 我得看一下 nginx 最终吧服务转发到了 那一台后端服务器 

因此, 在 nginx 配置的地方, 增加了一个 add_header backendIP $upstream_addr; 来获取实际处理 后端请求的服务的信息 

然后 后来一次 是因为 后台发版了, 之后 这个问题就复现了, 这也使我观察到了 上面的 特征3 

然后 看一下 backendIP, 然后 再 inspect 对应的额后端服务, 发现后端服务的 ip 和这个 backendIP 对不上 ?? 

所以 问题的大致原因 也就出现了, 发版之后 后端服务的 ip 变化了, 然后 前端服务里面访问的 ip 还是之前的 ip 

当然 最开始, 我以为是 前端服务里面的 dns 缓存之类的, 直到今天 测试了一下, 发现 似乎是其他的原因 

接下来 我们便来以一个 demo 实际的走一下 这个流程 

构造问题

首先 我们需要 一个前端服务, 和 两个后端服务, 前端服务A 只连接 其中的一个 后端服务A 

然后 之后我们同时重启 两个后端服务, 然后 再来访问这个 前端服务A, 可能会存在 前端服务A 访问到了 后端服务B 的情况 

1. 看下后端服务 

一个简单的 SpringBoot 项目, 其中开放了一些简单的接口, 比如这里的 /hello/context, 可以输出 当前应用名称 和 一些上下文的信息 

2. 部署后端服务 

首先来部署两个后端服务, docker-compose 大致如下 

两个服务使用 同一个镜像, 只是传递的环境变量的 APP_NAME 有一些区别, 因此 访问 /hello/context 的时候 appName 的输出会有一些区别 

另外使用同一个镜像的原因在于, 更加简单的构造 两个镜像同时重启 

version: "2"networks:fuzzy:external: trueservices:app0:container_name: app0image: app0:0.0.1ports:- "7901:7901"environment:APP_NAME: app0networks:- fuzzyapp1:container_name: app1image: app0:0.0.1ports:- "7902:7901"environment:APP_NAME: app1networks:- fuzzy

服务起起来之后 测试一下, 这里把服务映射到了宿主机的端口, 根据这个来测试一下 

访问情况如下, 可以看到是 符合我们的预期的, 不是很意外 

http://localhost:7901/hello/context

http://localhost:7902/hello/context

3. 部署前端服务 

前端服务我们这里 为了简单, 是直接使用的 nginx 镜像, 没有业务, 连接 app0 的服务 

前端服务的 docker-compose 如下 

version: "2"networks:fuzzy:external: trueservices:nginx:container_name: nginximage: nginx:latestports:- "80:80"volumes:- ./data:/etc/nginxnetworks:- fuzzy

nginx 配置大致如下 

可以看到 /hello 开头的这部分请求, 我们把它 转发到了 app0 的服务上面, 使用 add_header backendIP $upstream_addr; 输出了一下 具体的处理业务的后端服务器的信息  

server {listen       80;listen  [::]:80;server_name  localhost;location / {root   /usr/share/nginx/html;index  index.html index.htm;}location ~ /hello {proxy_pass   http://app0:7901;add_header backendIP $upstream_addr;proxy_set_header SSL-Client-Cert $ssl_client_cert;proxy_set_header name jerry;}#error_page  404              /404.html;# redirect server error pages to the static page /50x.htmlerror_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}}

4. 正常情况 和 出现问题的情况 

正常的情况 

出现问题 

问题细节

正常情况

首先我们看一下 app0, app1, nginx 的 ip 情况 

从下面可以整理出 网路情况如下 

app0192.168.80.3
app1192.168.80.2
nginx192.168.80.4

然后我们来看一下 正常的情况下 处理的后端服务的情况 

可以看到的是 访问的是 ip 是 192.168.80.3 对应于上面的 app0 

我们重启 app0, app1 直到复现问题

我们可以看到 此时处理服务的容器 的ip还是 192.168.80.3 

但是 返回的数据, 却已经是 app1 应该返回的数据了 

我们再来看一下 app0, app1, nginx 的 ip 情况 

从下面可以整理出 网路情况如下 

app0192.168.80.2
app1192.168.80.3
nginx192.168.80.4

可以看到的是 app0 和 app1 的 ip 变了, 两个容器的 ip 交换了一下, 但是 前端容器 还是将服务委托给了 192.168.80.3 的这个容器, 而不是 app0 这个服务 

是前端容器的 dns 的缓存么? 

为了 验证这个问题, 呵呵 可以使用 ping 或者 nslookup 之类的网络工具, 但是 在 nginx 容器里面这两个都没得 

我今天 还想了一阵子, 怎么验证这个问题, 呵呵 curl 有一个 -v, verbose 展示出请求的更详细的信息 

curl -v http://app0:7901/hello/context 

从下面的日志信息可以看出, 从 前端服务的容器中访问 app0 访问的是 最新的app0[192.168.80.2], 因此可以排除 容器的 dns缓存的猜测 

master:nginx jerry$ docker exec -it nginx /bin/sh
# curl -v http://app0:7901/hello/context
* Expire in 0 ms for 6 (transfer 0x55712a1dff50)
* Expire in 1 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 1 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
*   Trying 192.168.80.2...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55712a1dff50)
* Connected to app0 (192.168.80.2) port 7901 (#0)
> GET /hello/context HTTP/1.1
> Host: app0:7901
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 135
< Date: Sat, 14 Nov 2020 09:24:12 GMT
< 
* Connection #0 to host app0 left intact
context info as follow!, APP_NAME : app0<br/> headers : {"host":"app0:7901","user-agent":"curl/7.64.0","accept":"*/*"}<br/> params : {}

nginx 的 dns 缓存

nginx -s reload 一下 

# nginx -s reload 
2020/11/14 09:27:13 [notice] 33#33: signal process started

看一下 /hello/context 的情况, 返回的数据也是 app0 处理之后返回的数据, backendIP 也更新成了 192.168.80.2[app0对应的ip] 

所以之前的处理方式 : 重启前端服务, 实际上真正解决问题的是 nginx 的重新加载 

完 

参考

nginx查看请求被转发到哪台服务器

这篇关于88 docker 环境下面 前端A连到后端B + 前端B连到后端A的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/683705

相关文章

Gradle下如何搭建SpringCloud分布式环境

《Gradle下如何搭建SpringCloud分布式环境》:本文主要介绍Gradle下如何搭建SpringCloud分布式环境问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Gradle下搭建SpringCloud分布式环境1.idea配置好gradle2.创建一个空的gr

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

HTML5中的Microdata与历史记录管理详解

《HTML5中的Microdata与历史记录管理详解》Microdata作为HTML5新增的一个特性,它允许开发者在HTML文档中添加更多的语义信息,以便于搜索引擎和浏览器更好地理解页面内容,本文将探... 目录html5中的Mijscrodata与历史记录管理背景简介html5中的Microdata使用M

html5的响应式布局的方法示例详解

《html5的响应式布局的方法示例详解》:本文主要介绍了HTML5中使用媒体查询和Flexbox进行响应式布局的方法,简要介绍了CSSGrid布局的基础知识和如何实现自动换行的网格布局,详细内容请阅读本文,希望能对你有所帮助... 一 使用媒体查询响应式布局        使用的参数@media这是常用的

HTML5表格语法格式详解

《HTML5表格语法格式详解》在HTML语法中,表格主要通过table、tr和td3个标签构成,本文通过实例代码讲解HTML5表格语法格式,感兴趣的朋友一起看看吧... 目录一、表格1.表格语法格式2.表格属性 3.例子二、不规则表格1.跨行2.跨列3.例子一、表格在html语法中,表格主要通过< tab

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

Python如何自动生成环境依赖包requirements

《Python如何自动生成环境依赖包requirements》:本文主要介绍Python如何自动生成环境依赖包requirements问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录生成当前 python 环境 安装的所有依赖包1、命令2、常见问题只生成当前 项目 的所有依赖包1、