[笔记] 多层 Nginx反向代理与Docker容器化前端应用部署 : 客户端 -> 本地 Nginx -> Docker 内的 Nginx -> 前端应用

部署前端项目客户端 -> 本地 Nginx -> Docker 内的 Nginx -> 前端应用

在现代 Web 开发中,高效的部署流程对于确保应用的稳定性和性能至关重要。本文将介绍一种多层架构的部署方案,通过客户端访问本地 Nginx,再由本地 Nginx 转发请求到 Docker 内的 Nginx,最终到达前端应用。这种架构不仅提高了系统的可扩展性,还增强了安全性。以下是具体的部署步骤和注意事项。

环境准备 :

Nginx :用于本地和 Docker 内部的反向代理 , 可参考 [笔记] CentOS7 + Nginx 环境下,安装使用 Let's Encrypt 免费 SSL 证书 (自动续签) - 掘金

Docker :用于容器化前端应用 , 可参考 [笔记] Centos7 安装 Docker 和 Docker Compose 及 Docker 命令大全Docker和 - 掘金

一. 项目结构

arduino 复制代码
/home/luchangqiu/project
├── app1
│   ├── index.html
│   └── Dockerfile
├── app2
│   ├── index.html
│   └── Dockerfile
├── docker-compose.yml
├── generate_nginx_conf.py
├── nginx.conf.j2
└── nginx_apps.conf

二. 步骤详解

1. 创建前端项目的文件和 Dockerfile

创建 app1 的静态 HTML 文件
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>App 1</title>
</head>
<body>
    <h1>Welcome to App 1</h1>
    <p>This is the first application.</p>
</body>
</html>
创建 app1 的 Dockerfile
dockerfile 复制代码
# app1/Dockerfile

# 使用官方的 Nginx 镜像作为基础镜像
FROM nginx:alpine

# 复制静态文件到 Nginx 的默认目录
COPY ./ /usr/share/nginx/html/app1
创建 app2 的静态 HTML 文件
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>App 2</title>
</head>
<body>
    <h1>Welcome to App 2</h1>
    <p>This is the second application.</p>
</body>
</html>
创建 app2 的 Dockerfile
dockerfile 复制代码
# app2/Dockerfile

# 使用官方的 Nginx 镜像作为基础镜像
FROM nginx:alpine

# 复制静态文件到 Nginx 的默认目录
COPY ./ /usr/share/nginx/html/app2

2. 创建 Docker Compose 文件

在项目根目录下创建 docker-compose.yml 文件。

yaml 复制代码
version: '3'  # Docker Compose 文件版本,版本 3 支持更多高级功能

services:  # 定义服务列表
  nginx:  # 定义 Nginx 服务
    image: nginx:alpine  # 使用官方的 Nginx 镜像,基于 Alpine Linux
    container_name: nginx_container  # 设置容器名称
    volumes:  # 挂载卷,将主机文件映射到容器内
      - ./nginx_apps.conf:/etc/nginx/conf.d/default.conf  # 将主机上的 `nginx_apps.conf` 映射到容器内的 `/etc/nginx/conf.d/default.conf`
    ports:  # 端口映射,将容器端口映射到主机端口
      - "8080:80"  # 将容器的 80 端口映射到主机的 8080 端口
      - "4443:443"  # 将容器的 443 端口映射到主机的 4443 端口
    depends_on:  # 定义依赖关系,确保在启动 Nginx 之前先启动 `app1` 和 `app2`
      - app1
      - app2
    networks:  # 定义网络配置
      - frontend_network  # 使用名为 `frontend_network` 的网络
    healthcheck:  # 健康检查配置
      test: [ "CMD-SHELL", "nc -zv app1_container 80 && nc -zv app2_container 80" ]  # 使用 `nc` 命令检查 `app1_container` 和 `app2_container` 是否在监听 80 端口
      interval: 10s  # 每 10 秒执行一次健康检查
      timeout: 5s  # 每次健康检查超时时间为 5 秒
      retries: 5  # 如果健康检查失败,最多重试 5 次

  app1:  # 定义 `app1` 服务
    build: ./app1  # 使用 `app1` 目录下的 `Dockerfile` 构建镜像
    container_name: app1_container  # 设置容器名称
    networks:  # 定义网络配置
      - frontend_network  # 使用名为 `frontend_network` 的网络
    healthcheck:  # 健康检查配置
      test: [ "CMD-SHELL", "nc -zv 0.0.0.0 80" ]  # 使用 `nc` 命令检查容器是否在监听 80 端口
      interval: 10s  # 每 10 秒执行一次健康检查
      timeout: 5s  # 每次健康检查超时时间为 5 秒
      retries: 5  # 如果健康检查失败,最多重试 5 次

  app2:  # 定义 `app2` 服务
    build: ./app2  # 使用 `app2` 目录下的 `Dockerfile` 构建镜像
    container_name: app2_container  # 设置容器名称
    networks:  # 定义网络配置
      - frontend_network  # 使用名为 `frontend_network` 的网络
    healthcheck:  # 健康检查配置
      test: [ "CMD-SHELL", "nc -zv 0.0.0.0 80" ]  # 使用 `nc` 命令检查容器是否在监听 80 端口
      interval: 10s  # 每 10 秒执行一次健康检查
      timeout: 5s  # 每次健康检查超时时间为 5 秒
      retries: 5  # 如果健康检查失败,最多重试 5 次

networks:  # 定义网络
  frontend_network:  # 定义名为 `frontend_network` 的网络
    driver: bridge  # 使用桥接网络驱动
  • version: '3':指定 Docker Compose 文件的版本。
  • services::定义一组服务。
  • app1:app2::分别定义两个服务的详细配置,包括构建目录、容器名称、端口映射和网络连接。
  • networks::定义一个名为 frontend_network 的桥接网络,供两个服务使用。

3. 创建 Nginx 配置文件模板

在项目根目录下创建 nginx.conf.j2 文件。

jinja2 复制代码
# nginx.conf.j2
server {
    listen 80;
    server_name {{ server_name }};

    {% for app in apps %}
    location /{{ app.name }} {
        proxy_pass http://{{ app.container }}:{{ app.port }};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    {% endfor %}
}
  • server { ... }:定义一个服务器块。
  • listen 80;:监听 80 端口。
  • server_name your_domain_or_ip;:指定服务器的域名或 IP 地址。
  • {% for app in apps %} ... {% endfor %}:循环遍历应用列表。
  • location /{{ app.name }} { ... }:定义处理特定路径的请求。
  • proxy_pass http://127.0.0.1:{{ app.port }};:将请求转发到后端服务。
  • proxy_set_header:设置传递给后端服务的头部信息。

4. 创建生成 Nginx 配置文件的脚本

在项目根目录下创建 generate_nginx_conf.py 文件。

python 复制代码
# -*- coding: utf-8 -*-
# 导入必要的模块
import jinja2
import argparse
import json

# 创建模板加载器,指定模板文件的搜索路径
# searchpath="./" 表示模板文件在当前目录下
template_loader = jinja2.FileSystemLoader(searchpath="./")

# 创建 Jinja2 环境,使用上面的模板加载器
# Jinja2 环境用于加载和渲染模板
template_env = jinja2.Environment(loader=template_loader)

# 解析命令行参数
def parse_arguments():
    parser = argparse.ArgumentParser(description="Generate Nginx configuration file.")
    parser.add_argument("--server-name", type=str, required=True, help="Server name (e.g., localhost)")
    parser.add_argument("--apps", type=str, required=True, help="JSON string of apps list")
    parser.add_argument("--output-file", type=str, required=True, help="Output file path")
    return parser.parse_args()

# 主函数
def main():
    # 解析命令行参数
    args = parse_arguments()

    # 解析 JSON 字符串为 Python 列表
    apps = json.loads(args.apps)

    # 加载模板文件 nginx.conf.j2
    template = template_env.get_template('nginx.conf.j2')

    # 渲染模板,将应用列表传递给模板
    rendered_config = template.render(server_name=args.server_name, apps=apps)

    # 将渲染后的配置写入输出文件
    with open(args.output_file, 'w') as f:
        f.write(rendered_config)

    print(f"Nginx 配置文件已生成:{args.output_file}")

if __name__ == "__main__":
    main()

5. 构建和运行 Docker 容器

生成 Nginx 配置文件
sh 复制代码
cd /home/luchangqiu/project

# 运行脚本
python generate_nginx_conf.py --server-name=localhost --apps='[{"name": "app1", "container": "app1_container", "port": 80}, {"name": "app2", "container": "app2_container", "port": 80}]' --output-file=nginx_apps.conf
  • server_name:服务器名称为 localhost

  • apps:一个包含两个应用信息的 JSON 字符串,每个应用包含名称、容器名称和端口。

  • output_file:生成的 Nginx 配置文件的路径为 nginx_apps.conf

    解决 ImportError: No module named jinja2

    jinja2 是一个 Python 模板引擎,需要先安装才能使用。您可以使用 pip 来安装它。

    在您的终端中运行以下命令来安装 jinja2

    sh 复制代码
    pip install jinja2

    如果您使用的是 Python 3,并且 pip 命令指向 Python 2pip

    sh 复制代码
    pip3 install jinja2

    验证安装

    scss 复制代码
    python3 -c "import jinja2; print(jinja2.__version__)"

    再去重新运行命令 python3 generate_nginx_conf.py

构建和运行 Docker 容器
sh 复制代码
docker-compose up -d
复制代码
###### 解决 command not found

```sh
#  安装 docker-compose
pip3 install docker-compose
# 再去重新运行
docker-compose up -d
```

6. 修改本地nginx默认配置文件

添加 map 变量

map 变量和 service 同级

nginx 复制代码
	# 定义 map 变量
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
修改 监听 443 端口的 service , 添加 CORS 配置
nginx 复制代码
 		# CORS 配置
        location / {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Allow-Headers *;
            if ($request_method = 'OPTIONS') {
                return 204;
            }
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8080/;
            client_max_body_size 20m;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
完整的 nginx.conf 的 http 配置
测试 Nginx 配置文件语法正确性
sh 复制代码
nginx -t


*

重新加载 nginx 配置文件
sh 复制代码
nginx -s reload

7. 访问项目地址

访问 https://yourdomain.com/app1https://yourdomain.com/app2,确保它们能够正确显示。

相关推荐
最新资讯动态9 分钟前
想让鸿蒙应用快的“飞起”,来HarmonyOS开发者官网“最佳实践-性能专区”
前端
雾岛LYC听风15 分钟前
3. 轴指令(omron 机器自动化控制器)——>MC_GearInPos
前端·数据库·自动化
weixin_4435669816 分钟前
39-Ajax工作原理
前端·ajax
西岭千秋雪_17 分钟前
Spring Boot自动配置原理解析
java·spring boot·后端·spring·springboot
十九万里22 分钟前
基于 OpenCV + Haar Cascade 实现的极简版本人脸标注(本地化)
人工智能·后端
WebInfra23 分钟前
Rspack 1.3 发布:内存大幅优化,生态加速发展
前端·javascript·github
ak啊26 分钟前
Webpack 构建阶段:模块解析流程
前端·webpack·源码
我是谁的程序员30 分钟前
Flutter图片加载优化,自动缓存大小
后端
疯狂的程序猴31 分钟前
FlutterWeb实战:02-加载体验优化
后端
调试人生的显微镜34 分钟前
Flutter性能优化实践 —— UI篇
后端