Cách gắn một tệp duy nhất trong một ổ đĩa


257

Tôi đang cố gắng cập bến một ứng dụng php. Trong dockerfile tôi tải xuống kho lưu trữ, giải nén nó, v.v.

Mọi thứ đều hoạt động tốt, tuy nhiên nếu một phiên bản mới được phát hành và tôi cập nhật dockerfile thì tôi phải cài đặt lại ứng dụng, vì config.php bị ghi đè.

Vì vậy, tôi nghĩ rằng tôi có thể gắn kết tệp như một ổ đĩa, giống như tôi làm với cơ sở dữ liệu.

Tôi đã thử nó theo hai cách, với âm lượng và đường dẫn trực tiếp.

docker-soạn:

version: '2'
services:
  app:
    build: src
    ports:
      - "8080:80"
    depends_on:
      - mysql
    volumes:
      -  app-conf:/var/www/html/upload
      -  app-conf:/var/www/html/config.php
    environment:
      DB_TYPE: mysql
      DB_MANAGER: MysqlManager

  mysql:
    image: mysql:5.6
    container_name: mysql
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE:
      MYSQL_USER:
      MYSQL_PASSWORD:

volumes:
  mysqldata:
  app-conf:

Kết quả là lỗi:

Và tôi đã thử nó với một đường dẫn nhất định, như một khối lượng được gắn kết.

/src/docker/myapp/upload:/var/www/html/upload
/src/docker/myapp/upload:/var/www/html/config.php

Tuy nhiên cả hai cách đều không hiệu quả. Với âm lượng được gắn, tôi thấy rằng tải lên được tạo.

Nhưng rồi thất bại với

/var/www/html/config.php \\ "gây ra \" không phải là thư mục \\ "\" "

Nếu tôi thử nó với

/src/docker/myapp/upload/config.php:/var/www/html/config.php

Docker tạo thư mục tải lên và sau đó là thư mục config.php. Không phải là một tập tin.

Hoặc có một cách khác để duy trì cấu hình?


Trong trường hợp của tôi, tôi đơn giản là "chạm" vào một tệp trống trước khi tạo vùng chứa / âm lượng. Nếu tập tin không tồn tại, nó đã tạo một thư mục.
FreeSoftwareServers

Câu trả lời:


312

TL; DR / Thông báo:

Nếu bạn gặp một thư mục được tạo thay cho tệp bạn đang cố gắn, có lẽ bạn đã không cung cấp đường dẫn hợp lệtuyệt đối . Đây là một lỗi phổ biến với chế độ thất bại im lặng và khó hiểu.

Khối lượng tệp được thực hiện theo cách này trong docker (ví dụ đường dẫn tuyệt đối (có thể sử dụng biến env) và bạn cần đề cập đến tên tệp):

    volumes:
      - /src/docker/myapp/upload:/var/www/html/upload
      - /src/docker/myapp/upload/config.php:/var/www/html/config.php

Bạn cũng có thể làm:

    volumes:
      - ${PWD}/upload:/var/www/html/upload
      - ${PWD}/upload/config.php:/var/www/html/config.php

Nếu bạn kích hoạt docker-compose từ /src/docker/myappthư mục


81
Giống như tôi đã nói, nếu tôi thử /src/docker/myapp/upload/config.php:/var/www/html/config.php Docker tạo thư mục tải lên và sau đó là thư mục config.php. Không phải là một tập tin.
Jakub Juszczak

9
Trong bài viết của bạn, bạn đã viết khác nhau. Nếu tập tin ở đó, nó sẽ gắn kết như tập tin.
BlackStork

16
Để làm việc này, tôi phải cung cấp một đường dẫn tuyệt đối. Mẹo sử dụng PWD đã giúp rất nhiều ở đây, cảm ơn!
Steve Smith

4
Đối với tôi là tạo một thư mục chứ không phải các tệp, nhưng tôi nghĩ bởi vì tệp đó được sao chép sau đó trong đường dẫn đó có cách nào để trì hoãn ràng buộc không?
eKelvin

18
nếu /src/docker/myapp/upload/config.php không tồn tại trong docker máy chủ sẽ tạo một thư mục ... Những gì tôi đang làm là tạo một tập lệnh tạo tệp trống trước khi chạy docker chạy - sẽ rất lý tưởng nếu tôi có thể hướng dẫn docker làm điều đó cho tôi thông qua cmd line args.
Cancerbero

78

Tôi đã bị một vấn đề tương tự. Tôi đã cố gắng nhập tệp cấu hình của mình vào thùng chứa để có thể sửa nó mỗi khi tôi cần mà không cần xây dựng lại hình ảnh.

Ý tôi là tôi nghĩ lệnh dưới đây sẽ ánh xạ $(pwd)/config.pytừ máy chủ Docker /root/app/config.pyvào container dưới dạng tệp.

docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image

Tuy nhiên, nó luôn tạo một thư mục có tên config.py, không phải tệp.

Trong khi tìm kiếm manh mối, tôi tìm thấy lý do (từ đây )

Nếu bạn sử dụng -v hoặc --volume để liên kết gắn kết một tệp hoặc thư mục chưa tồn tại trên máy chủ Docker, -v sẽ tạo điểm cuối cho bạn. Nó luôn được tạo như một thư mục .

Do đó, nó luôn được tạo như một thư mục vì máy chủ docker của tôi không có $(pwd)/config.py.

Ngay cả khi tôi tạo config.py trong máy chủ docker. $(pwd)/config.pychỉ overwirte /root/app/config.pykhông xuất khẩu /root/app/config.py.


16
Tôi vừa thêm một touch path/to/filecái Dockerfileđể khi tôi gắn kết nó vẫn sẽ là một tệp (không phải là thư mục đã tạo)
shadi

8
bên trái phải :là con đường đầy đủ. Nó hoạt động theo cách này
sdkks

Đó touchlà câu trả lời, hãy làm điều đó trong Dockerfile sau đó mount âm lượng soạn thảo docker của bạn sẽ hoạt động chính xác mà không cần tạo một thư mục
ctrlbrk

27

Sử dụng mount ( --mount) thay vì volume ( -v)

Thông tin thêm: https://docs.docker.com/st Storage / bind-Count /

Thí dụ:

Đảm bảo /tmp/a.txt tồn tại trên máy chủ docker

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh

Cảm ơn Subbu, @Jakub Juszczak đây sẽ là câu trả lời được chấp nhận, đó là câu trả lời duy nhất trả lời câu hỏi, và nó đã làm việc cho tôi
neokyle

2
Điều này không thực sự trả lời câu hỏi. khối lượng cũng sẽ làm việc (vì vấn đề là trong đường dẫn tuyệt đối). Sự khác biệt duy nhất giữa --mount-vlà hành vi khi phần chủ của khối lượng chưa tồn tại. Theo liên kết của bạn:> Nếu bạn sử dụng -v hoặc --volume để liên kết gắn kết một tệp hoặc thư mục chưa tồn tại trên máy chủ Docker, -v sẽ tạo điểm cuối cho bạn. Nó luôn được tạo như một thư mục.
Bố già

2
Tôi không biết làm thế nào để dịch nó thành một docker-compose. 'Sự giúp đỡ nhỏ?
msanford

@msanford Tôi đã thêm một ví dụ soạn thảo docker vào câu trả lời.
sebisnow

10

Đối với bất kỳ ai sử dụng Windows container như tôi, hãy biết rằng bạn KHÔNG THỂ liên kết hoặc gắn kết các tệp đơn bằng cách sử dụng Windows container.

Các ví dụ sau sẽ thất bại khi sử dụng các thùng chứa dựa trên Windows, vì đích đến của ổ đĩa hoặc khối gắn kết bên trong thùng chứa phải là một trong: một thư mục không tồn tại hoặc trống; hoặc một ổ đĩa khác C :. Hơn nữa, nguồn của liên kết gắn kết phải là một thư mục cục bộ, không phải là một tập tin .

net use z: \\remotemachine\share

docker run -v z:\foo:c:\dest ...

docker run -v \\uncpath\to\directory:c:\dest ...

docker run -v c:\foo\somefile.txt:c:\dest ...

docker run -v c:\foo:c: ...

docker run -v c:\foo:c:\existing-directory-with-contents ...

Thật khó để nhận ra nhưng nó ở đó

Liên kết đến vấn đề Github liên quan đến ánh xạ tệp vào bộ chứa Windows



7

Kể từ phiên bản tệp soạn thảo docker phiên bản 3.2, bạn có thể chỉ định một khối gắn kết loại "liên kết" (thay vì loại "âm lượng" mặc định) cho phép bạn gắn một tệp vào thùng chứa. Tìm kiếm "liên kết gắn kết" trong tài liệu âm lượng soạn thảo docker: https://docs.docker.com/compose/compose-file/#volume

Trong trường hợp của tôi, tôi đã cố gắn một tệp ".secrets" duy nhất vào ứng dụng của mình chỉ chứa các bí mật để phát triển và thử nghiệm cục bộ. Trong sản xuất, ứng dụng của tôi lấy các bí mật này từ AWS.

Nếu tôi gắn tệp này dưới dạng ổ đĩa bằng cú pháp tốc ký:

volumes:
 - ./.secrets:/data/app/.secrets

Docker sẽ tạo ra một ".secrets" thư mục bên trong container thay vì lập bản đồ đến tập tin bên ngoài của container. Mã của tôi sau đó sẽ đưa ra một lỗi như "IsADirectoryError: [Errno 21] Là một thư mục: '.secrets'".

Tôi đã sửa lỗi này bằng cách sử dụng cú pháp tay dài thay vào đó, chỉ định tệp bí mật của tôi bằng cách sử dụng giá trị âm lượng "liên kết" chỉ đọc:

volumes:
 - type: bind
   source: ./.secrets
   target: /data/app/.secrets
   read_only: true

Bây giờ Docker gắn chính xác tệp .secrets của tôi vào vùng chứa, tạo tệp bên trong vùng chứa thay vì thư mục. Hy vọng những người khác tìm thấy ví dụ này hữu ích!


Cảm ơn ngài! Đó là giải pháp tôi cần để có thể gắn tệp WordPress wp-config.php của tôi (và ngăn không cho nó được tạo dưới dạng thư mục)
Jono

6

Bạn cũng có thể sử dụng đường dẫn tương đối đến docker-compose.ymltệp của mình như thế này (được thử nghiệm trên máy chủ Windows, bộ chứa Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf

1
Tôi đã thử nghiệm điều này trên Mac với version: '3.7'chỉ định trong docker-compose.ymltệp với phiên bản docker-compose 1.24.1, bản dựng 4667896b và nó đã hoạt động.
Acumenus

6
Tôi vẫn nhận được một thư mục thay vì một tập tin.
chovy

0

Đối với tôi, vấn đề là tôi có một liên kết tượng trưng bị hỏng trên tập tin mà tôi đang cố gắn vào container


0

Tôi đã có vấn đề tương tự trên Windows , Docker 18.06.1-ce-win73 (19507).

Xóa và thêm lại ổ đĩa được chia sẻ thông qua bảng cài đặt Docker và mọi thứ hoạt động trở lại.


0

Trong các cửa sổ, nếu bạn cần biến env $ {PWD} trong docker-compose.yml, bạn có thể tạo tệp .env trong cùng thư mục với tệp docker-compose.yml sau đó chèn thủ công vị trí thư mục của bạn.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

Quyền hạn (pwd_var.ps1):

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env

Có nhiều tính năng hay hơn cho các biến .env soạn docker: https://docs.docker.com/compose/reference/envvars/ đặc biệt đối với COMPOSE_CONVERT_WINDOWS_PATHSbiến env cho phép docker compose chấp nhận đường dẫn windows bằng baskslash "\".

Khi bạn muốn chia sẻ một tệp trên windows, tệp phải tồn tại trước khi chia sẻ nó với container.


Bạn không thể sử dụng PowerShell với docker, nó tạo ra một nhà cung cấp khóa và gây tổn thương cho cộng đồng ...
Matej 'Yin' Gagyi

0

Có lẽ điều này giúp một ai đó.

Tôi đã có vấn đề này và đã thử mọi thứ. Liên kết khối lượng nhìn tốt và ngay cả khi tôi gắn thư mục (không phải tệp), tôi có tên tệp trong thư mục được gắn chính xác nhưng được gắn dưới dạng thư mục.

Tôi đã cố gắng kích hoạt lại các ổ đĩa được chia sẻ và Docker phàn nàn rằng tường lửa đang hoạt động.

Sau khi vô hiệu hóa tường lửa, tất cả đều hoạt động tốt.


Cảm ơn vì điều đó! Bài đăng của bạn khiến tôi nhận ra rằng selinux của tôi đã được thiết lập để thực thi và điều đó gây ra tất cả những rắc rối của tôi. Không biết tại sao bạn lại bị bỏ phiếu _ () _ /
Octavian

0

Bạn có thể gắn tập tin hoặc thư mục / thư mục tất cả phụ thuộc vào tập tin hoặc thư mục nguồn. Và bạn cũng cần cung cấp đường dẫn đầy đủ hoặc nếu bạn không chắc chắn mình có thể sử dụng PWD. Dưới đây là một ví dụ làm việc đơn giản.

Trong ví dụ này, tôi đang gắn tập tin lệnh env đã tồn tại trong thư mục làm việc của tôi

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"

-1

Tôi gặp vấn đề tương tự trên Windows 8.1

Hóa ra đó là do trường hợp nhạy cảm của đường dẫn. Tôi gọi docker-compose uptừ thư mục cd /c/users/alex/và bên trong container một tập tin đã được chuyển thành thư mục.

Nhưng khi tôi đã làm cd /c/Users/alex/(không phải người dùng viết hoa) và được gọi docker-compose uptừ đó, nó đã hoạt động.

Trong hệ thống của tôi, cả thư mục Người dùng và thư mục Alex đều được viết hoa, mặc dù có vẻ như chỉ có vấn đề về người dùng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.