node.js - 在 AWS 中部署和运行 Docker

标签 node.js reactjs amazon-web-services docker nginx

我刚刚完成我的 React 和 NodeJS 项目并为每个项目创建一个 Dockerfile,然后创建一个 docker-compose 文件来为每个项目(前端和后端)创建 docker 镜像。

我还将图像推送到 Docker 中心的存储库。
我现在该怎么办?我想在 AWS EC2 中运行我的 docker 项目,所以我在我的 AWS 仪表板中创建了一个新的 EC2 实例并在那里安装 docker 并设法从我的 docker hub 下载我的图像......

但是现在我很困惑,我需要创建一个容器来运行它们吗?我需要单独运行每一个吗?

另外,我使用 Nginx 来使用端口 80 而不是默认的 3000。

我现在真的迷路了(第一次使用 Docker 和 AWS)
谢谢!

编辑 1

我的 React dockerfile 是:

# build environment
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm ci --silent
RUN npm install react-scripts@3.4.1 -g --silent
COPY . ./
RUN npm run build

# production environment
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
# new
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

我的 Nodejs dockerfile 是:
FROM node:8

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

EXPOSE 5000

CMD [ "npm", "start" ]

我的 Nginx 配置文件是:
server {

  listen 80;

  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-compose.yml 文件是:
version: "2"
services:
  frontend:
    image: itaik/test-docker:frontend
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend
  backend:
    image: itaik/test-docker:backend
    build: ./backend
    ports:
      - "5000:5000"

在我的计算机(Windows)上,我下载了 Docker 桌面应用程序并使用 docker compose-up 命令,它使用我的两个图像创建了一个容器,一切都很好,这就是我试图在我的 AWS EC2 上实现的( Linux)。
希望现在事情更清楚了。

编辑 2

好的,所以我设法用不同的容器运行我的两个图像,它们现在都像我想要的那样在线
我使用命令:
docker run -d -p 5000:5000 itaik/test-docker:backenddocker run -d -p 80:80 itaik/test-docker:frontend
但是现在,由于某种原因,我对“localhost:5000”的所有 API 调用都出现了错误:
GET http://localhost:5000/user/ net::ERR_CONNECTION_REFUSED
这与我的 React/Nodejs 代码或我设置 docker 图像的方式有关吗?

谢谢!

编辑 3

即使在我使用 docker-compose 并且两个图像都在同一个网桥上运行之后,我仍然遇到该错误。

我能想到的唯一解决方案是手动编辑我的代码并将“localhost”更改为 AWS 公共(public) IP,但我想我只是错过了一些需要做的事情......
也许我的网桥对公共(public) IP 不可见?
因为当我进入公共(public) IP(端口 80)和端口 5000 时,我确实得到了响应。

但是对 localhost:5000 的 API 调用出现错误。

最佳答案

可能使这项工作的最短路径是

  • 将前端和后端合并到同一个 docker 镜像中(因为你必须从某个地方提供你的包,而后端是最近的已经准备好的地方)
  • 确保主机和端口设置以及容器在您的机器上正常工作
  • 将图像推送到 DockerHub(或例如 AWS ECR)
  • 在 AWS EC2 上获取机器并在那里安装 docker(如果需要,还可以安装 Docker Compose)
  • 确保您机器的控制组允许传入端口的流量(右键单击 AWS 控制台上的实例),您的应用程序将在其上运行(对于您的示例,您应该打开端口 :80)
  • 拉取镜像并启动容器(或通过 docker-compose 启动 2 个),端口设置为 80:3000 (假设您的应用在容器上的 :3000 上提供服务)
  • 在同一个 AWS EC2 控制台上单击您的实例,您将看到您机器的公共(public)地址(类似 ec2-203-0-113-25.compute-1.amazonaws.com )
  • 我认为这些是最常见的陷阱

  • 我建议将您的应用程序部署在单个镜像中(例如,在将其构建到静态包中后,Express 可以轻松地为您的前端应用程序提供服务),因为使容器相互通信可能需要一些时间。

    但是,如果您仍然想为您的应用程序提供 2 个组件——来自 Nginx 的前端和来自 NodeJS 的后端,那么您可以使用 docker-compose。只需确保每个组件的主机设置正确(它们不会在本地主机上看到对方)

    更新 2

    实际上有两种方法可以使前端与后端通信(我想您可能正在使用 axios 或类似的 API 调用):

    第一种方式 - 到 显式设置 http://<host>:<port> 作为 axios baseURL 所以你所有的 api 调用都被插入到 http://ec2-203-....amazonaws.com:3000/api/some-data .但是您应该知道确切的主机,您的后端正在服务。也许这是最明确和最简单的方法:)

    第二种方式 - 是到 让浏览器找到你的服务器 .我不是很熟悉它是如何工作的,但在高层次上它是这样工作的:用户从 yousite.com 获取您的应用程序作为捆绑包.并且应用程序需要从后端获取数据,但在代码中,这些调用是“相对的”——仅 /api/some-data说明。

    由于没有设置后端主机,应用程序要求浏览器找到它的“家”,我想,location.hostname成为此类调用的主机,因此完整的 url 变为 http://yousite.com/api/some-data .

    但是,正如您所看到的,如果用户进行此调用,它将访问 Nginx 而不是实际的后端,因为 Nginx 是服务于前端的。

    所以接下来你必须做的事情 - 代理从 Nginx 到 NodeJs 的此类调用。还有一件事——应该只代理 API 调用。其他调用应该像往常一样返回你的包。所以你必须以这种方式设置代理:
    location /api/ {
      proxy_pass http://backend:5000;
    }
    
  • 注意 NodeJs 应用程序在 backend:5000 ,而不是 localhost:5000 - 这是 docker-compose 如何设置 DNS

  • 所以现在 Nginx 做了两件事:
  • 提供静态内容
  • 反向代理 api 调用到您的后端


  • 您可能已经注意到,要让您的应用程序在 2 个容器中工作,它有很多棘手的部分。这就是您可以使用 express 提供静态内容(来自目录 build )的方式,因此您不需要使用 Nginx:

    const app = express();
    app.use('/', express.static(path.join(__dirname, 'build')));
    

    我建议尝试第一种方式 - 明确设置主机:端口 - 并启用所有日志记录,以便您知道发生了什么。完成第一部分后,更新 Nginx 以使其正常工作

    祝你好运!

    关于node.js - 在 AWS 中部署和运行 Docker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61146786/

    相关文章:

    ios - 我正在构建一个 iOS 应用程序,只是选择使用 AWS iOS SDK 而不是 BaaS 来构建后端。我刚刚为自己创造了哪些额外的工作?

    amazon-web-services - 为什么 Max、Min、Avg 统计数据在 Cloudwatch 中的 5 分钟指标上有不同的结果?

    javascript - 使用 `CanvasRenderingContext2D.putImageData()` 时出现白屏,即使数据似乎包含图像

    node.js - nodejs Kue 的条件尝试

    javascript - 在 axios 请求中包含密码的安全方法是什么?

    javascript - 从外部调用react组件

    javascript - react 引用值为空

    amazon-web-services - AWS Lambda IP 地址范围

    javascript - 在NodeJS中,有没有类似dependent : :destroy in Ruby for associated records?的方法

    node.js - 如何在 2 个应用程序之间共享 Mongoose 模型?