Tóm lại: Không, VOLUME
hướng dẫn của bạn không chính xác.
Dockerfile VOLUME
chỉ định một hoặc nhiều khối lượng cho các đường dẫn phía container. Nhưng nó không cho phép tác giả hình ảnh chỉ định một đường dẫn máy chủ. Về phía máy chủ, các ổ đĩa được tạo với một tên giống như ID rất dài bên trong gốc Docker. Trên máy của tôi đây là /var/lib/docker/volumes
.
Lưu ý: Vì tên tự động quá dài và không có ý nghĩa từ quan điểm của con người, nên các tập này thường được gọi là "không tên" hoặc "ẩn danh".
Ví dụ của bạn sử dụng '.' nhân vật thậm chí sẽ không chạy trên máy của tôi, bất kể tôi tạo dấu chấm cho đối số thứ nhất hay thứ hai. Tôi nhận được thông báo lỗi này:
docker: Lỗi phản hồi từ daemon: oci runtime error: container_linux.go: 265: bắt đầu quá trình container gây ra "process_linux.go: 368: container init gây ra \" open / dev / ptmx: không có tệp hoặc thư mục như vậy \ "".
Tôi biết rằng những gì đã được nói đến thời điểm này có lẽ không có giá trị lắm đối với người đang cố gắng hiểu VOLUME
và -v
chắc chắn nó không cung cấp giải pháp cho những gì bạn cố gắng thực hiện. Vì vậy, hy vọng, các ví dụ sau đây sẽ làm sáng tỏ hơn về những vấn đề này.
Minitutorial: Chỉ định khối lượng
Đưa ra Dockerfile này:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Đối với kết quả của minitutorial này, sẽ không có gì khác biệt nếu chúng tôi chỉ định vol1 vol2
hoặc /vol1 /vol2
- đừng hỏi tôi tại sao)
Xây dựng nó:
docker build -t my-openjdk
Chạy:
docker run --rm -it my-openjdk
Trong container, chạy ls
trong dòng lệnh và bạn sẽ thấy hai thư mục tồn tại; /vol1
và /vol2
.
Chạy container cũng tạo hai thư mục, hoặc "volume", ở phía máy chủ.
Trong khi chạy container, hãy thực thi docker volume ls
trên máy chủ và bạn sẽ thấy một cái gì đó như thế này (tôi đã thay thế phần giữa của tên bằng ba dấu chấm cho ngắn gọn):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
Quay lại vùng chứa , thực thi touch /vol1/weird-ass-file
(tạo một tệp trống tại vị trí đã nói).
Tập tin này hiện có sẵn trên máy chủ, trong một trong những tập không tên lol. Tôi đã mất hai lần thử vì lần đầu tiên tôi đã thử tập được liệt kê đầu tiên, nhưng cuối cùng tôi đã tìm thấy tệp của mình trong tập được liệt kê thứ hai, sử dụng lệnh này trên máy chủ:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
Tương tự, bạn có thể cố gắng xóa tệp này trên máy chủ và nó cũng sẽ bị xóa trong vùng chứa.
Lưu ý: _data
Thư mục cũng được gọi là "điểm gắn kết".
Thoát ra khỏi container và liệt kê các khối lượng trên máy chủ. Họ đã đi. Chúng tôi đã sử dụng --rm
cờ khi chạy container và tùy chọn này xóa sạch không chỉ vùng chứa khi thoát mà còn cả khối lượng.
Chạy một container mới, nhưng chỉ định một ổ đĩa bằng cách sử dụng -v
:
docker run --rm -it -v /vol3 my-openjdk
Điều này thêm một tập thứ ba và toàn bộ hệ thống kết thúc có ba tập không tên. Lệnh sẽ bị hỏng nếu chúng tôi chỉ định -v vol3
. Đối số phải là một đường dẫn tuyệt đối bên trong container. Về phía máy chủ, tập thứ ba mới là ẩn danh và nằm cùng với hai tập còn lại /var/lib/docker/volumes/
.
Nó đã được tuyên bố trước đó rằng Dockerfile
không thể ánh xạ tới một đường dẫn máy chủ gây ra vấn đề cho chúng ta khi cố gắng đưa các tệp từ máy chủ đến vùng chứa trong thời gian chạy. Một -v
cú pháp khác nhau giải quyết vấn đề này.
Hãy tưởng tượng tôi có một thư mục con trong thư mục dự án của tôi ./src
mà tôi muốn đồng bộ hóa /src
bên trong container. Lệnh này thực hiện thủ thuật:
docker run -it -v $(pwd)/src:/src my-openjdk
Cả hai bên của :
nhân vật mong đợi một con đường tuyệt đối. Bên trái là một đường dẫn tuyệt đối trên máy chủ, bên phải là một đường dẫn tuyệt đối bên trong container. pwd
là một lệnh "in thư mục hiện tại / làm việc". Đưa lệnh vào $()
sẽ nhận lệnh trong ngoặc đơn, chạy nó trong một lớp con và mang lại đường dẫn tuyệt đối đến thư mục dự án của chúng tôi.
Đặt tất cả lại với nhau, giả sử chúng ta có ./src/Hello.java
trong thư mục dự án của mình trên máy chủ với các nội dung sau:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Chúng tôi xây dựng Dockerfile này:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Chúng tôi chạy lệnh này:
docker run -v $(pwd)/src:/src my-openjdk
Điều này in "Xin chào, thế giới!".
Phần tốt nhất là chúng tôi hoàn toàn tự do sửa đổi tệp .java bằng một thông báo mới cho đầu ra khác trong lần chạy thứ hai - mà không phải xây dựng lại hình ảnh =)
Chú thích cuối
Tôi còn khá mới với Docker và "hướng dẫn" đã nói ở trên phản ánh thông tin tôi thu thập được từ một cuộc thi hackathon dòng lệnh 3 ngày. Tôi gần như xấu hổ vì tôi đã không thể cung cấp các liên kết để xóa tài liệu giống như tiếng Anh để sao lưu các tuyên bố của mình, nhưng tôi thành thật nghĩ rằng điều này là do thiếu tài liệu và không phải là nỗ lực cá nhân. Tôi biết các ví dụ hoạt động như được quảng cáo bằng cách sử dụng thiết lập hiện tại của tôi đó là "Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce".
Hướng dẫn không giải quyết vấn đề "làm thế nào để chúng tôi chỉ định đường dẫn chứa trong Dockerfile và để lệnh chạy chỉ định đường dẫn máy chủ". Có thể có một cách, tôi chỉ không tìm thấy nó.
Cuối cùng, tôi có một cảm giác đặc biệt rằng việc chỉ định VOLUME
trong Dockerfile không chỉ là hiếm, nhưng có lẽ đó là cách tốt nhất để không bao giờ sử dụng VOLUME
. Vì hai lý do. Lý do đầu tiên chúng tôi đã xác định: Chúng tôi không thể chỉ định đường dẫn máy chủ - đó là một điều tốt vì Dockerfiles nên rất không tin vào các chi tiết cụ thể của máy chủ. Nhưng lý do thứ hai là mọi người có thể quên sử dụng --rm
tùy chọn khi chạy container. Người ta có thể nhớ để loại bỏ container nhưng quên loại bỏ âm lượng. Ngoài ra, ngay cả với bộ nhớ tốt nhất của con người, nó có thể là một nhiệm vụ khó khăn để tìm ra những khối lượng ẩn danh nào là an toàn để loại bỏ.