You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GitLab+Docker Compose部署Node应用时容器内挂载目录为空如何解决

问题根本原因
  • 你配置的./src:/app/src属于绑定挂载(bind mount),这类挂载的规则是:容器内路径的内容会完全被宿主机对应路径的内容覆盖,如果宿主机上的对应路径不存在,Docker会自动创建一个空目录挂载进去。
  • 你在GitLab CI中使用docker-compose -H ssh://$SERVER_USER@$SERVER_IP执行命令时,所有相对路径的解析、构建上下文的读取都发生在GitLab Runner执行环境本地,而非远程的Digital Ocean Droplet服务器。你的CI流程既没有在Runner本地拉取完整项目源码,也没有把源码同步到远程Droplet的对应路径,不管是Runner本地还是远程服务器上都不存在有效的./src目录,挂载后自然会覆盖镜像中原本通过COPY . .打入的/app/src代码,表现为容器内源码目录为空。
  • 额外的流程缺陷:当前CI脚本没有主动拉取仓库代码的步骤,Docker构建时拿不到完整源码上下文,就算移除挂载,构建出来的镜像本身也会缺失代码;且docker-compose up没有加后台运行参数,会导致CI任务一直阻塞不结束。
修复方案

推荐使用方案1,符合生产部署的常规逻辑:

方案1:移除开发态的源码挂载,使用镜像内置代码部署(推荐)

./src:/app/src这类挂载是本地开发时用的——修改本地代码后无需重新构建镜像即可实时同步到容器,生产环境完全不需要这个配置。

  1. 修改docker-compose.yml,删除server服务下的volumes源码挂载项,顺便补全服务重启策略:
version: '3'
services:
  mongodb:
    hostname: mongodb
    image: 'mongo:3.4.1'
    environment:
      - MONGO_DATA_DIR=/data/db
      - MONGO_LOG_DIR=/dev/null
      - MONGODB_USER="mongodbadmin"
      - MONGODB_PASS="mongodbadmin&*&"
    expose:
      - "27017"
    volumes:
      - './data/mongo:/data/db'
    command: mongod --smallfiles --logpath=/dev/null
    restart: always
  server:
    build:
      dockerfile: Dockerfile
      context: .
    working_dir: /app
    depends_on:
      - mongodb
    environment:
      - NODE_ENV=dev
    ports:
      - 3000:3000
    command: npm start
    restart: always
  1. 修改.gitlab-ci.yml,补全拉取代码的步骤,修正SSH密钥处理、容器启动参数的问题:
image: docker/compose:latest

stages:
    - deploy

variables:
    TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
    TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA
deploy:
    stage: deploy
    tags:
        - deployment
    script:
        # 安装依赖、拉取当前分支完整代码
        - apk update && apk add openssh-client git
        - git fetch --depth=1
        # 配置SSH认证
        - eval $(ssh-agent -s)
        - echo "$ID_RSA" | tr -d '\r' | ssh-add - > /dev/null
        # 远程执行部署命令
        - docker-compose -H "ssh://$SERVER_USER@$SERVER_IP" down --remove-orphans
        - docker-compose -H "ssh://$SERVER_USER@$SERVER_IP" build --no-cache
        - docker-compose -H "ssh://$SERVER_USER@$SERVER_IP" up -d # 加-d参数后台运行容器,避免CI阻塞
    only:
        - main

注:如果后续切生产环境,建议把NODE_ENV改为production,同时在Dockerfile的npm install步骤加--production参数,只安装生产依赖,减小镜像体积、降低安全风险。

方案2:保留挂载配置(仅适合特殊场景,不推荐生产用)

如果你确实需要保留源码挂载的逻辑,必须在CI流程中先把项目源码同步到远程Droplet的部署目录下,确保宿主机的./src路径存在且有完整代码,再执行docker-compose命令。
需要在CI的script步骤里、执行docker-compose命令前,加文件同步逻辑,例如用scp同步:

# 替换为你远程服务器上的实际部署路径
REMOTE_DEPLOY_PATH=/opt/node-app
# 先在远程创建部署目录
ssh $SERVER_USER@$SERVER_IP "mkdir -p $REMOTE_DEPLOY_PATH"
# 同步必要的部署文件到远程
scp -r ./src ./package.json ./Dockerfile ./docker-compose.yml $SERVER_USER@$SERVER_IP:$REMOTE_DEPLOY_PATH

同步完成后,执行docker-compose命令时需要先cd到远程的部署路径,否则相对路径解析会出错。


内容的提问来源于stack exchange,提问作者Mahmoud Mousa Hamad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 22:51:18