【问题标题】:Unable to view data in docker volume using docker-compose无法使用 docker-compose 查看 docker 卷中的数据
【发布时间】:2021-12-25 18:08:15
【问题描述】:

我第一次尝试使用 docker volume,我很难让容器与主机 (Ubuntu) 共享文件。我可以使用 docker exec 查看我的代码在容器内写入的文件,但没有文件位于 /var/lib/docker/volumes 下的卷中。

我的 Docker 文件

FROM node:16-alpine

RUN apk add dumb-init
RUN addgroup gp && adduser -S appuser -G gp

RUN mkdir -p /usr/src/app/logs

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . /usr/src/app/
RUN chown -R appuser:gp /usr/src/app/logs/

USER appuser

我的 docker-compole.yml

version: "3.6"
services:
  my-service:
    user: appuser
    container_name: demou 
    build:
      context: . 
    image: "myService" 
   
    working_dir: /usr/src/app 

    ports:
      - 8080:8080 # 
    environment:
      - NODE_VERSION=16 
    volumes:
       - /logs:/logs/:rw
    command: sh -c "dumb-init node src/server.js"
    networks:
      - Snet
  # restart: always
volumes:
  logs:
   # driver: local
    name: "logs"
networks:
  Snet:
    name: "Snetwork"

server.js 除了将 helloworld.txt 文件写入日志目录之外,什么都不做。当我在容器中运行应用程序时,我没有看到任何错误甚至警告。只是日志在 docker 保存其卷的主机上不可用。我在这里错过了什么?

谢谢

【问题讨论】:

    标签: docker docker-compose docker-volume


    【解决方案1】:

    撰写文件使用绑定挂载(由 logs 之前的前导 / 表示:

    ...
    services:
      my-service:
        ...
        volumes:
           - /logs:/logs/:rw
           # ^ this slash makes the mount a bind mount
        ...
    

    我们实际上想通过删除前导 / 来使用命名卷:

    ...
    services:
      my-service:
        ...
        volumes:
           - logs:/logs/:rw 
           # ^ no slash, will be interpreted as named volume
           #   referencing the named volume "logs" defined below
        ...
    volumes:
      logs:
       # driver: local
        name: "logs"
    ...
    

    更多详情请参考relevant docker-compose file documentation


    顺便说一句:由于引用格式无效,我在启动 docker-compose.yml 文件时遇到了问题。图片名称不得包含大写字母。所以我不得不把它改成my-service。即使那样,由于缺少文件,我也无法构建my-service 图像。

    这是一个完整的docker-compose.yml,它重现了所需的行为,我使用了一个带有简单脚本的 alpine 来写入卷:

    version: "3.6"
    services:
      my-service:
        image: alpine:3.14.3
        working_dir: /logs
        volumes:
           - logs:/logs/:rw
        command: sh -c 'echo "Hello from alpine" > log.txt'
    volumes:
      logs:
        name: logs
    

    【讨论】:

    • 抱歉图片名称,我忘记了大写的问题。问题仍然存在。在 docker volume ls 下运行时可以看到日志目录,但 _data 目录始终为空。
    • 您使用的是哪个版本的 docker-compose?我正在使用最新的,但我不介意降级到旧的
    • Docker Compose version v2.0.0
    • 对不起,我在使用我的图像时遇到了错误,但是当我按照您的示例使用高山图像时错误消失了。问题是为什么我的图像表现不一样?
    • 这似乎是一个权限问题。你能:停止所有容器。删除卷logs,重新运行docker compose up?
    【解决方案2】:

    您暗示您正在尝试实际阅读输出的日志,这足够合理。对于这个用例,您应该使用 Docker 绑定挂载,而不是命名卷。

    你指定的地方

    volumes:
      - /logs:/logs:rw
    

    第一部分(以斜杠开头)是主机上的绝对路径;如果你在主机系统上ls /,在容器外,你应该在那里看到logs 目录。第二部分是容器内的路径,它与您在 Dockerfile 中指示的内容不匹配。如果你把它改成

    volumes:
      - ./logs:/usr/src/app/logs:rw
      # ^^     ^^^^^^^^^^^^
    

    使其成为主机端的相对路径和容器端的预期目录,然后您将能够直接读取包含@​​987654326@文件的目录的子目录中的日志。您可以删除文件末尾的volumes: 块。

    (为了完整起见,如果volumes: 条目的左侧根本不包含斜杠,则它指的是顶级volumes: 块中指定的命名卷;另请参阅@Turing85's answer .)

    权限方面,容器进程必须以拥有日志目录的相同 numeric 用户 ID 运行。容器 写入 的任何其他目录也必须具有相同的 numeric 所有者。镜像中的代码是否为root所有都没关系(其实这样更好,因为这样可以防止代码被意外覆盖)。

    user: 1000  # matches host uid; try running `id -u`
    volumes:    # or `ls -lnd logs`
      - ./logs:/usr/src/app/logs
    

    还可以考虑将您的应用程序设置为记录到标准输出,而不是文件。这样就避免了这个问题,您可以使用docker logs 来读取日志输出。在 Kubernetes 等更多涉及的容器环境中,有一些标准方法可以从容器中收集日志到标准输出,但收集日志到文件要复杂得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-05
      • 1970-01-01
      • 2018-01-31
      • 2021-08-19
      • 2020-05-13
      • 2018-10-28
      相关资源
      最近更新 更多