Caddy 容器覆盖前端容器中的文件

问题描述 投票:0回答:1

我有一个包含 4 个容器的 docker compose 文件。 Caddy 、Watchtower 以及前端和后端容器。前端采用React+vite。后端是 Node.js 和 Express。

我在 caddy 容器和前端容器之间有一个共享卷。前端应该使用“npm run build”构建其文件,然后构建文件应该位于 caddy 的 usr/share/caddy 中,以便可以提供它们。

这是我的 docker 撰写:

services:
  caddy:
    image: caddy
    container_name: caddy_container
    ports:
      - "8080:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - frontend_build:/usr/share/caddy  
    restart: always
    networks:
      - default

  backend:
    image: hashirayaz/rehaish_backend:latest
    container_name: backend_container
    # build: ./rehaish_backend
    environment:
    - MONGO_USERNAME=${MONGO_USERNAME}
    - MONGO_PASSWORD=${MONGO_PASSWORD}
    - MONGO_DATABASE=${MONGO_DATABASE}
    - PORT=${PORT}
    - JWT_SECRET=${JWT_SECRET}
    - JWT_EXPIRES_IN=${JWT_EXPIRES_IN}
    - NODE_ENV=${NODE_ENV}
    - CORS_ORIGIN=${CORS_ORIGIN}
    - NODE_ENV=production
    ports:
      - "3000:3000"
    networks:
      - default
    
  frontend:
    image: hashirayaz/rehaish_frontend:latest
    container_name: frontend_container
    # build: ./rehaish_frontend
    volumes:
      - frontend_build:/app/dist
    environment:
      - VITE_BACKEND_URL=${VITE_BACKEND_URL}
    networks:
      - default
    depends_on:
      - backend
      - caddy
    labels:
      - com.centurylinklabs.watchtower.enable=true

  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: always
    privileged: true
    networks:
      - default
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 5
    environment:
      - REPO_USER=${DOCKER_USER}
      - REPO_PASS=${DOCKER_PAT}
      - WATCHTOWER_RETAIN=1

volumes:
  caddy_data:
  frontend_build:

networks:
  default:
    driver: bridge

这是我的球童文件:

{
    email [email protected]
}

rehaishkikhwaish.site {
    # Serve static files from the dist folder (mounted in /usr/share/caddy)
    root * /usr/share/caddy
    encode gzip
    file_server
    
    # Reverse proxy for backend API
    handle /api/* {
        reverse_proxy backend_container:3000
    }
    handle /img/* {
        reverse_proxy backend_container:3000
    }


    tls {
        issuer acme
    }
}

当我运行 docker compose up 时,caddy 自己的 index.html 正在我的网站上提供。当我将shell附加到前端容器并cd到/app/dist时,index.html是caddy自己的index.html而不是我网站的index.html

docker docker-compose mern caddy caddyfile
1个回答
0
投票

该行为听起来与 Docker 初始化命名卷的规则一致。 尝试使用命名卷将文件从一个容器发布到另一个容器存在几个重大问题,我会避免这样做。 更一般地说,我建议不要在已包含图像内容的目录上安装任何内容。

您可以构建 Dockerfile

FROM
任何您想要的其他图像。 由于您已经为镜像指定了
image:
名称,因此您可以将 Dockerfile 中的文件从前端镜像添加到代理镜像中;它可以小至
COPY

Compose 不知道图像之间的构建依赖关系,因此当您需要重建它时,您需要分两步完成

# Dockerfile.caddy FROM caddy COPY --from=hashirayaz/rehaish_frontend:latest /app/dist /usr/share/caddy

通过此设置,您还可以从 Compose 文件中删除 
docker-compose build frontend docker-compose build

卷以及所有提及它的内容。

(看起来没有任何东西会将请求传递到 

frontend_build

容器。如果这只将前端构建为静态文件,请考虑在多阶段构建中进行。这将允许您从正在运行的容器中删除无操作容器应用程序,只需运行

frontend
一次即可重建所有内容。)

通过您此处的设置,您会遇到两个直接的技术问题。 如果你启动一个挂载了 Docker 命名卷的容器,该卷是空的,你将它挂载到一个有镜像内容的目录上,那么 Docker 会将镜像内容复制到该卷中;然后,无论如何,体积内容都会隐藏原始图像中的内容。

如果 Caddy 容器首先启动(您通过

docker-compose build

强制启动),则


Caddy容器启动;
    depends_on:
  1. 卷是空的;您将其安装在带有骨架
    frontend_build
    文件的目录上;因此文件被复制到卷中。
    前端容器启动; 
  2. index.html
  3. 卷不为空;因此图像中的
    frontend_build
    容器被体积内容替换。
    
    
  4. 在这种特殊情况下,可能会反转
/app/dist

,强制

depends_on:
frontend
之前开始,而不是
反之亦然
。 但是以这种方式使用命名卷还存在其他几个问题:

它仅适用于 Docker 命名卷;不是绑定挂载、任何类型的 Kubernetes 卷挂载,也不是任何其他存储。
  • 如果您更新图像,卷永远不会更新,并且您将提供旧内容。
  • 提供的服务取决于该特定机器上的卷中的内容,因此设置不可重复。
  • 我会避免依赖 Docker 命名卷初始化。 对于像这样的许多情况,在 Dockerfile 中复制文件会更可靠,而且也不会更困难。 也可以使用入口点包装脚本在启动时将文件复制到某种共享存储中,但这会增加复杂性(您的设置显然没有入口点包装脚本),并且如果您计划最终在集群环境中运行,你不一定能获得共享存储。

© www.soinside.com 2019 - 2024. All rights reserved.