เซิร์ฟเวอร์โหนด Containerized ไม่สามารถเข้าถึงได้ด้วย server.listen (พอร์ต '127.0.0.1')

ฉันตั้งค่าเซิร์ฟเวอร์โหนดอย่างง่ายใน Docker

นักเทียบท่าไฟล์

FROM node:latest
RUN apt-get -y update
ADD example.js .
EXPOSE 1337   
CMD node example.js

example.js

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n'+new Date);
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

ตอนนี้สร้างภาพ

$ docker build -t node_server .

ตอนนี้รันในคอนเทนเนอร์

$ docker run -p 1337:1337 -d node_server  
$ 5909e87302ab7520884060437e19ef543ffafc568419c04630abffe6ff731f70

ตรวจสอบว่าคอนเทนเนอร์กำลังทำงานอยู่และมีการแมปพอร์ต:

$ docker ps  

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
5909e87302ab        node_server         "/bin/sh -c 'node exa"   7 seconds ago       Up 6 seconds        0.0.0.0:1337->1337/tcp   grave_goldberg

ตอนนี้เรามาแนบไปกับคอนเทนเนอร์และตรวจสอบว่าเซิร์ฟเวอร์ทำงานอยู่ภายใน:

$ docker exec -it 5909e87302ab7520884060437e19ef543ffafc568419c04630abffe6ff731f70 /bin/bash 

และในประเภทบรรทัดคำสั่งคอนเทนเนอร์:

root@5909e87302ab:/# curl http://localhost:1337
Hello World
Mon Feb 15 2016 16:28:38 GMT+0000 (UTC)

ดูดีใช่มั้ยล่ะ?

ปัญหา

เมื่อฉันรันคำสั่ง curl เดียวกันบนโฮสต์ (หรือนำทางด้วยเบราว์เซอร์ของฉันไปที่ http://localhost:1337) ฉันไม่เห็นอะไรเลย

มีความคิดใดบ้างว่าทำไมการแมปพอร์ตระหว่างคอนเทนเนอร์และโฮสต์จึงไม่ทำงาน

สิ่งที่ฉันได้ลองไปแล้ว:

  • วิ่งด้วยธง --expose 1337

person Assaf Shomer    schedule 15.02.2016    source แหล่งที่มา
comment
คุณไม่ได้รันด้วย --expose คุณสร้างภาพด้วยคำสั่ง EXPOSE จากนั้น คุณเรียกใช้ด้วย --publish (หรือ -p) ดูคำตอบของฉันด้านล่าง   -  person VonC    schedule 15.02.2016


คำตอบ (2)


พอร์ตของคุณถูกเปิดเผยอย่างถูกต้อง แต่เซิร์ฟเวอร์ของคุณกำลังฟังการเชื่อมต่อบน 127.0.0.1 ภายในคอนเทนเนอร์ของคุณ:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n'+new Date);
}).listen(1337, '127.0.0.1');

คุณต้องเรียกใช้เซิร์ฟเวอร์ของคุณดังนี้:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n'+new Date);
}).listen(1337, '0.0.0.0');

สังเกต 0.0.0.0 แทน 127.0.0.1

person Chris McKinnel    schedule 15.02.2016
comment
การฟังบน 0.0.0.0 ดูแปลกมาก ไม่ชัดเจนในทันทีว่ามันหมายถึงอะไร ดูเหมือนว่าจะเป็นค่าเริ่มต้น ดังนั้นคุณจึงสามารถละเว้นอาร์กิวเมนต์นั้นได้จากฟังก์ชัน listen() ซึ่งฉันคิดว่า nodejs.org/api/ - person Davos; 11.11.2017
comment
การฟังบน 0.0.0.0 หมายถึงการฟังบนอินเทอร์เฟซทั้งหมด มันมักจะต้องใช้ความพยายามมากเกินไป บางครั้งก็เป็นปัญหาด้านความปลอดภัย แต่โดยทั่วไปแล้วก็ไม่เป็นอันตราย มันสมเหตุสมผลแล้วภายในคอนเทนเนอร์นักเทียบท่า - person Jim Stewart; 22.03.2018
comment
ขอบคุณมาก โซลูชันนี้จัดการปัญหากับเซิร์ฟเวอร์ทุกประเภทที่ทำงานภายใน Docker เช่น เซิร์ฟเวอร์ Express Java หรือ node.js อินเทอร์เฟซจะต้องอยู่ในทุกกรณี: 0.0.0.0 โดยที่พอร์ตนั้นเป็นพอร์ตที่กำลังส่งออกด้วยตัวเลือก -P $PORT:$PORT/tcp ดังนั้นโดยปกติแล้วเซิร์ฟเวอร์จะตรวจสอบ export HOST=0.0.0.0 ณ รันไทม์ - person loretoparisi; 04.04.2018
comment
ขอบคุณมากสำหรับสิ่งนี้ - ฉันใช้เวลาไม่รู้จบเพื่อแก้ไขปัญหานี้! - person readikus; 13.04.2020
comment
ขอบคุณมาก. ฉันมีปัญหาเดียวกัน แต่มี netty ซึ่งฉันไม่สามารถเข้าถึงได้จากภายนอกคอนเทนเนอร์ มีวิธีที่ดีกว่าในการทำความเข้าใจว่าคอนเทนเนอร์อินเทอร์เฟซเครือข่ายใดถูกผูกไว้ ดังนั้นจึงไม่ควรใช้ 0.0.0.0 - person matio; 22.11.2020
comment
สิ่งนี้ช่วยชีวิตฉันไว้! ฉันเพิ่งรู้ว่าไม่มีทางที่จะเผยแพร่พอร์ตของอินเทอร์เฟซ localhost ของคอนเทนเนอร์ได้อย่างชัดเจน กฎคือ --publish [ip:hostPort:containerPort | ip::containerPort | โฮสต์พอร์ต:คอนเทนเนอร์พอร์ต | คอนเทนเนอร์พอร์ต] - person dom free; 22.07.2021

การเพิ่ม EXPOSE 1337 ลงในไฟล์นักเทียบท่า

EXPOSE ถือเป็น บังคับ หากคุณต้องการ "เปิดเผย" "พอร์ตนั้นไปยังคอนเทนเนอร์อื่น

ตามความคิดเห็นของ BMitch:

Expose ไม่จำเป็นสำหรับการเผยแพร่พอร์ตหรือเชื่อมต่อคอนเทนเนอร์กับคอนเทนเนอร์ผ่านเครือข่ายนักเทียบท่าที่ใช้ร่วมกัน
เป็นข้อมูลเมตาสำหรับการเผยแพร่พอร์ตทั้งหมดด้วย -P และตรวจสอบรูปภาพ/คอนเทนเนอร์

So:

วิ่งด้วยธง --expose 1337

ไม่แน่ชัด: คุณต้อง นักเทียบท่าทำงาน กับ -p 1337:1337

คุณต้องการอย่างใดอย่างหนึ่ง:

  • สร้างภาพด้วยคำสั่ง EXPOSE (ใช้โดย -P)
  • หรือ รันด้วยพอร์ตที่เผยแพร่บนโฮสต์ -p 1337:1337

การทดสอบ curl http://localhost:1337 เสร็จสิ้นจากภายในคอนเทนเนอร์ (ไม่ EXPOSE หรือจำเป็นต้องเผยแพร่)
หากคุณต้องการให้มันทำงานจากโฮสต์ Linux คุณต้องมี EXPOSE+-P หรือ คุณต้องมี -p 1337:1337
อย่างใดอย่างหนึ่ง .

การประกาศว่าเปิดเผยเพียงอย่างเดียวเป็นสิ่งที่ดีสำหรับการบันทึกเจตนา แต่ไม่ได้ทำอะไรเพียงลำพัง

ตัวอย่างเช่น:

https://i.stack.imgur.com/wmKgd.png

ในรูปนั้น 8080 คือ EXPOSE'd ซึ่งเผยแพร่ไปยังโฮสต์ Linux 8888
และหากโฮสต์ Linux นั้นไม่ใช่โฮสต์จริง พอร์ตเดียวกันนั้นจะต้องส่งต่อไปยังโฮสต์จริงอย่างรวดเร็ว ดู "วิธีเข้าถึง Tomcat ที่ทำงานอยู่ใน Docker Container จากเบราว์เซอร์"

หาก localhost ไม่ทำงานจากโฮสต์ Linux ให้ลองใช้ที่อยู่ IP:

CID=$(docker run -p 1337:1337 -d node_server)
CIP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${CID})
curl http://${CIP}:1337

หรือตามที่กล่าวไว้ข้างต้น ทำให้เซิร์ฟเวอร์ของคุณรับฟังจากการเชื่อมต่อที่มาจาก IP ใด ๆ: 0.0.0.0 ซึ่งก็คือ ที่อยู่การออกอากาศหรือศูนย์ เครือข่าย.

person VonC    schedule 15.02.2016
comment
ขอบคุณสำหรับความคิดเห็น แต่อย่างที่ฉันได้กล่าวไว้ข้างต้น ฉันได้ลองเพิ่ม EXPOSE 1337 แล้ว แต่มันก็ใช้งานไม่ได้เช่นกัน - person Assaf Shomer; 15.02.2016
comment
@AssafShomer คุณต้องการทั้งสองอย่างนั่นคือคำตอบของฉันทั้งหมด - person VonC; 15.02.2016
comment
@AssafShomer ฉันได้แก้ไขคำตอบเพื่อให้ประเด็นนั้นชัดเจนยิ่งขึ้น - person VonC; 15.02.2016
comment
ขอบคุณแน่นอน ฉันลองทั้งสองอย่างแล้ว กล่าวคือ: สร้างด้วย EXPOSE 1337 และรันด้วย -p 1337:1337 แต่ก็ยังไม่มีอะไร ฉันเปลี่ยนคำถามเพื่อสะท้อนสิ่งนั้น - person Assaf Shomer; 15.02.2016
comment
@AssafShomer คุณอยู่บน Linux โดยตรงหรือคุณใช้นักเทียบท่าผ่าน boot2docker VM บน Windows หรือ Mac - person VonC; 15.02.2016
comment
บน Linux โดยตรง ไม่มี boot2docker ไม่มี Windows และไม่มี VM โลหะเปลือย :) (เกือบ) - person Assaf Shomer; 15.02.2016
comment
@AssafShomer คุณลองใช้ IP ของคอนเทนเนอร์เพื่อทำการทดสอบหรือไม่ (ฉันได้แก้ไขคำตอบแล้ว) - person VonC; 15.02.2016
comment
แล้วสวิตช์ docker run --expose ทำหน้าที่อะไร? เอกสารแจ้งว่า This exposes port ... of the container without publishing the port to the host system’s interfaces ซึ่งบอกเป็นนัยว่ามีอยู่ในอินเทอร์เฟซของคอนเทนเนอร์ หากคุณทราบที่อยู่นั้น docs.docker.com/engine/reference/commandline/run/ ดูเหมือนว่าจะมีประโยชน์หากคุณไม่ต้องการให้โฮสต์เปิดสิ่งเหล่านั้น พอร์ตลงในคอนเทนเนอร์ของคุณ - person Davos; 10.11.2017
comment
@Davos docker run --expose switch ทำอะไรได้บ้าง? : จะเปิดเผย ณ รันไทม์ (เพื่อให้คอนเทนเนอร์อื่นเห็น) พอร์ตที่ไม่ได้ถูกเปิดเผยในตอนแรกในอิมเมจ Dockerfile - person VonC; 10.11.2017
comment
ไม่จำเป็นต้องใช้ Expose เพื่อเผยแพร่พอร์ตหรือเชื่อมต่อคอนเทนเนอร์กับคอนเทนเนอร์ผ่านเครือข่ายนักเทียบท่าที่ใช้ร่วมกัน เป็นข้อมูลเมตาสำหรับการเผยแพร่พอร์ตทั้งหมดด้วย -P และตรวจสอบรูปภาพ/คอนเทนเนอร์ ไม่มีผลกระทบรันไทม์ที่ฉันเคยเห็น - person BMitch; 11.11.2017
comment
EXPOSE ใน Dockerfile นั้นไม่จำเป็นเลย มันทำหน้าที่เป็นเอกสารอย่างหมดจด เป็นความคิดที่ดีที่จะแสดงเจตนา แต่ก็ทำให้เข้าใจผิดเช่นกันเพราะไม่ได้ทำอะไรเลย อาจจะเป็นการแสดงความคิดเห็นก็ได้ - person Jim Stewart; 22.03.2018
comment
@จิมฉันเห็นด้วย อย่าลังเลที่จะแก้ไขคำตอบนี้และทำให้ประเด็นนั้นชัดเจนยิ่งขึ้น - person VonC; 22.03.2018