【问题标题】:How to route Angular app inside Nginx container?如何在 Nginx 容器内路由 Angular 应用程序?
【发布时间】:2020-08-31 03:42:16
【问题描述】:

我的问题

我想用 docker 容器部署我的 Angular 应用程序。不幸的是,我很难路由特定的 uri。

前端图像包含 nginx 和我编译的 Angular 应用程序。为了在容器内执行路由,nginx 将所有 uris 指向我编译的带有try_files $uri $uri/ myapplication/index.html =404 的应用程序,然后 Angular 路由器负责一切。

但是,当我运行前端容器时。我只能访问我的应用程序,而角度路由根本不起作用。

另一方面,如果我在没有 docker 的情况下使用 nginx 为我编译的应用程序提供服务,则路由可以完美运行。

鉴于此,我想知道:

如何在 docker 容器内正确路由 Angular 应用程序?

您可以在 Tl;dr 下方找到所有详细信息


整个构建过程

我的应用由三个服务组成:

  1. Angular 前端(Nginx + Angular)
  2. 后端 API (NodeJs + Express)
  3. 数据库(MongoDB)

1) 上下文

我有以下文件树:

|frontend
||package.json
||nginx.conf
||frontend.dockerfile
||Jumble
|backend
||package.json
||backend.dockerfile
||server.js
||Jumble
|docker-compose.yml

Docker-compose.yml 文件:

services:
  frontend:
    container_name: clockmachine-frontend
    build:
      context: ./frontend
      dockerfile: clockmachine-frontend.dockerfile

  database:
    container_name: mongo
    image: mongo
    ports:
    - "27017:27017"

  backend:
    container_name: clockmachine-api
    image: clockmachine-api
    build:
      context: ./backend
      dockerfile: clockmachine-api.dockerfile
    environment:
      - NODE_ENV=production
    ports:
      - "3000:3000"

我的前端 Dockerfile:

#### Stage 0, Build Angular frontend
FROM node:latest as build
WORKDIR /app
COPY package.json package.json
RUN npm install
COPY . .
RUN npm run build -- --prod

####Stage 1, Build Nginx backend
FROM nginx:alpine
COPY --from=build /app/dist/ /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

nginx.conf 文件:

server {
  listen 0.0.0.0:80;
  listen [::]:80;
  default_type application/octet-stream;
  client_max_body_size  256M;

  root /usr/share/nginx/html/myapplication;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html =404;
  }
}

后端 dockerfile:

#### Stage 0, Build API
FROM node:alpine
LABEL author="Olivier D'Ancona"
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node","server.js"]

2) 构建

我在主文件夹中构建了我的应用程序,如下所示:

sudo docker-compose build
sudo docker-compose up

前端将被编译并在 nginx 服务器中提供服务。 后端将使用 nodejs 和 express 部署。 数据库将从 dockerhub 中提取一个 mongo 图像。

此时,应用程序正在构建,没有问题。我控制了我的服务状态:

  1. http://localhost:27017/ 与 Mongo db 实例连接(看起来您正试图在本机驱动程序端口上通过 HTTP 访问 MongoDB。)
  2. http://localhost:3000/api/ 也能正常工作(我成功连接到 mongo)
  3. http://localhost:8080 无法连接(Firefox 无法与 localhost:8080 的服务器建立连接。)
  4. http://localhost/student 这是我的应用的静态路由(欢迎使用 nginx!如果你看到这个页面,说明 nginx 网络服务器已经成功安装并工作。需要进一步配置。)

3) 前端路由问题

所以此时,数据库和后端正在协同工作。我的应用程序在 localhost/myapplication/index.html 上提供,但角度路由不起作用,而是浏览器告诉我他无法访问我的应用程序。我发现有人有类似的问题here


4) 隔离容器

所以我尝试单独构建和运行前端容器:

我将目录更改为文件夹 /frontend 并输入:

sudo docker build -t mytag -f clockmachine-frontend.dockerfile .
sudo docker run mytag

构建过程大约需要 10 分钟并成功完成。这次当我到达http://localhost/myapplication 时,应用程序运行正常,但又遇到了这个路由问题。


5) 在没有容器的情况下运行 nginx

所以,我尝试直接在我的机器上运行 nginx。我编译了我的前端应用程序:

ng build --prod

并将其移至/usr/share/nginx/html/myapplication

我使用相同的 nginx.conf 配置文件并将其放入/etc/nginx/conf.d/default.conf,我什至尝试更改文件名而不覆盖 default.conf 文件。

结果是我的应用程序在localhost/myapplication 上正常运行,角度路由完美运行!


6) 结论

总而言之,我尝试运行 docker-compose 文件,但前端容器出现路由问题。然后我隔离了这个容器,结果也一样。最后,我直接使用 nginx 为我的应用程序提供服务,并且成功了,因为路由工作正常。

【问题讨论】:

  • 那是一大堆文字。如果有很多人会阅读所有这些,我会感到惊讶。你需要努力使这个问题更简洁。在此之前,VTC 过于宽泛,抱歉
  • 这是因为如果我不提供一些上下文,这真的很具体,没有人可以帮助我。我已经尝试留下更少的细节。此外,第 1 部分)只是作为我所做的文档的文档,只有介绍和结论才真正重要
  • 我已经删除了一些不相关的信息,并试图将有用的东西移到顶部

标签: angular docker nginx docker-compose routes


【解决方案1】:

终于,经过 15 天的劳动,我修好了!

问题出在 nginx 配置中的 listen [::]:80 行。 另外,前端容器的端口设置不正确。

这就是我实现它的方式:

前端 Dockerfile:

# Stage 0: compile angular frontend
FROM node:latest as build
WORKDIR /app
COPY . . 
RUN npm install
RUN npm run build --prod


# Stage 1: serve app with nginx server
FROM nginx:latest
COPY --from=build /app/dist/pointeuse  /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Nginx 配置:

server {
  listen 80;
  sendfile on;
  default_type application/octet-stream;

  gzip on;
  gzip_http_version 1.1;
  gzip_disable      "MSIE [1-6]\.";
  gzip_min_length   256;
  gzip_vary         on;
  gzip_proxied      expired no-cache no-store private auth;
  gzip_types        text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_comp_level   9;

  root /usr/share/nginx/html;

  location / {
    try_files $uri $uri/ /index.html =404;
  }
}

Docker-compose 文件:

version: '3.1'

services:
        frontend:
                container_name: clockmachine-frontend
                depends_on:
                        - database 
                        - backend
                image: clockmachine-frontend
                build:
                        context: ./frontend
                        dockerfile: frontend.dockerfile
                ports:
                        - "80:80"
        database:
                container_name: mongo
                image: mongo
                ports:
                        - "27017:27017"

        backend:
                container_name: clockmachine-api
                image: clockmachine-api
                build:
                        context: ./backend
                        dockerfile: backend.dockerfile
                environment:
                        - NODE_ENV=production
                ports:
                        - "3000:3000"

如您所见,我重命名了上下文文件。

使用 nginx 服务器将 Angular 应用程序容器化是一团糟,因为文档各不相同。

如果你想部署一个 Angular 应用程序

查看此链接:

  1. Angular deployment Documentation
  2. Dan Wahlin example
  3. Serving static content with nginx
  4. Nginx.org documentation

【讨论】:

  • 我在这个问题上迟到了,但我用同样的方法让它工作。我对此有有效的解决方案。但是恭喜你解开了这个谜
  • 你不应该在 db 服务中打开 27017:27017 端口,因为没有人需要在应用程序之外访问数据库。
【解决方案2】:

我认为问题在于您为前端应用程序使用了 /myapplication 前缀。
最好是直接在根 url 上托管应用程序而不使用“虚拟目录”。

但是,如果您仍然需要使用它,则需要在 Angular index.html Base href (https://angular.io/guide/deployment#the-base-tag) 中设置您将使用的路径,在本例中为“/myapplication”。

其次,try_files $uri $uri/ myapplication/index.html =404 应该是 try_files myapplication/$uri myapplication/$uri/ myapplication/index.html =404,因为您不想重定向不以 myapplication 开头的元素。

【讨论】:

  • 你好 Miq,目前当我遇到路由问题时,nginx 进入文件夹并为我的 myapp/index.html 提供服务。 html 已加载,但 angular 转译文件(polyfill、runtime 和 main)不会加载,因为 nginx 尝试发回我的 html 文件。对于每个文件,我都收到此错误:从“localhost:8080/runtime-es2015.1eba213af0b233498d9d.js”加载模块由于不允许的 MIME 类型(“text/html”)而被阻止。
猜你喜欢
  • 1970-01-01
  • 2020-06-04
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 2016-04-14
  • 2019-11-19
相关资源
最近更新 更多