利用 Docker & Nginx 实现 Node.js 集群反向代理

2025/01/16 docker

译文:Setting Up an NGINX Reverse Proxy with a Node.js Cluster Using Docker (opens new window)

在本文中,我将向大家介绍一个项目,在这个项目中,我设置了一个 Nginx 服务器作为反向代理来处理 Node.js 应用程序集群的请求。该设置使用 Docker 对 Nginx 服务器和 Node.js 应用程序进行容器化,从而实现无缝扩展和管理。在本文结束时,您将明白为什么 Nginx 是现代网络开发的必备工具,以及如何为此类用例进行配置。

# Nginx 是什么

NGINX(发音为「engine-x」)是一款高性能网络服务器和反向代理服务器。它因速度快、可靠性高和能够处理并发连接而被广泛使用。以下是它的一些主要功能:

  • 网络服务器: NGINX 可以以极快的速度提供 HTML、CSS 和 JavaScript 等静态文件。Apache 网络服务器也提供此功能,但 Nginx 因其高性能、低资源消耗和处理大量并发连接的能力而备受青睐;
  • 反向代理:它可以将传入的客户端请求转发到后端服务器或上游服务器,并将响应返回给客户端。这就提高了可扩展性和安全性。如何实现? 在这种情况下,终端用户不直接向后端服务器发送请求,而是由 Nginx 作为中介处理这项任务;
  • 负载均衡:NGINX 可以使用轮循或最少连接(默认为轮循算法)等算法在多个后端(上游)服务器之间分配传入流量;
  • Kubernetes 入口控制器:NGINX 经常被用作 Kubernetes 集群的入口控制器。在这个角色中,NGINX 接收来自云负载均衡器的请求,并将它们路由到群集内部的服务。这就确保了集群的安全,只有负载平衡器向公众开放;

# K8S 中的 Nginx

当用作 Kubernetes 入口控制器时,NGINX 在集群中扮演类似的角色。工作原理如下:云负载均衡器将请求转发给 NGINX 入口控制器。 入口控制器将请求路由到相应的 Kubernetes 服务。服务将请求转发给 Pod(应用实例)。

这种设置可确保 Kubernetes 集群的安全,只有云负载均衡器才会暴露于外部流量。

在本项目中,我们将 NGINX 用作一个 Node.js 集群的反向代理和负载均衡器,为网页提供服务。

# 项目概述

下面是该项目的 Github (opens new window) 链接,其中包括源代码、我创建的自定义 nginx 配置以及用于将整个设置容器化的 Docker-Compose 文件。

该项目由以下组件组成:

  1. NGINX 服务器:通过 8080 端口监听,并将传入的 HTTP 请求转发给 Node.js 集群;
  2. Node.js 集群: 由三个 Docker 容器组成,每个容器都在 3000 端口上运行一个 Node.js 应用程序;
  3. Docker Compose:协调所有容器的部署;

设置工作原理如下:

  1. 客户端向 8080 端口上的 NGINX 服务器发送 HTTP 请求;
  2. NGINX 作为反向代理,使用轮询负载均衡策略将请求转发给其中一个 Node.js 容器;
  3. Node.js 容器会处理请求,并通过 NGINX 返回响应;

# 自定义 Nginx 配置

以下是我在本项目中使用的 NGINX 配置文件:

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include mime.types;

    # Upstream block to define the Node.js backend servers
    upstream nodejs_cluster {
        server  app1:3000;
        server  app2:3000;
        server  app3:3000;
    }

    server {
        listen 8080;  # Listen on port 8080 for HTTP
        server_name localhost;

        # Proxying requests to the Node.js cluster
        location / {
            proxy_pass http://nodejs_cluster;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

说明

  • 配置中,我们有 serverhttpevent 等模块。在这些块中,我们有决定服务器行为的指令;
  • Nginx 设置了 worker_processes,负责获取和处理来自浏览器的请求。这些进程在单线程事件循环中处理来自用户的多个并发请求。工作进程会影响 Nginx 处理流量的能力。应根据服务器的硬件和预期流量负载进行调整。在生产层面,建议将工作进程设置为与 CPU 内核数量相当;
  • 然后,我们在事件块中设置 worker_connections 指令。这将配置每个 Worker 进程应处理的并发连接数;
  • 服务器的主要逻辑定义在 http 块中。我们还可以配置 nginx 监听使用 HTTPS 协议和 SSL 加密的请求,但在这个简单的设置中,我没有配置。因此,http 块定义了 nginx 处理用户请求的端口,以及特定域或 IP 地址的转发位置;
  • server 块通过 8080 端口监听,并将请求转发给所定义的上游服务器;
  • upstream 块定义了 Node.js 后端服务器(在我们的例子中是三个容器)。当 Nginx 充当反向代理时,向后端服务器发出的请求来自 Nginx,而不是直接来自客户端。因此,后端服务器会将 Nginx 服务器的 IP 地址视为请求源;
  • 为什么我提到: 这是因为,docker 的内部 DNS 服务会将 app1、app2 和 app3 解析到我们在 docker compose 文件中创建的 nodejs 容器服务;
  • 我们还希望转发来自原始客户端请求的信息。这将为日志记录提供有用信息。proxy_pass 指令会将请求发送到上游集群,而 HostX-Real-IP 等标头则会保留客户端信息;
  • 另一项重要配置必须是在对客户端的响应中 include mime.types。当 Nginx 从上游服务器返回响应时,它可以包含 Nginx 服务的文件类型,这有助于浏览器处理和呈现文件;

关于 Nginx 的配置就介绍到这里,这将是建立其他项目的基础,因为逻辑基本保持不变。

# Docker Compose 配置

下面是定义整个设置的 docker-compose.yml 文件:

version: '3'
services:
  app1:
    build: ./app
    environment:
      - APP_NAME=App1
    image: yashpatil16/nginx-app1:latest
    ports:
      - "3001:3000"

  app2:
    build: ./app
    environment:
      - APP_NAME=App2
    image: yashpatil16/nginx-app3:latest
    ports:
      - "3002:3000"

  app3:
    build: ./app
    environment:
      - APP_NAME=App3
    image: yashpatil16/nginx-app3:latest
    ports:
      - "3003:3000"

  nginx:
    build: ./app/nginx
    image: yashpatil16/nginx:nodejs-app
    ports:
      - "8080:8080"
    depends_on:
      - app1
      - app2
      - app3

说明

  • app1app2app3 服务分别构建并运行一个 Node.js 应用程序,在内部开放 3000 端口;
  • nginx 服务构建 NGINX 映像,向主机开放 8080 端口;
  • depends_on 指令确保 Node.js 容器先于 NGINX 启动;

我还为 Nginx 服务器容器编写了一个自定义的 DockerFile,指示它使用我的配置而不是默认配置文件。

# Use the official Nginx image as the base image
FROM nginx:latest

# Remove the default Nginx configuration file
RUN rm /etc/nginx/conf.d/default.conf

# Copy the custom Nginx configuration file
COPY ./nginx.conf /etc/nginx/conf.d/nginx.conf

# 运行项目

  1. 构建并启动容器:docker-compose up --build
  2. 在浏览器中访问应用程序 http://localhost:8080

NGINX 会将请求转发给其中一个 Node.js 容器,并返回响应:

要验证循环负载均衡方法,请检查日志:

正如 Docker Compose 文件中提到的,请求由不同的容器提供服务,在我们的例子中就是 App1、2、3。

# 总结

差不多就是这样。我们了解了 Nginx 是什么,它有哪些功能,以及如何将 Nginx 服务器设置为上游服务器的反向代理。这是一个简单的设置,但对于任何其他项目来说,逻辑都是一样的,只是在这里和那里做了更多的配置。

上次更新: 2025/1/24 08:03:38