Docker Compose 部署多个单页应用

Photo by Mak on Unsplash

场景

近阶段,我需要把我多个SPA部署到一台虚拟机上。多个应用通过二级域名进行访问。我知道通过 Nginx 设定多个虚拟主机可以做到这一点。但是如何和 Docker Compose 结合是个问题。目前的我是只有 SPA 应用,因此只在那个文件夹里作了一个 Nginx。假如要多个 SPA 如何编写 Docker Compose 文件呢。我想了下面两种方案。

方案

一是多个SPA放在一个容器。这意味着要共享一个 Dockerfile,感觉不利于维护。弃用;二是每个SPA放在不同容器。通过一个中转 Nginx 转发到不同容器各自的 Nginx。需要注意的是,需要在每个SPA 的 Dockerfile 中禁止默认的 Nginx Server 配置,关闭 80 端口,否则会报端口占用错误。

# 阻止80端口监听
RUN rm -f /etc/nginx/conf.d/default.conf

Docker Compose 配置

# <https://www.jianshu.com/p/658911a8cff3>
# dockercompose 配置文档
version: "3.4"
services:
  os:
    network_mode: "host"
    build:
      # version 3.4 的配置方式 <https://forums.docker.com/t/option-network-mode-host-in-docker-compose-file-not-working-as-expected/51682>
      # network: host
      context: ./os
      dockerfile: ./Dockerfile
    container_name: os
    restart: always
  admin:
    network_mode: "host"
    build:
      # version 3.4 的配置方式 <https://forums.docker.com/t/option-network-mode-host-in-docker-compose-file-not-working-as-expected/51682>
      # network: host
      context: ./admin
      dockerfile: ./Dockerfile
    container_name: admin
    restart: always
  nginx:
    network_mode: "host"
    image: nginx:latest
    container_name: nginx
    restart: always
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/my.conf

中转 Nginx 配置

# 转发给offical-site
server {
    listen      80;
    server_name www.zsdaren.com;

    location / {
        proxy_pass  http://localhost:8081;
        # if BACKEND_URI is using TLS/SSL with SNI, this is important!
        # proxy_ssl_server_name on;
        proxy_redirect  off;
        proxy_set_header  Host  $proxy_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-Host  $server_name;
    }

}

# 转发给web
server {
    listen      80;
    server_name admin.zsdaren.com;

    location / {
        proxy_pass  http://localhost:8082;
        # if BACKEND_URI is using TLS/SSL with SNI, this is important!
        # proxy_ssl_server_name on;
        proxy_redirect  off;
        proxy_set_header  Host  $proxy_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-Host  $server_name;
    }

}

SPA Nginx 配置

server {
    listen      8082;
    root /usr/share/nginx/html;

    # 出现413 Request Entity Too Large的解决方法 https://blog.csdn.net/qq_28867949/article/details/78978496
    client_max_body_size 20m;

    #charset koi8-r;
    #access_log  logs/host.access.log  main;

    location / {
        # add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass  http://localhost:8080/api;
        # if BACKEND_URI is using TLS/SSL with SNI, this is important!
        # proxy_ssl_server_name on;
        proxy_redirect  off;
        proxy_set_header  Host  $proxy_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-Host  $server_name;
    }

}

SPA Dockerfile

# 援引自这里 <https://blog.csdn.net/weixin_44042863/article/details/105872006>
# <https://hub.docker.com/_/node>
FROM node:14-alpine3.12 as stage1

WORKDIR  /os

COPY package.json ./package.json

# 安装依赖
RUN npm install

# 将代码复制到容器中
COPY . .

# 生成 /dist 目录
RUN npm run build

# <https://hub.docker.com/_/nginx>
FROM nginx:alpine

# 阻止80端口监听
RUN rm -f /etc/nginx/conf.d/default.conf

# 声明服务端口
EXPOSE 8081

COPY --from=stage1 /os/dist /usr/share/nginx/html

COPY ./nginx.conf /etc/nginx/conf.d/my.conf