部署前端项目 :客户端 -> 本地 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
shpip install jinja2
如果您使用的是
Python 3
,并且pip
命令指向Python 2
的pip
shpip3 install jinja2
验证安装
scsspython3 -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/app1
和 https://yourdomain.com/app2
,确保它们能够正确显示。