利用docker在本地搭建nginx环境

利用 docker 搭建如下拓扑结构的的实验环境。相关代码可以在 https://github.com/dhyuan/dockerEnv/tree/main/nginx 获得。

Topology

1) 网路

首先创建一个网络’nginx-net’,把所有的相关的容器放在这个网络里以方便容器之间的访问。
这个网络地址范围 172.50.0.0/16。相关脚本 createNetwork.sh。

docker network create --subnet=172.50.0.0/16 nginx-net

2) 创建并运行 Nginx 容器 ‘nginxA’, ‘nginxB’, ‘nginxC’.

并把个容器的 IP 固定下来防止容器重启后 IP 变化以影响日志观察。
把相关配置影射到本地方便修改。相关脚本 startNginx.sh。

下面是配置 nginx 容器 nginxA。

docker run --name nginxA \
--network nginx-net --ip 172.50.0.11 \
-v ~/dockerEnv/nginx/nginxA/html:/usr/share/nginx/html:ro \
-v ~/dockerEnv/nginx/nginxA/config/conf.d:/etc/nginx/conf.d \
-v ~/dockerEnv/nginx/nginxA/config/nginx.conf:/etc/nginx/nginx.conf:ro \
-v ~/dockerEnv/nginx/nginxA/log:/var/log/nginx \
-p 18080:9090 \
-d nginx:1.22.0

Nginx 镜像不包含 ping,curl 这样的常用工具,可以自行安装。

docker exec -it nginxA sh
apt-get update
apt-get install iputils-ping curl

3) 创建一个容器作为 client

因为 nginx 容器都在自己的网络 nginx-net 里,为了方便测试通过创建一个 Alpine 容器作为客户端环境。Alpine 容器以-it 交互模式运行。

docker run --name nclient100 --network nginx-net --ip 172.50.0.100 -it alpine:3.16.0

Alpine 镜像没有 curl 命令,可以通过 apk 安装。

apk add curl

可以在 console 发送 curl 命令进行测试。

curl http://nginxA:9090/testProxy/index.html
curl -H "X-FORWARDED-FOR: 12.3.4.5"  http://nginxA:9090/testProxy/index.html

4) Play around

因为 ngix 容器的配置、日志、html 目录都映射到了本地,所以可以本地的这些内容进行测试、验证。
可以根据自己的需要修改 nginxA(B|C)/config/confd/9090.conf 里的**”location /testProxy”** 来进行相关 nginx 相关参数的验证。

查看各容器的 IP,可运行 ./showInfo.sh
清除各容器的 nginx 日志,可运行 ./cleanlog.sh
修改 nginx 的配置后进行语法检查,可运行 ./testCfg.sh
变更了 nginx 的配置使之生效,可运行 ./reload.sh

5) Demo

下图显示了一个测试获取真实用户 IP 的场景。

为了查看 HTTP header 里的 X_REAL_IP 字段,在‘log_format main’里加上了 “ | $http_x_real_ip” ,这样在 access.log 就就可以看到 nginx 接收到的 HEADER X_REAL_IP 的值。

从图里 nginxC 的 access.log 中可以看到,nginxC 收到的 X_REAL_IP 是 ngixA 的 IP。如果我们希望这里的 X_REAL_IP 记录的是真正 web client 的 IP 就需要把 nginxB 中的指令 “proxy_set_header X-Real-IP $remote_addr;” 注释掉。这样,ngixC中收到的X_REAL_IP就是 nginxA中看到的$remote_addr,及 ngixA 看到的 client 的 IP 了。

X-FORWARDED_FOR_demo