Sự khác biệt giữa các cuộc triển lãm trên đường phố và sự xuất bản trên mạng của Docker là gì?


517

Tôi đang thử nghiệm với Dockerfiles và tôi nghĩ rằng tôi hiểu hầu hết logic. Tuy nhiên, tôi không thấy sự khác biệt giữa "phơi bày" và "xuất bản" một cổng trong bối cảnh này.

Tất cả các hướng dẫn tôi đã thấy đầu tiên bao gồm EXPOSElệnh trong Dockerfile:

...
EXPOSE 8080
...

Sau đó, họ xây dựng một hình ảnh từ Dockerfile này:

$ docker build -t an_image - < Dockerfile

Và sau đó xuất bản cùng một cổng như trên khi chạy hình ảnh:

$ docker run -d -p 8080 an_image

hoặc xuất bản tất cả các cổng bằng cách sử dụng

$ docker run -d -P an_image

Điểm phơi bày một cổng trong Dockerfile là gì, nếu nó sẽ được xuất bản? Có bao giờ cần phải phơi bày một cổng trước và không xuất bản nó sau không? Thực tế, tôi muốn chỉ định tất cả các cổng mà tôi sẽ sử dụng trong Dockerfile khi tạo hình ảnh, và sau đó không bận tâm đến chúng nữa, chạy chúng đơn giản với:

$ docker run -d an_image

Điều này có thể không?

Câu trả lời:


732

Về cơ bản, bạn có ba tùy chọn:

  1. Không chỉ định EXPOSEcũng không-p
  2. Chỉ xác định EXPOSE
  3. Chỉ định EXPOSE-p

1) Nếu bạn chỉ định cũng không EXPOSEphải -p, dịch vụ trong container sẽ chỉ có thể truy cập được từ bên trong container.

2) Nếu bạn EXPOSElà một cổng, dịch vụ trong vùng chứa không thể truy cập được từ bên ngoài Docker, nhưng từ bên trong các container Docker khác. Vì vậy, điều này là tốt cho giao tiếp giữa các container.

3) Nếu bạn EXPOSE-pmột cổng, dịch vụ trong container có thể truy cập từ mọi nơi, ngay cả ngoài Docker.

Lý do tại sao cả hai được tách ra là IMHO vì:

  • việc chọn một cổng máy chủ phụ thuộc vào máy chủ và do đó không thuộc về Dockerfile (nếu không thì nó sẽ phụ thuộc vào máy chủ),
  • và thường là đủ nếu một dịch vụ trong một container có thể truy cập được từ các container khác.

Các tài liệu nêu rõ:

Các EXPOSEhướng dẫn cho thấy cổng để sử dụng trong các liên kết.

Nó cũng chỉ cho bạn cách liên kết các container , về cơ bản là giao tiếp giữa các container mà tôi đã nói.

PS: Nếu bạn làm -p, nhưng không EXPOSE, Docker sẽ ẩn EXPOSE. Điều này là do nếu một cổng được mở cho công chúng, nó cũng tự động mở cho các container Docker khác. Do đó -pbao gồm EXPOSE. Đó là lý do tại sao tôi không liệt kê nó ở trên như một trường hợp thứ tư.


57
Tôi nghĩ rằng bạn không đúng với EXPOSE. Từ các container khác, bạn có thể truy cập tất cả các cổng container mà không để lộ chúng. Tôi đã thử nó. Điều đáng chú ý ở đây là địa chỉ IP của container không thể đoán trước. Tôi tin rằng liên kết đó được sử dụng để chỉ định vùng chứa nào bạn muốn kết nối (vì vậy bạn liên kết với IP container cụ thể), không cho phép kết nối.
Jiri

7
"Nếu bạn không chỉ định bất kỳ của những", sẽ có ích nếu bạn làm sáng tỏ điều đó với "những" bạn có ý nghĩa EXPOSE-pvà không phải là ba điểm đạn tiền lệ. Có tôi bối rối ở đó một chút.
Pithikos

4
Để hoàn thành đầy đủ, câu trả lời này cũng sẽ giải quyết trường hợp thứ tư có thể xảy ra: bạn không chỉ định EXPOSE, nhưng bạn đã chỉ định -p. Theo hiểu biết của tôi rằng nếu bạn luôn sử dụng -pvà chạy các thùng chứa riêng lẻ thì EXPOSEcó thể bỏ qua, nhưng nó trở nên hữu ích / cần thiết khi sử dụng -Phoặc --link. (Và vì bạn không biết người khác sẽ sử dụng hình ảnh của bạn như thế nào, EXPOSEnên được chỉ định trong bất kỳ hình ảnh công khai nào.)
GrandOpener

6
Các tài liệu không còn nêu "Lệnh EXPOSE hiển thị các cổng để sử dụng trong các liên kết".
Lorin Hochstein

11
Downvote bởi vì điều này là không chính xác. Expose về cơ bản là tài liệu, và không sử dụng nó không hạn chế quyền truy cập. Đây là một sự hiểu lầm nguy hiểm nếu bất cứ ai dựa vào nó để hạn chế truy cập.
mc0e

167

Câu trả lời ngắn:

  • EXPOSElà một cách để làm tài liệu
  • --publish(hoặc -p) là một cách để lập bản đồ một cổng máy chủ để một chạy cảng container

Lưu ý bên dưới rằng:

  • EXPOSEcó liên quan đến Dockerfiles( tài liệu )
  • --publishcó liên quan đến docker run ...( thực thi / thời gian chạy )

Các cổng tiếp xúc và xuất bản

Trong mạng Docker, có hai cơ chế khác nhau liên quan trực tiếp đến các cổng mạng: phơi bày và xuất bản cổng. Điều này áp dụng cho mạng cầu mặc định và mạng cầu do người dùng xác định.

  • Bạn hiển thị các cổng bằng cách sử dụng EXPOSEtừ khóa trong Dockerfile hoặc --exposecờ để docker chạy. Các cổng tiếp xúc là một cách để ghi lại các cổng nào được sử dụng, nhưng thực tế không ánh xạ hoặc mở bất kỳ cổng nào . Các cổng tiếp xúc là tùy chọn.

  • Bạn xuất bản các cổng bằng cách sử dụng --publishhoặc --publish-allgắn cờ docker run. Điều này cho Docker biết cổng nào sẽ mở trên giao diện mạng của container. Khi một cổng được xuất bản, nó được ánh xạ tới một cổng thứ tự cao có sẵn (cao hơn 30000) trên máy chủ, trừ khi bạn chỉ định cổng để ánh xạ tới máy chủ trong thời gian chạy. Bạn không thể chỉ định cổng để ánh xạ tới máy chủ khi bạn xây dựng hình ảnh (trong Dockerfile), vì không có cách nào để đảm bảo rằng cổng sẽ có sẵn trên máy chủ nơi bạn chạy hình ảnh .

từ: Docker container mạng

Cập nhật tháng 10 năm 2019 : đoạn văn bản trên không còn trong tài liệu mà là phiên bản lưu trữ ở đây: docs.docker.com/v17.09/engine/userguide/networking/#exposeing-and-publishing-ports

Có thể tài liệu hiện tại là dưới đây:

Cổng xuất bản

Theo mặc định, khi bạn tạo một thùng chứa, nó không xuất bản bất kỳ cổng nào của nó ra thế giới bên ngoài. Để cung cấp một cổng có sẵn cho các dịch vụ bên ngoài Docker hoặc với các container Docker không được kết nối với mạng của bộ chứa, hãy sử dụng --publishhoặc -pgắn cờ. Điều này tạo ra một quy tắc tường lửa ánh xạ một cổng container tới một cổng trên máy chủ Docker.

và có thể được tìm thấy ở đây: docs.docker.com/config/containers/container-networking/#published-ports

Cũng thế,

LỘ RA

... EXPOSEHướng dẫn không thực sự xuất bản cổng . Nó có chức năng như một loại tài liệu giữa người xây dựng hình ảnh và người điều hành container, về những cổng nào được dự định xuất bản.

từ: Tham chiếu Dockerfile






Truy cập dịch vụ khi EXPOSE/ --publishkhông được xác định:

Tại câu trả lời của @Golo Roden, có ghi rằng ::

"Nếu bạn không chỉ định bất kỳ thứ nào trong số đó, dịch vụ trong container sẽ không thể truy cập được từ bất cứ đâu ngoại trừ từ bên trong chính container."

Có thể đó là trường hợp tại thời điểm câu trả lời được viết, nhưng bây giờ có vẻ như ngay cả khi bạn không sử dụng EXPOSEhoặc --publish, hostvà mạng khác containerscủa cùng một mạng sẽ có thể truy cập dịch vụ mà bạn có thể bắt đầu bên trong container đó.

Cách kiểm tra cái này:

Tôi đã sử dụng như sau Dockerfile. Về cơ bản, tôi bắt đầu với Ubuntu và cài đặt một máy chủ web nhỏ:

FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd

Tôi buildhình ảnh là "testexpose" và runmột thùng chứa mới với:

docker run --rm -it testexpose bash

Trong container, tôi khởi chạy một vài trường hợp mini-httpd:

root@fb8f7dd1322d:/# mini_httpd -p 80
root@fb8f7dd1322d:/# mini_httpd -p 8080
root@fb8f7dd1322d:/# mini_httpd -p 8090

Sau đó tôi có thể sử dụng curltừ máy chủ hoặc các thùng chứa khác để lấy trang chủ của mini-httpd.


16
đây là câu trả lời đúng câu trả lời được chấp nhận dựa trên các phiên bản trước, có vẻ như.
Luke W

cổng máy chủ bạn đã sử dụng cho curl là gì?
cơn bão não

Tôi đã sử dụng IP của container (một cái gì đó như 172.17.0.2) và tất cả các cổng tôi đang đề cập. Nếu bạn đang sử dụng Docker cho Mac / Windows, thì mạng sẽ khác. Không có docker0cầu.
tgogos

khi xuất bản tất cả các cổng EXPOSEd với cờ "-P", làm thế nào tôi có thể biết cổng nào được sử dụng trên máy chủ ??
Sixty4bit


9

Xem tài liệu tham khảo chính thức: https://docs.docker.com/engine/reference/builder/#expose

Việc EXPOSEcho phép bạn xác định các cổng riêng (container) và công cộng (máy chủ) để lộ tại thời điểm xây dựng hình ảnh khi container đang chạy nếu bạn chạy container -P.

$ docker help run
...
  -P, --publish-all                    Publish all exposed ports to random ports
...

Cổng công cộng và giao thức là tùy chọn, nếu không chỉ định một cổng công cộng, một cổng ngẫu nhiên sẽ được chọn trên máy chủ bởi docker để hiển thị cổng container được chỉ định trên Dockerfile.

Một pratice tốt là không chỉ định cổng công cộng, bởi vì nó chỉ giới hạn một container cho mỗi máy chủ (một container thứ hai sẽ ném một cổng đã được sử dụng).

Bạn có thể sử dụng -ptrong docker runkiểm soát những gì cổng công cảng container tiếp xúc sẽ là khả năng kết nối.

Dù sao, nếu bạn không sử dụng EXPOSE(với -Pkhi chạy docker) cũng không -p, sẽ không có cổng nào bị lộ.

Nếu bạn luôn sử dụng -ptại docker runbạn không cần EXPOSEnhưng nếu bạn sử dụng lệnh EXPOSEcủa bạn docker runcó thể đơn giản hơn, EXPOSEcó thể hữu ích nếu bạn không quan tâm cổng nào sẽ được hiển thị trên máy chủ hoặc nếu bạn chắc chắn chỉ có một container sẽ được tải.


chính xác. Khi bạn có EXPOSE portNumber trong Dockerfile, hãy nhớ gọi docker chạy với -P.
KunYu Tsai

6

Bạn hiển thị các cổng bằng cách sử dụng từ khóa EXPOSE trong Dockerfile hoặc cờ --expose để docker chạy. Các cổng tiếp xúc là một cách để ghi lại các cổng nào được sử dụng, nhưng thực tế không ánh xạ hoặc mở bất kỳ cổng nào. Các cổng tiếp xúc là tùy chọn.

Nguồn: cam kết của github


3

Hầu hết mọi người sử dụng docker soạn với các mạng. Các tài liệu nêu:

Tính năng mạng Docker hỗ trợ tạo mạng mà không cần lộ các cổng trong mạng, để biết thông tin chi tiết, hãy xem tổng quan về tính năng này).

Điều đó có nghĩa là nếu bạn sử dụng mạng để liên lạc giữa các container, bạn không cần phải lo lắng về việc lộ cổng.


-5

EXPOSE được sử dụng để ánh xạ cổng container cổng cục bộ, tức là: nếu bạn chỉ định phơi sáng trong tệp docker như

EXPOSE 8090

Nó sẽ làm gì để ánh xạ cổng localhost 8090 sang cổng container 8090

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.