Gắn ổ đĩa Docker thất bại sau khi VPN kết nối: hãy kiểm tra daemon
Bind mount của bạn vẫn ổn. VPN thay đổi daemon nào trả lời máy khách, vì vậy hãy in endpoint, chứng minh đường dẫn ở đó và ngừng chỉnh sửa ổ đĩa.
Gần như mọi bài viết về vấn đề này đều đổ lỗi cho ổ đĩa, và đó chính là lý do việc sửa chữa mất nhiều thời gian đến vậy. Bạn có một bind mount đang hoạt động, VPN của công ty kết nối, và docker compose up giờ đây thất bại với đường dẫn nguồn bị thiếu, thư mục rỗng hoặc một lần gắn mà engine từ chối tạo. Trong những môi trường tôi đã dọn dẹp, tệp Compose không hề thay đổi và đường dẫn vẫn đúng. Thứ đã thay đổi là daemon nào nhận được yêu cầu, và lỗi gắn kết chỉ là nơi đầu tiên mà khác biệt đó trở nên hữu hình.
Ổ đĩa không hề di chuyển; yêu cầu mới là thứ di chuyển
Một -v /srv/app:/app cờ không phải là bản sao thư mục do shell của bạn thực hiện. Máy khách biến nó thành một yêu cầu API, và daemon trả lời sẽ phân giải /srv/app theo hệ thống tệp của chính nó. Khi cả hai bên chạy trên cùng một nhân, đường dẫn đó chính là đường dẫn bạn thấy trong trình quản lý tệp. Khi endpoint thay đổi, cùng chuỗi đó được tra trên một máy chưa từng nghe nói đến thư mục dự án của bạn, và daemon hoặc báo nguồn bị thiếu hoặc lặng lẽ tạo một thư mục rỗng thay vào đó.
Đây cũng là lý do một ổ đĩa có tên vẫn hoạt động trong khi bind mount thì không. -v appdata:/app đặt tên cho vùng lưu trữ do daemon sở hữu, nên không cần bất kỳ đường dẫn máy chủ nào tồn tại ở một nơi cụ thể. Nếu việc chuyển một dịch vụ từ bind mount sang ổ đĩa có tên khiến lỗi biến mất, bạn chưa sửa được vấn đề. Bạn đã xác nhận rằng máy khách và daemon không đồng ý về việc đường dẫn thuộc hệ thống tệp nào, và sự bất đồng đó quay lại ngay khi bạn cần một thư mục máy chủ thật lần nữa.
In endpoint trước khi bạn chạm vào lần gắn
Nhiều cài đặt có thể trỏ máy khách tới một endpoint, và chúng không phải lúc nào cũng đồng ý: --context cờ, DOCKER_CONTEXT, DOCKER_HOST trong shell hiện tại, và ngữ cảnh được lưu trong cấu hình máy khách. Thay vì lý luận về thứ tự ưu tiên, hãy in tất cả và so sánh các câu trả lời.
docker context show
docker context ls
docker version
docker info --format "{{.Name}} {{.OperatingSystem}} {{.ServerVersion}}"
Cấu hình máy khách nằm ở ~/.docker/config.json trên Linux và macOS và ở %USERPROFILE%\.docker\config.json trên Windows, và một giá trị được export trong terminal hiện tại sẽ ghi đè giá trị đã lưu chỉ cho phiên đó. Nếu endpoint là tên máy chủ thay vì socket cục bộ, việc phân giải tên và các tuyến đường quyết định nó sẽ hạ cánh ở đâu, và đó chính là thứ một máy khách VPN viết lại. Một đường hầm thêm tuyến hoặc thay bộ phân giải có thể gửi một cái tên từng có nghĩa là chiếc laptop này tới một địa chỉ bên trong mạng công ty.
So sánh trạng thái thay vì cấu hình. Chạy docker ps -a và docker images khi đường hầm tắt, rồi chạy lại khi bật. Một danh sách container khác là bằng chứng mạnh hơn bất kỳ tệp cấu hình nào, vì nó cho thấy một daemon khác đã trả lời yêu cầu của bạn.
Hỏi daemon xem đường dẫn có tồn tại ở đó không
Khi bạn biết mình đã đến daemon nào, hãy bảo nó nhìn vào thư mục. --mount dạng này thất bại với thông báo rõ ràng hơn cờ ngắn, vì nó xác thực nguồn trước khi khởi động container:
docker run --rm --mount type=bind,source=/srv/app,target=/app alpine ls -la /app
Nếu nó báo nguồn bị thiếu, hãy tạo nó trên máy đã trả lời, hoặc trỏ dịch vụ tới một ổ đĩa có tên và sao chép dữ liệu vào đó. Điều bạn không nên làm là tạo lại ổ đĩa và cài lại engine trước lần kiểm tra này. Những hành động đó thay đổi môi trường đủ để che giấu sự không khớp trong khi vẫn để nó nguyên tại chỗ.
Một đường dẫn nữa chạy ở nơi hoàn toàn khác: kéo một image là việc của daemon, không phải của máy khách. Một lần kéo thành công chỉ chứng minh daemon tiếp cận được một registry, và một bind mount hoạt động chỉ chứng minh một đường dẫn đã được phân giải. Hãy kiểm tra từng đường dẫn ở nơi nó thực sự được thực thi, nếu không bạn sẽ mất cả buổi chiều cho đường dẫn sai.
Tên intranet thất bại vì một lý do khác
Nửa sau của cùng báo cáo thường là container không thể tiếp cận intranet.corp.example. Đó là một cơ chế riêng, không phải vấn đề ổ đĩa thứ hai. Container nhận /etc/resolv.conf của nó khi khởi động, được tạo từ cài đặt bộ phân giải của daemon, nên một máy chủ DNS mà VPN thêm vào sau khi container được tạo sẽ không xuất hiện ở đó cho đến khi container được tạo lại.
Bộ phân giải nhúng của Docker trên một mạng do người dùng định nghĩa chuyển tiếp các truy vấn bên ngoài tới các máy chủ đã cấu hình của máy chủ, điều này giúp ích khi VPN viết lại bộ phân giải của máy chủ và gây hại khi DNS chia tách gửi một vùng nội bộ tới một máy chủ mà daemon không còn thấy. Một ánh xạ hẹp và tường minh tránh được cuộc tranh luận cho những cái tên không bao giờ thay đổi:
services:
web:
extra_hosts:
- "intranet.corp.example:10.20.30.40"
Điều này ghi một mục vào tệp hosts của container, nên container không bao giờ học được gì về đường hầm, và nó cũng đóng băng địa chỉ. Khi máy chủ nội bộ di chuyển, mục đó vẫn sai cho đến khi ai đó sửa tệp Compose. Hãy dùng nó cho một thiết bị cố định hoặc một cơ sở dữ liệu được ghim, và để DNS xử lý những cái tên di chuyển.
Cài đặt lại thực sự thay đổi điều gì
Cài lại Docker Desktop tạo lại VM, socket và danh sách ngữ cảnh, và lần gắn bắt đầu hoạt động trở lại. Kết quả đó là thật và nó không dạy được gì, đó là lý do cùng một lỗi quay lại sau bản cập nhật VPN tiếp theo. Việc cài lại đã thay thế endpoint mà máy khách đang dùng; nó không dung hòa đường dẫn mà dự án của bạn đặt tên với hệ thống tệp mà daemon thực sự đọc.
Trình tự làm việc của tôi rất ngắn. Xác nhận endpoint mà máy khách sẽ dùng. Xác nhận daemon nào đã trả lời bằng cách so sánh danh sách container. Yêu cầu daemon đó liệt kê đường dẫn nguồn. Chỉ khi đó mới sửa lần gắn, thêm một mục hosts hoặc đổi loại ổ đĩa. Nếu bạn duy trì tệp Compose cho một nhóm làm việc qua VPN, hãy ưu tiên ổ đĩa có tên cho dữ liệu mà daemon nên sở hữu, để một đường dẫn máy chủ không bao giờ trở thành một phần của hợp đồng.