如何在Docker中隐藏后端

45次阅读
没有评论

问题描述

正在学习Docker,并尝试使用Docker发布一个非常简单的Web应用程序,其中包含两个容器:后端和前端。用户希望在最终发布时,不要将后端的端口暴露给主机。然而,由于这个原因,前端无法从后端获取数据。
以下是用户的前端index.html文件:

<html>
  <head>
    <title>Hello Public World</title>
  </head>
  <body>
    <h1>Message from backend:</h1>
    <p id="backend"></p>
    <script>
      const back = document.getElementById("backend");
      const url = "http://localhost:3333/"; //I tried backend:3333, but without success
      fetch(url)
        .then((resp) => resp.json()) // Transform the data into json
        .then(function (data) {
          back.innerHTML = data.message;
        });
    </script>
  </body>
</html>

用户的Dockerfile如下:

# pull official base image
FROM node:lts
# set working directory
WORKDIR /usr/src/app
# install app dependencies
COPY package.json ./
RUN npm install
# add app
COPY . ./
EXPOSE 3000
# start app
CMD ["npm", "run", "start"]

用户的后端index.js文件如下:

const express = require("express");
const app = express();
const cors = require("cors");
const port = 3333;
const allowlist = ["http://localhost:3000"];
const corsOptions = {
  origin: allowlist,
  methods: "GET",
  preflightContinue: false,
  optionsSuccessStatus: 204,
};
app.use(cors(corsOptions));
app.use(express.json());
app.get("/", (req, res) => {
  console.log("GET /");
  res.json({ message: "Hello Private World!" });
});
app.listen(port, () =>
  console.log(`Example app listening at http://localhost:${port}`)
);

用户的Dockerfile如下:

# pull official base image
FROM node:lts
# set working directory
WORKDIR /usr/src/app
# install app dependencies
COPY package.json ./
RUN npm install
# add app
COPY . ./
#EXPOSE 3333
# start app
CMD ["npm", "run", "start"]

用户还提供了Docker Compose文件:

version: "3.8"
services:
  backend:
    image: helloworld-private
    build:
      context: ./backend
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: "express_container"
    volumes:
      - ./backend/:/usr/src/app
      - /usr/src/app/node_modules
    networks:
      - webappnetwork
    expose:
      - "3333"
  web:
    image: helloworld-public
    build:
      context: ./web
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: "liveserver_container"
    links:
      - backend
    volumes:
      - ./web/:/usr/src/app
      - /usr/src/app/node_modules
    environment:
      - PORT=3000
    networks:
      - webappnetwork
    ports:
      - "3000:3000"
networks:
  webappnetwork:
    driver: bridge

用户想知道是否有任何抽象层次的东西他忽略了。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

在你的情况下,你需要使用nginx代理来隐藏后端。以下是一种解决方案:
1. 在你的前端应用中,定义一个用于后端API的位置,例如/api
2. 使用nginx代理将该位置的请求转发到后端容器。
3. 将静态资源(前端应用)和API代理部署在同一个nginx中,以提高性能。
4. 使用Dockerfile定义环境变量和默认值,例如:

ENV API_URL=http://backend:3333
  1. 在你的docker-compose.yaml或k8s定义中,通过环境变量更新配置。
    以下是一个示例nginx配置文件,用于将/api请求代理到后端容器:
server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }

    location /api {
        proxy_pass http://backend:3333;
    }
}

请注意,上述示例中的backend是后端容器的服务名称,你需要根据你的实际情况进行调整。

方案2

另一种方法是使用Traefik作为反向代理。Traefik是一个功能强大的反向代理和负载均衡器,可以轻松地将请求路由到不同的容器。以下是一种解决方案:
1. 在你的docker-compose.yaml文件中,将Traefik作为一个服务添加到你的网络中。
2. 在你的前端和后端服务中,使用Traefik的标签来定义路由规则和后端服务。
3. 配置Traefik以将请求路由到正确的服务。
以下是一个示例docker-compose.yaml文件,使用Traefik作为反向代理:

version: "3.8"
services:
  traefik:
    image: traefik:v2.4
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
  backend:
    image: helloworld-private
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.backend.rule=Host(`yourdomain.com`) && PathPrefix(`/api`)"
      - "traefik.http.services.backend.loadbalancer.server.port=3333"
  web:
    image: helloworld-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.web.rule=Host(`yourdomain.com`) && PathPrefix(`/`)"
      - "traefik.http.services.web.loadbalancer.server.port=3000"

请注意,上述示例中的yourdomain.com是你的域名,你需要将其替换为你自己的域名。

方案3

如果你不想使用nginx或Traefik,你还可以使用其他反向代理工具,如Apache HTTP Server或Caddy。这些工具都提供了类似的功能,可以将请求路由到不同的容器。
你可以根据你的喜好和需求选择适合你的工具,并按照它们的文档进行配置。

总结

在你的情况下,你可以使用nginx、Traefik或其他反向代理工具来隐藏后端。这些工具可以将请求路由到正确的容器,并提供更好的性能和安全性。你可以根据你的需求选择适合你的工具,并按照它们的文档进行配置。

正文完