场景
按规定尽可能减少开放到外网的端口,所以需要将多个服务部署到一个ip一个端口上。
方案
使用ng实现请求转发。根据http请求中的host与ng配置文件中的server_name匹配,转发到对应的机器上。
在docker上部署三个容器,每个容器中启动一个ng服务(这仨ng服务的欢迎页面不同,用以区分不同服务)。其中一个ng作为反向代理,另外ng作为http服务(之后这俩ng会被替换成其他服务,比如gitlab服务)。
实现
定制镜像
官方ng镜像中没有vim,而公司生产环境的电脑又不能直连互联网,所以需要在本地开发环境将ng镜像修改下然后部署到生产环境。
使用Dockerfile定制镜像。
FROM nginx:latest
RUN apt-get update && \apt-get install -y vim && \rm -rf /var/lib/apt/lists/*
在Dockerfile所在目录下执行如下命令
docker build -t nginx_wjl
不要使用
docker commit
定制镜像。具体原因参见《Docker从入门到实践 第三版》
成功定制镜像
部署
// 创建网络
docker network create ng_net// 反向代理
docker run --name mynginx0 --network ng_net -p 1080:80 -d nginx_wjl// 服务1
docker run --name mynginx1 --network ng_net -p 1081:80 -d nginx_wjl// 服务2
docker run --name mynginx2 --network ng_net -p 1082:80 -d nginx_wjl
修改文件
修改欢迎页面
vim /usr/share/nginx/html/index.html
修改反向代理的配置文件
user nginx;
worker_processes auto;error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;events {worker_connections 1024;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main 'wjl $host wjl$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;#tcp_nopush on;keepalive_timeout 65;#gzip on;include /etc/nginx/conf.d/*.conf;server {listen 80;server_name server1.com;location / {proxy_pass http://mynginx1:80;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}server {listen 80;server_name server2.com;location / {proxy_pass http://mynginx2:80;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}
}
host
SwichHosts做如下配置
127.0.0.1 server1.com
127.0.0.1 server2.com
效果
反向代理欢迎页面
server1欢迎页面
server2欢迎页面
通过反向代理访问server1欢迎页面。虽然访问的是"server1.com",但由于之前修改了host,所以实际访问的ip是回环地址。
通过反向代理访问server2欢迎页面
其他
遇到的问题
host无效
用switchhosts配置完之后,命令行中可以发现功能都正常运行,但是在浏览器上就是无法访问相应服务。就好像浏览器没有将"server1.com"这个地址解析成回环地址。
询问ChatGPT,他告诉我可能是开了代理导致的。关闭代理后问题解决了。
docker网络
容器好像必须在一个docker网络下才能相互访问。docker网络这部分内容不太了解,有机会要学习下。
ng关键文件 欢迎页面 配置文件 日志
ng容器中的关键文件存储位置可能与平时本机或者win下的不一样。以下路径都是ChatGPT告诉我的,亲测有效。
// 欢迎页面
vim /usr/share/nginx/html/index.html// 配置文件
vim /etc/nginx/nginx.conf// 日志
vim /var/log/nginx/error.log
vim /var/log/nginx/access.log
日志无效
日志文件打开之后啥也没有,原因是ng镜像中的日志文件是链接,重定向到"stdout"和"stderr"。
若要通过文件形式查看日志,可以把镜像中自带的这俩文件删除,删除之后运行"nginx -s reload"。之后的日志就会显示到这俩文件中了。
这个问题原因的发现比较偶然,手一抖打出"ls -l"的命令,然后发现这是链接。
server_name
最开始的方案中没打算通过域名进行流量分发,想通过不同的uri实现流量分发。比如访问反向代理的"/server1/add",server1就会接收到一个"/add"请求。
实现过程中发现ng配置未生效,最后发现是因为server_name没配置回环地址,但我访问的时候用的是回环地址,所以导致配置文件没提供我想要的功能。
user nginx;
worker_processes auto;error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;events {worker_connections 1024;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main 'wjlwjl$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;#tcp_nopush on;keepalive_timeout 65;#gzip on;include /etc/nginx/conf.d/*.conf;server {listen 80;server_name mynginx0 127.0.0.1;# 这里追加了回环地址。mynginx0这个是容器名,应该没啥用。location /n1 {proxy_pass http://mynginx1:80/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}location /n2 {proxy_pass http://mynginx2:80/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}
}
实现了"通过uri进行请求转发"的功能后,突然意识到可以按照server_name进行请求转发,所以本篇博客才以server_name作为请求转发的依据。
"server_name需要加回环地址"这个发现也是突然来的灵感。可能是在某个地方听说过这部分知识。
win&curl
排查问题的过程中,我尝试在容器内,在powershell,在cmd上使用curl测试请求。
curl -H "Host: server1.com" http://127.0.0.1
在反向代理容器中使用curl
但是curl在powershell中没法修改header,所以在powershell中使用了另一个指令
Invoke-WebRequest -Uri "http://127.0.0.1:1080" -Headers @{"Host" = "server1.com"}
待解决问题
反应慢
通过反向代理访问另外俩服务时反应比较慢。这个问题先delay,本篇博客实现的功能只是一个大项目中的小环节,等整个大项目完成差不多之后再性能调优。