angular - 如何使用 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;
}
}
解决方案
我解决了我的问题。在此过程中,我做了一些编辑,但最终解开谜题的关键是我的 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;
}
}