首页 > 解决方案 > 如何使用 Nginx 和 Traefik 为同一域上的 Dockerized Angular 应用程序提供静态文件?

问题描述

我想做的是在同一个域上有 2 个 Angular 应用程序,但为不同的路径提供不同的文件。例如,浏览“app1/”会显示与“app1/test”路径不同的内容。注意:这些是默认的 Angular 应用程序,它们没有做任何特别的事情。我唯一将登录页面更改为“app1”或“app2”以验证路径是否命中了正确的容器。

此外,我希望 app1/test 路径上的任何内容都解析到同一主机。所以像“app1/test”和“app1/test/page1”这样的路径会指向同一个容器。我可以毫无问题地到达 app1/,但我似乎无法弄清楚如何正确路由到 app1/test。我可以浏览到它,但它提供 app1/ 的内容,而不是它应该提供的内容。我已经验证我正在创建的所有文件也在容器内,只是没有被访问。

最后,URL 信息需要处于允许 nginx 路由到正确容器的状态,并且还允许 Angular 应用程序处理自己的虚拟路由,而这两者不会相互干扰。

这是我的配置文件:

码头工人-compose.yml


services:

  traefik:
    image: "traefik:v2.4"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  app1:
    build:
      context: ./app1
    ports:
      - "8081:80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.entrypoints=web"
      - "traefik.http.routers.app1.rule=Host(`localhost`)"
      - "traefik.http.routers.app1.middlewares=app1-stripprefix"
      - "traefik.http.routers.app1.middlewares=app1-autodetect"
      - "traefik.http.middlewares.app1-stripprefix.stripprefix.prefixes=/"
      - "traefik.http.middlewares.app1-autodetect.contenttype.autodetect=false"
      - "traefik.port=80"

  app2:
    build:
      context: ./app2
    ports:
      - "8082:80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app2.entrypoints=web"
      - "traefik.http.routers.app2.rule=Host(`localhost`) && PathPrefix(`/test{regex:$$|/.*}`)"
      - "traefik.http.routers.app2.middlewares=app2-stripprefix"
      - "traefik.http.routers.app2.middlewares=app2-autodetect"
      - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/test"
      - "traefik.http.middlewares.app2-autodetect.contenttype.autodetect=false"
      - "traefik.port=80"

两个 Angular 应用程序的 Dockerfile


# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY package.json /app/package.json
RUN npm install
RUN npm install -g @angular/cli@11.0.7

# add app
COPY . /app

# generate build
RUN ng build --output-path=dist

# base image
FROM nginx:1.16.0-alpine

# copy artifact build from the 'build environment'
COPY --from=build /app/dist /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf

# expose port 80
EXPOSE 80

# run nginx
CMD ["nginx", "-g", "daemon off;"]

app1 的 nginx.conf

include /etc/nginx/mime.types;
server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

app2 的 nginx.conf

include mime.types;
include /etc/nginx/mime.types;
server {
    listen       80;
    server_name  localhost;
    location /test {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

标签: angulardockernginxtraefik

解决方案


我解决了我的问题。在此过程中,我做了一些编辑,但最终解开谜题的关键是我的 nginx.conf 文件中的“try_files”行。在这里阅读:https ://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/

以下是更新的文件:

码头工人-compose.yml


services:

  traefik:
    image: "traefik:v2.4"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  app1:
    build:
      context: ./app1
    ports:
      - "8081:80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.entrypoints=web"
      - "traefik.http.routers.app1.rule=Host(`localhost`)"
      - "traefik.http.routers.app1.middlewares=app1-stripprefix"
      - "traefik.http.routers.app1.middlewares=app1-autodetect"
      - "traefik.http.middlewares.app1-stripprefix.stripprefix.prefixes=/"
      - "traefik.http.middlewares.app1-autodetect.contenttype.autodetect=false"
      - "traefik.port=80"

  app2:
    build:
      context: ./app2
    ports:
      - "8082:80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app2.entrypoints=web"
      - "traefik.http.routers.app2.rule=PathPrefix(`/test{regex:$$|/.*}`)"
      - "traefik.http.routers.app2.middlewares=app2-stripprefix"
      - "traefik.http.routers.app2.middlewares=app2-autodetect"
      - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/test"
      - "traefik.http.middlewares.app2-autodetect.contenttype.autodetect=false"
      - "traefik.port=80"

Dockerfile(适用于 app1)

FROM node:14.15.4 as build

WORKDIR /app

ENV PATH /app/node_modules/.bin:$PATH

COPY package.json /app/package.json
RUN npm install
RUN npm install -g @angular/cli@11.0.7

COPY . /app

RUN ng build --output-path=dist

FROM nginx:1.16.0-alpine

COPY --from=build /app/dist /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

应用程序 2 的 Dockerfile

FROM node:14.15.4 as build

WORKDIR /app

ENV PATH /app/node_modules/.bin:$PATH

COPY package.json /app/package.json
RUN npm install
RUN npm install -g @angular/cli@11.0.7

COPY . /app

RUN npm install
RUN npm install --save-dev @angular-devkit/build-angular
RUN ng build --base-href /test --deploy-url /test/ --output-path=dist

FROM nginx:1.16.0-alpine

COPY --from=build /app/dist /usr/share/nginx/html/test
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

app1 的 nginx.conf

include mime.types;
include /etc/nginx/mime.types;
server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

app2 的 nginx.conf

include mime.types;
include /etc/nginx/mime.types;
server {
    listen       80;
    server_name  localhost;
    location /test {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /test/index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
    location /.ico {
        root   /usr/share/nginx/html;
        add_header Content-Type     image/x-icon;
    }
}

推荐阅读