简体   繁体   English

Docker Node.js 与 nginx

[英]Docker Node.js with nginx

i try to dockerzied node.js, pm2我尝试 dockerzied node.js, pm2

This is my Dockerfile这是我的 Dockerfile

FROM node:14.17.0 AS build

# Set working directory
WORKDIR /usr/app

# Install PM2 globally
RUN npm install --global pm2
RUN cd /usr/app && ls
# Credential for real time monitoring PM2 Plus
ENV PM2_PUBLIC_KEY xxxxx
ENV PM2_SECRET_KEY xxxxx


# Copy "package.json" and "package-lock.json" before other files
# Utilise Docker cache to save re-installing dependencies if unchanged
COPY ./package*.json ./

# Install dependencies
RUN npm install

# Copy all files
COPY ./ ./

# Build app
RUN npm run-script build

# Expose the listening port
EXPOSE 3000

# Launch app with PM2
CMD [ "pm2-runtime", "start", "npm", "--", "start" ]


FROM nginx:alpine

# ## Replace the default nginx index page with our Angular app
RUN rm -rf /usr/share/nginx/html/*
RUN ls
COPY --from=build  /usr/app /usr/share/nginx/html

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

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

it's working without nginx and run succesfuly, but when i try to proxy_pass there is error.它在没有 nginx 的情况下工作并成功运行,但是当我尝试 proxy_pass 时出现错误。

nginx nginx

# Run as a less privileged user for security reasons.
user nginx;

# #worker_threads to run;
# "auto" sets it to the #CPU_cores available in the system, and
# offers the best performance.
worker_processes    auto;

events { worker_connections 1024; }

http {
    server {
        # Hide nginx version information.
        server_tokens off;

        listen  80;
        root /usr/share/nginx/html/public;
        include /etc/nginx/mime.types;

        location / {
                proxy_pass http://localhost:3000;
             #   try_files $uri $uri/ /index.php$is_args$args;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

        gzip            on;
        gzip_vary       on;
        gzip_http_version  1.0;
        gzip_comp_level 5;
        gzip_types
                        application/atom+xml
                        application/javascript
                        application/json
                        application/rss+xml
                        application/vnd.ms-fontobject
                        application/x-font-ttf
                        application/x-web-app-manifest+json
                        application/xhtml+xml
                        application/xml
                        font/opentype
                        image/svg+xml
                        image/x-icon
                        text/css
                        text/plain
                        text/x-component;
        gzip_proxied    no-cache no-store private expired auth;
        gzip_min_length 256;
        gunzip          on;
    }
}

when i add nginx conf and run当我添加 nginx conf 并运行时

docker run -d -p 3000:3000 test/test

there is error 502. what is my problem?出现错误 502。我的问题是什么? why it's not working proxy_pass.为什么它不工作proxy_pass。 without proxy_pass working fine, in 3000 port what is my problem?没有 proxy_pass 工作正常,在 3000 端口我的问题是什么? why it's not working proxy_pass.为什么它不工作proxy_pass。 without proxy_pass working fine, in 3000 port没有 proxy_pass 工作正常,在 3000 端口

A Dockerfile only builds one image, usually out of the very last build stage (starting from the final FROM line). Dockerfile 只构建一个映像,通常是在最后一个构建阶段(从最后的FROM行开始)。 So in your case the image that's being built only contains the Nginx server and the compiled front-end application.因此,在您的情况下,正在构建的映像包含 Nginx 服务器和已编译的前端应用程序。 It does not contain the separate Node server and nothing inside the container is listening on port 3000.它不包含单独的节点服务器,并且容器内没有任何东西正在监听端口 3000。

I'd suggest one of two possible approaches here.我会在这里建议两种可能的方法之一。

If your application is something like a React or Angular pure front-end application, leave this setup as-is.如果您的应用程序类似于 React 或 Angular 纯前端应用程序,请保持此设置不变。 The first stage will never be run per se so you don't need a CMD in it.第一阶段本身永远不会运行,因此您不需要CMD Remove the proxy_pass Nginx configuration option (and maybe the entire custom Nginx configuration) and just serve the static files.删除proxy_pass Nginx 配置选项(可能还有整个自定义 Nginx 配置)并只提供 static 文件。

On the other hand, if your application is more of an Express back-end service, then you need to run this as two separate containers.另一方面,如果您的应用程序更像是 Express 后端服务,那么您需要将其作为两个独立的容器运行。 This is a more involved process:这是一个更复杂的过程:

First, split this Dockerfile into two.首先,将这个 Dockerfile 一分为二。 I might have the Dockerfile be just the back-end application (I might remove the unnecessary pm2 setup, and definitely do not leak credentials via Dockerfile ENV ).我可能让Dockerfile只是后端应用程序(我可能会删除不必要的pm2设置,并且绝对不会通过 Dockerfile ENV泄漏凭据)。 A second Dockerfile.nginx would copy the static assets from the first image;第二个Dockerfile.nginx将从第一个图像中复制 static 资产; I might simplify the Dockerfile slightly我可能会稍微简化 Dockerfile

# Dockerfile.nginx
FROM nginx:alpine
COPY --from=my-name/my-app /usr/app/dist/ /usr/share/nginx/html/
COPY ./.nginx/nginx.conf /etc/nginx/nginx.conf

(So long as the built application includes an index.html it will overwrite the default contents; the base image's CMD is inherited and you don't need to restate it.) (只要构建的应用程序包含index.html它将覆盖默认内容;基础映像的CMD被继承,您无需重新声明它。)

In the Nginx configuration set proxy_pass http://backend:3000/;在Nginx配置中设置proxy_pass http://backend:3000/; Keep a try_files line too, or add separate routes for a /static or /assets path, if those files are in the image.保留try_files行,或者为/static/assets路径添加单独的路由,如果这些文件在图像中。

Finally, write a Docker Compose setup to start the two containers together:最后,编写一个 Docker Compose setup 来一起启动两个容器:

version: '3.8'
services:
  backend: # <-- this name matches proxy_pass
    build: .
    image: my-name/my-app # <-- this name matches COPY --from=
    # ports: ['3000:3000']  # optional
  proxy:
    build:
      context: .
      dockerfile: Dockerfile.nginx
    ports:
      - '8080:80'
    depends_on:
      - backend

You need to build the image in two steps;您需要分两步构建映像; first build the back-end image and then build the proxy image.先构建后端镜像,再构建代理镜像。 Compose doesn't have any native way to understand that one of the images depends on the other's content. Compose 没有任何本地方式来理解其中一个图像取决于另一个图像的内容。

docker-compose build backend
docker-compose build
docker-compose up -d

Compose automatically creates a network for you so the two containers can talk to each other using their service names backend and proxy as host names. Compose会自动为您创建一个网络,因此这两个容器可以使用它们的服务名称backendproxy作为主机名相互通信。 (You will see many examples that manually configure networks: and container_name: but these options are not necessary.) You can connect to the built application on http://localhost:8080 ; (您将看到许多手动配置networks:container_name:的示例,但这些选项不是必需的。)您可以在http://localhost:8080上连接到已构建的应用程序; in the Compose ports: option the first port number matches the port number in the URL, and the second matches the Nginx listen directive (the port inside the container where the server is running).在 Compose ports:选项中,第一个端口号与 URL 中的端口号匹配,第二个端口号与 Nginx listen指令(容器内运行服务器的端口)匹配。 I've commented out a second ports: line which would allow you to directly reach the back-end service bypassing the proxy, if you'd find that useful.我已经注释掉了第二个ports:行,它允许您绕过代理直接访问后端服务,如果您觉得这很有用的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM