近段时间需要实现一个转发 post 请求到指定后端服务的小工具,由于一直想学习 gin 框架,所以就使用这个框架进行尝试,预计会产生几篇文章。本文研究如何利用 nginx 容器和后端服务进行转发工具的测试。

概述

转发的工具实现起来比较简单,但为了验证,还需要使用其它工具配合,本文自编后端程序,并使用 nginx 实现多个后端程序的转发。
为方便理解,下面给出示例图。
不使用 nginx 实现转发如下图所示:
在这里插入图片描述
使用 nginx 实现转发如下图所示:
在这里插入图片描述
注意图中 URL 的变化。

后端服务

前面文章已经实现了简单的后端服务响应函数,此处不再列出。需要注意的是,因本系列转发和后端均用同一套代码,如果要在程序中启动后端服务,必须修改后端服务可执行文件名称,参考前文代码。

nginx容器启动及重启

centos/nginx-116-centos7
docker run -itd --name nginx -p 84:8080 -v $PWD:/opt/bin centos/nginx-116-centos7 bash
docker-compose
version: '2'

services:
  nginx:
    image: centos/nginx-116-centos7
    container_name: nginx
    command: /bin/bash -c "/home/latelee/bin/run.sh"
    volumes:
      - $PWD/bin:/home/latelee/bin
      - $PWD/nginx/log:/var/opt/rh/rh-nginx116/log/nginx
      - $PWD/nginx/etc:/etc/nginx
      - /etc/localtime:/etc/localtime
    #environment:
    #  - ORACLE_HOME=/work/instantclient_12_1
    #  - TNS_ADMIN=$ORACLE_HOME
    ports:
      - 8080:8080
      - 8090:8090

注:后端服务程序(和启动脚本)以及 nginx 配置文件均放到主机目录,因为这样更容易更新。

为了在容器启动时运行自定义的命令,需要关闭 nginx 服务的后台执行,启动脚本 run.sh 内容如下:

#!/bin/bash

echo "run..."
cd /home/latelee/bin

nginx -g "daemon off;"&

sleep 1
./httpforward.exe -p 8090 

关于在容器中启动 nginx 的方法,官方 docker 有介绍:

If you add a custom CMD in the Dockerfile, be sure to include -g daemon off; in the CMD in order for nginx to stay in the foreground, so that Docker can track the process properly (otherwise your container will stop immediately after starting)!

-g daemon off

启动容器:

docker-compose up -d

查看日志:

docker-compose logs -f
nginx -s reloadnginx -sstop, quit, reopen, reloadnginx -s stopnginx: [error] open() "/var/opt/rh/rh-nginx116/run/nginx/nginx.pid" failed (2: No such file or directory)reload

nginx 转发的一些测试

/etc/nginx/nginx.conf/etc/nginx/conf.dnginx -s reload
location /fee/9000 {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
/fee/9000/fee/9000proxy_pass
location /fee/9000 {
        proxy_pass http://127.0.0.1:9000;
}
/fee/9000http://127.0.0.1:9000/fee/9000
/
location /fee/9000 {
        proxy_pass http://127.0.0.1:9000/;
}

两者对比如下:

不加斜杠:http://127.0.0.1:8080/fee/9000  --> http://127.0.0.1:9000/fee/9000
添加斜杠:http://127.0.0.1:8080/fee/9000  --> http://127.0.0.1:9000/

添加斜杠的扩展:http://127.0.0.1:8080/fee/9000/foo  --> http://127.0.0.1:9000/foo
http://127.0.0.1:9000/

实验结果

请求命令:

$ curl http://192.168.28.11:8090/fee/test -X POST -F  "file=@sample.json"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   434  100    98  100   336   3920  13440 --:--:-- --:--:-- --:--:-- 18083{"code":0,"data":{"result":"ok in back end server, port: 9001 info: run in port 9001"},"msg":"ok"}

转发工具:

nginx    | got url:  http://127.0.0.1:8080/fee/9001
nginx    | [GIN] 2021/09/14 - 01:32:17 | 200 |   10.002826ms |    192.168.28.5 | POST     "/fee/test"

nginx 日志:

==> nginx/log/access.log <==
127.0.0.1 - - [14/Sep/2021:01:32:17 +0800] "POST /fee/9001 HTTP/1.1" 200 98 "-" "Go-http-client/1.1" "-"

小结

本文中,自编的转发工具要管理和配置后端程序以及 nginx,即启动若干后端程序,根据规则分配端口号(从9000开始)和 URL,将其写到 nginx 配置文件,最后重启 nginx 服务。——当然,这些都是使用较简单的方法。
在启动后端程序中,由于笔者使用相同的代码,因此花了一些时间排查问题。
在测试 nginx 转发 URL 时,也花了较多的时间(前后大概2个深夜的时间)。

在后续中,笔者将研究如何自实现负载均衡算法。——计划做此事已了大半年,趁此机会抽点时间搞下。

参考

关于转发 URL 的讨论 https://stackoverflow.com/questions/42997684/nginx-on-docker-doesnt-work-with-location-url
nginx镜像: https://hub.docker.com/_/nginx

李迟 2021.9.19 凌晨—