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

Docker Swarm部署报错:绑定路径不存在,疑似自动绑定docker子目录

Docker Swarm部署报错:bind path is not exist

我在Docker Swarm部署服务时碰到bind path is not exist错误,发现Docker试图绑定根目录下docker目录的所有子目录,但我没在Compose文件或GitLab CI配置里声明过相关绑定规则。已经排查过引入的CI文件只处理PHP相关构建,没涉及Docker或环境变量,甚至移除了include配置,问题还是没解决。

文件结构

docker/
  deploy/
    service.yml
  volume/
    redis/.gitkeep
    logs/.gitkeep

GitLab CI配置(.gitlab-ci.yml)

# 已确认引入的文件仅处理PHP相关构建,未涉及Docker或环境变量
include:
  - project: project/repository
    file: "deploy/php-ci.yml"

stages:
  - build
  - test
  - release

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  PROJECT_CODE: "service-2"
  PROJECT_NAMESPACE: "service-2"

cache:
  paths:
    - vendor/
    - node_modules/

branch-build:
  rules:
    - if: $CI_COMMIT_BRANCH == 'stage'
      when: always
    - if: $CI_COMMIT_BRANCH == 'main'
      when: always
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      when: always
    - if: $CI_COMMIT_BRANCH == 'devops'
      when: always

unit-test:
  stage: test
  image: $IMAGE
  allow_failure: false
  needs:
    - branch-build
  variables:
    ELASTIC_HOST: "elasticsearch.logs:9300"
    ELASTIC_LOGS_INDEX: "test_service_api"
  before_script:
    - COMPOSER_ALLOW_SUPERUSER=1 composer install --dev --no-interaction
    - cp .env.example .env
    - php artisan key:generate
  script:
    - php artisan test
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
      when: always
    - if: $CI_COMMIT_BRANCH == 'stage'
      when: always
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      when: always
    - if: $CI_COMMIT_BRANCH == 'devops'
      when: always

prod-deploy:
  needs:
    - branch-build
    - unit-test
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
      when: always

stage-deploy:
  needs:
    - branch-build
    - unit-test
  rules:
    - if: $CI_COMMIT_BRANCH == 'stage'
      when: always

# 自定义部署任务
devops-deploy:
  stage: release
  environment: staging
  needs:
    - branch-build
    - unit-test
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - cp $ENV_STAGING ./docker/deploy/.env
    - cat ./docker/deploy/.env
  script:
    - docker stack deploy -c ./docker/deploy/wizard.yml --with-registry-auth wizard
  tags:
    - swarm-stage
  rules:
    - if: $CI_COMMIT_BRANCH == 'devops'
      when: always

Compose配置(service.yml)

version: "3.8"

services:
  app:
    image: ${IMAGE}
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 1s
      update_config:
        failure_action: rollback
        parallelism: 1
        delay: 10s
    networks:
      - proxy_main
      - apiats-swarm-internal
    ports:
      - "8090:80"
    working_dir: /var/www/html
    env_file:
      - .env
    volumes:
      # 仅声明了以下绑定,未涉及deploy目录
      - ./:/var/www/html
      - ./docker/volumes/logs:/var/logs
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wizard-api-app.rule=Host(`service.local`)"
      - "traefik.http.routers.wizard-api-app.entrypoints=web"

  mailhog:
    image: mailhog/mailhog:latest
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 1s
      update_config:
        failure_action: rollback
        parallelism: 1
        delay: 10s
    ports:
      - "8025"
    networks:
      - swarm-internal

networks:
  proxy_main:
    external: true
  swarm-internal:
    external: true

Dockerfile

FROM php:8.2.15-apache

RUN apt-get update && apt-get install -y \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip \
    supervisor \
    zlib1g-dev

ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
RUN a2enmod rewrite headers

RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd opcache iconv

RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime

ENV LOG_CHANNEL=stderr

RUN apt-get clean && rm -rf /var/lib/apt/lists/*

RUN pecl install redis &&  docker-php-ext-enable redis

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

COPY *.json *.lock ./
COPY . .
COPY ./docker-entrypoint.sh /docker-entrypoint.sh
COPY ./.build/supervisor.conf /etc/supervisor/conf.d/ss.conf
RUN cp "/var/www/html/.build/php.ini" "$PHP_INI_DIR/php.ini"

RUN composer check-platform-reqs \
       && COMPOSER_ALLOW_SUPERUSER=1 composer install \
           --no-dev \
           --prefer-dist \
           --no-scripts \
           --optimize-autoloader \
           --no-interaction \
       && composer clear-cache

RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]

CMD ["apache2-foreground"]

排查与解决建议

  • 核对部署用的Compose文件:CI脚本里部署的是wizard.yml,但你提供的是service.yml,确认这两个文件内容是否一致。如果wizard.yml里存在错误的volume绑定规则,会直接导致路径不存在的问题。
  • 替换相对路径为绝对路径:Swarm模式下,volume的相对路径是基于Swarm节点的工作目录,而非GitLab Runner的工作目录。把volumes里的相对路径改成节点上的绝对路径,比如/opt/service-2/docker/volumes/logs:/var/logs,同时提前在节点上创建该目录。
  • 检查Swarm节点的目录状态:直接登录swarm-stage标签的节点,查看根目录下的docker目录是否存在,以及docker/volumes/logs等路径是否创建。如果路径不存在,手动创建后再部署。
  • 排查.env文件内容:你将$ENV_STAGING复制到部署目录的.env,检查这个文件里是否有和volume相关的变量,比如是否存在被Compose引用的VOLUME_*变量,导致意外的路径绑定。
  • 移除不必要的目录绑定:app服务里绑定./:/var/www/html在Swarm模式下风险极高,因为每个节点的本地目录结构不同,会覆盖容器内的代码。既然代码已经打包进镜像,直接删除这个volume绑定即可。

内容的提问来源于stack exchange,提问作者ChannelDSR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:43:18