通过NGINX在Docker中提供Angular 10应用程序

3

我正在尝试使用NGINX在Docker中部署Angular 10 Web应用程序,但是我无法使它被服务。在Google上搜寻了很多零散的信息,但我找到了以下步骤:

  1. 通常在Docker外为生产环境(--prod构建Angular应用程序。结果保存在项目的dist文件夹中,然后将其复制到容器中。我发现其他示例在容器内使用多阶段构建,但出于可扩展性的目的不建议这样做。无论如何,手动构建应用程序让我更容易控制结果,所以对我来说这是正确的方式。

  2. 提供一个nginx:alpineDockerfile,其中我只需将自定义配置和编译后的应用程序复制到容器中,然后通过ENTRYPOINT 将其作为可执行文件运行:

FROM nginx:alpine

COPY nginx.conf /etc/nginx/nginx.conf

WORKDIR /usr/share/nginx/html
COPY dist/myapp/ .

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

这样,NGINX的日志应该会被重定向到控制台,因此显示在容器的终端中。

  1. 核心内容在NGINX配置文件中。我对此了解不多,但从https://blog.codecentric.de/en/2019/03/docker-angular-dockerize-app-easily/https://denys.dev/2018-03-02/your-angular-apps-as-docker-containers/上的证据推断出以下内容,它应该正确地考虑了HTML 5路由(保存在同一文件夹中的nginx.conf文件):
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    server {
        listen 80;
        server_name  localhost;

        root   /usr/share/nginx/html;
        index  index.html index.htm;
        include /etc/nginx/mime.types;

        gzip on;
        gzip_min_length 1000;
        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;

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

我也发现了这个其他文章,但它对Angular的配置不够完整。

  1. 构建镜像(docker build . -t myrepo/myapp:tag)。在此过程中,发送dist文件夹以外的无用内容需要花费很多时间。因此,遵循https://denys.dev/2018-03-02/your-angular-apps-as-docker-containers/中的提示("优化构建"),我添加了一个.dockerignore文件:
e2e
node_modules
src

这次构建速度比之前快多了。在两种情况下都成功构建了。
现在我可以直接运行容器(docker run -d -p 4200:80 myrepo/myapp:tag),或者通过 Docker Compose 脚本运行它。在这两种情况下,我都需要将容器的端口80(NGINX)重定向到主机端口4200(通常是 Angular 应用的本地主机端口)。
问题:我期望在localhost:4200看到由 NGINX 提供的应用程序。但实际上我只看到了 NGINX 的默认欢迎页面,告诉我 NGINX 服务器已经成功安装并工作,但需要进一步配置。
我查看了日志,但使用 docker logs mycontainer 并没有显示任何内容。
我试图检查容器的文件系统,以查看 Angular 应用是否放置在正确位置(usr/share/nginx/html)。为此,我遵循了 Exploring Docker container's file system 中的建议:对于 alpine 镜像,由于没有 bash,所以我使用 docker export mycontainer > mydump.tar 将文件系统转储到 TAR 文件中。通过查看 TAR 的内容,我可以看到我的应用程序文件都在那里:index.html,JS 文件,资产等等。
我错过了什么来完成 NGINX 配置并让我的应用程序提供服务?
更新:
我按照 @Derek 的指示操作:删除了 .gitignore,将我的 nginx.conf 替换为建议的配置文件,重新构建了应用程序,并运行了它。这一次构建大约花费了15分钟,并将1.134 GB 的构建上下文发送给 Docker 守护程序。
为了在测试环境中快速运行它,我将镜像发布到 Docker Hub 中。整个项目都是开源的,因此如果有人想要在可重复的环境中诊断问题,则有二进制映像和其源代码。
  • 镜像: vedph2020/cadmus_web:1.0.51.0.4 是我的nginx版本)。只需使用那里的 docker-compose.yml,为 cadmus-web 服务标记版本号为 1.0.5。那里有一些后端内容,但我确定它能正常工作,因为我可以连接到其端点:localhost:60380/swagger。
  • 代码库:https://github.com/vedph/cadmus_web(真实应用名称是 cadmus_web;因此构建命令是 docker build . -t vedph2020/cadmus_web:1.0.5)。

同时,我尝试创建一个空的 Angular 应用程序,并使用原始的 Dockerfile 和 nginx 文件。令我惊讶的是,它可以工作。唯一的区别是虚拟的 Angular 应用程序没有路由,而我的应用程序使用了哈希位置策略。假设在 NGINX 中存在与哈希相关的配置问题,我尝试从 http://localhost:4200/#/home 访问我的应用程序,但并没有成功:显示了相同的欢迎页面。


对于Alpine镜像,没有bash,但是它有/bin/sh可以完成同样的操作。您能否检查/usr/share/nginx/html/index.html是否包含您的代码? - Nick ODell
谢谢,阿尔派好像没有bash这只是一个推断,我还没有时间去检查。无论如何在引用的SO帖子中列出的方法都没有起作用,除了 export。就我所能从TAR中看到的,我的 index.html 包含了预期的代码。 - Naftis
2个回答

2
我告诉你如何处理容器...我看到所有的东西都是一样的,但请删除 .dockerignore 文件...当你只复制 dist 文件时,不需要忽略 src 等...

重要提示

  1. 运行 ng build 时,请验证应用程序的名称...进入文件夹并观察文件夹的名称以验证它是否是我的应用程序

结构

这需要在您的应用程序根目录中。

src
dist
    name_of_your_app
        index.html //and the other files
e2e
node_modules
nginx.conf
Dockerfile

DOCKERFILE

FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY dist/name_of_your_app/ /usr/share/nginx/html
EXPOSE 80

NGINX配置文件

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        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;
        }
    }
}

构建

docker build -t my_app .

运行

docker run -d -p 4200:80 -t my_app

就是这样...也许还需要一些配置、标签...dockerignore 是你的问题。如果这解决了你的问题,请告诉我。


非常感谢你, Derek!我按照你的指示尝试了,但是不幸的是它没有起作用。请看我更新的帖子底部。 - Naftis
很好,你解决了这个问题。对每个人来说,这种特殊情况都是一个学习的机会。 - Derek Menénedez
抱歉,你的建议没有起作用。幸运的是,我似乎找到了问题,现在发布一个答案。 - Naftis
这就是我想表达的,即使我的方法不起作用,你能找到答案也很好。 - Derek Menénedez

1
我认为我已经找到了问题所在:通过查看文件系统转储,我注意到了default.conf文件;检查其内容,我发现已经有一个端口为80的localhost位置。我认为这不应该是个问题,因为我的nginx.conf文件没有导入(include指令)它;但似乎它仍然被评估。至少,一旦我在我的Dockerfile中将其移除:
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
RUN rm /etc/nginx/conf.d/default.conf
WORKDIR /usr/share/nginx/html
COPY dist/apps/cadmus/ .
EXPOSE 80

应用程序如期启动。希望这能帮助像我这样的新手,为提供Angular定义清晰的过程(无论如何,我想我甚至可以重新引入gzip指令和.dockerignore)...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接