ฉันจะกำหนดการแม็พพอร์ตให้กับคอนเทนเนอร์ Docker ที่มีอยู่ได้อย่างไร


436

ฉันไม่แน่ใจว่าฉันเข้าใจผิดบางอย่างที่นี่ แต่ดูเหมือนว่าเป็นไปได้ที่จะตั้งค่าการแมปพอร์ตด้วยการสร้างคอนเทนเนอร์ใหม่จากรูปภาพ มีวิธีกำหนดการแมปพอร์ตให้กับคอนเทนเนอร์ Docker ที่มีอยู่หรือไม่


3
การใช้ iptables อาจทำงานได้เหมือนคำตอบนี้การเปิดเผยพอร์ตบนคอนเทนเนอร์ Docker สด
Choldrim

2
ฉันสงสัยว่านี่คือจากการออกแบบ นักเทียบท่าพยายามบังคับให้คุณ "ทำซ้ำ" และคอนเทนเนอร์เป็นระบบบันทึก "ประเภท" ทุกสิ่งที่คุณทำตามขั้นตอนที่ไม่ส่งผลกระทบต่อคอนเทนเนอร์จะเป็นขั้นตอนที่ทำด้วยมืออย่างง่ายดาย กล่าวอีกวิธีหนึ่ง: คุณต้องการให้คอนเทนเนอร์ของคุณเป็นตัวแทนของการกำหนดค่าทั้งหมดที่จำเป็นในการใช้งาน ดังนั้นหากคุณต้องการเปิดพอร์ตใหม่คุณต้องสร้างคอนเทนเนอร์ใหม่
แลนซ์ใจดี

2
คำถามเก่าและฉันไม่ได้ตอบคำถาม แต่ฉันอยากจะบอกว่าบางทีคุณและผู้คนที่ยกระดับคำถามและคำตอบนี้อาจเข้าใจผิดแนวคิดของนักเทียบท่าอย่างสมบูรณ์ นักเทียบท่าใช้สำหรับแอปพลิเคชั่นไร้สัญชาติที่สามารถเพิ่มหรือลดขนาดได้หลายครั้ง คุณไม่ควรคงอยู่สิ่งใดในคอนเทนเนอร์สำหรับสภาพแวดล้อมการผลิตที่ไม่สามารถสร้างใหม่ได้หากคุณต้องการคงอยู่ให้แมปไดเรกทอรี นักเทียบท่าไม่ใช่สิ่งที่ "light vm" บางทีสิ่งที่คุณกำลังมองหาคือ linuxcontainers.org, lxd ขึ้นอยู่กับแนวคิดของนักเทียบท่า แต่ด้วย "light vm" ในใจ
Edgar Carvalho

ในกรณีนี้อาจช่วยได้เป็นไปได้ที่จะใช้เครื่องมือ "Kitematic" เพื่อเพิ่มการแมปพอร์ตไปยังคอนเทนเนอร์ที่ใช้งานอยู่ นี่ควรหมายความว่าต้องมีคำสั่ง docker เพื่อทำสิ่งเดียวกัน แต่ด้วย googling เล็กน้อย :) ขอให้โชคดี
Yaffah

คำตอบ:


298

คุณสามารถเปลี่ยนการแมปพอร์ตได้โดยแก้ไขhostconfig.jsonไฟล์โดยตรงที่ /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

คุณสามารถกำหนด [hash_of_the_container] ผ่านdocker inspect <container_name>คำสั่งและค่าของฟิลด์ "Id" คือแฮช

1) stop the container 
2) stop docker service (per Tacsiazuma's comment)
3) change the file
4) restart your docker engine (to flush/clear config caches)
5) start the container

ดังนั้นคุณไม่จำเป็นต้องสร้างภาพด้วยวิธีนี้ คุณยังสามารถเปลี่ยนการตั้งค่าสถานะเริ่มต้นใหม่ได้ที่นี่

PS คุณสามารถเยี่ยมชมhttps://docs.docker.com/engine/admin/เพื่อเรียนรู้วิธีรีสตาร์ทเอ็นจิ้นนักเทียบท่าอย่างถูกต้องตามเครื่องโฮสต์ของคุณ ฉันเคยsudo systemctl restart dockerรีสตาร์ทเครื่องยนต์นักเทียบท่าที่ใช้งาน Ubuntu 16.04


17
เมื่อนักเทียบท่าหยุดดูเหมือนว่าจะเขียนทับการเปลี่ยนแปลงของคุณดังนั้น 2. หยุดนักเทียบท่า, 3. ไฟล์การเปลี่ยนแปลง, 4. เริ่มเครื่องมือนักเทียบท่า
Tacsiazuma

5
ฉันลองข้างต้นแล้วใช้งานได้ ดูรายละเอียดเพิ่มเติมได้ที่: mybrainimage.wordpress.com/2017/02/05/…
rohitmohta

11
สิ่งสำคัญคือการหยุดตู้คอนเทนเนอร์หยุดเครื่องยนต์นักเทียบท่าและเปลี่ยนทั้งสองhostconfig.jsonและconfig.v2.jsonเพื่อให้งานนี้ ใช้ลิงก์ที่ให้บริการโดย @rohitmohta เพื่อดูรายละเอียด
Kalpak Gadre

5
ทำงานได้ดีสำหรับฉันเพียงใช้อย่างเดียวหากใช้แอป docker บน mac ทำตามคำแนะนำที่นี่เพื่อไปที่โฟลเดอร์ / var / lib / docker / container: stackoverflow.com/a/41226917/2048266โดยทั่วไปทำงานscreen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/ttyเมื่อคุณได้รับ tty ที่ทำงานอยู่คุณสามารถ นำทางไปยัง / var / lib /
docker

14
สำหรับ windows มีใครบ้างที่สามารถแบ่งปันตำแหน่งที่ตั้งของโฟลเดอร์ conatiners ให้ฉันได้ไหม?
วีเจย์

463

ฉันยังสนใจในปัญหานี้

เช่น @Thasmoกล่าว forwardings พอร์ตสามารถระบุเฉพาะกับdocker run(และdocker create) คำสั่ง
คำสั่งอื่น ๆdocker startไม่มี-pตัวเลือกและdocker portแสดงเฉพาะการส่งต่อปัจจุบัน

ในการเพิ่มการส่งต่อพอร์ตฉันทำตามขั้นตอนเหล่านี้เสมอ

  1. หยุดเรียกใช้คอนเทนเนอร์

    docker stop test01
    
  2. กระทำภาชนะ

    docker commit test01 test02
    

    บันทึก:ข้างต้นtest02เป็นภาพใหม่ที่ฉันสร้างขึ้นจากtest01ภาชนะ

  3. อีกครั้งเรียกใช้จากภาพที่ตกลงไว้

    docker run -p 8080:8080 -td test02
    

โดยที่ 8080 ตัวแรกเป็นพอร์ตภายในเครื่องและ 8080 ตัวที่สองคือพอร์ตคอนเทนเนอร์


15
ถ้าฉันต้องการเก็บชื่อ test01 ไว้ล่ะ?
user69715

12
ใครรู้ว่ามีปัญหาเปิดให้เทียบกับ Docker เพื่อให้สเปคพอร์ต (- เผยแพร่) ด้วยdocker start?
Elijah Lynn

8
และเกิดอะไรขึ้นกับไดรฟ์ข้อมูลในสถานการณ์นี้
Andrew Savinykh

78
นี่เป็นวิธีการแก้ปัญหาที่แย่มากฉันไม่รู้ว่าจะจัดการหา upvotes ได้ 250 คะแนนอย่างไร บางทีผู้ที่ upvoted ไม่ทราบว่าวิธีนี้ทำให้เกิดปัญหา ใช่มันแย่มากและเท่ากับการเริ่มต้นคอนเทนเนอร์ใหม่ที่ทำงานบนพอร์ตอื่น
Arrrr

25
@Arrrr บางทีคุณต้องการที่จะออกคำตอบที่ดีกว่า? ฉันแน่ใจว่าเราทุกคนยินดีถ้าคุณบอกเราถึงวิธีที่ดีกว่าในการทำเช่นนี้
crockeea

40

หากโดย "มีอยู่" คุณหมายถึง "กำลังทำงาน" แสดงว่าเป็นไปไม่ได้ที่จะเพิ่มการแมปพอร์ต (ในปัจจุบัน)

อย่างไรก็ตามคุณสามารถเพิ่มอินเทอร์เฟซเครือข่ายใหม่ด้วยเช่นPipeworkหากคุณจำเป็นต้องเปิดเผยบริการในภาชนะที่ใช้งานอยู่โดยไม่ต้องหยุด / เริ่มต้นใหม่


4
นี่ควรเป็นคำตอบที่ดีที่สุด รวบรัดและตอบคำถามของ OP ซึ่งไม่มีคนอื่นทำ! บางครั้งผลลัพธ์ที่เป็นลบก็เป็นผล!
เมฆบางส่วน

19

ไม่แน่ใจว่าคุณสามารถใช้การแมปพอร์ตกับคอนเทนเนอร์ที่รันอยู่หรือไม่ คุณสามารถใช้การส่งต่อพอร์ตในขณะที่เรียกใช้คอนเทนเนอร์ที่แตกต่างจากการสร้างคอนเทนเนอร์ใหม่

$ docker run -p <public_port>:<private_port> -d <image>  

จะเริ่มเรียกใช้คอนเทนเนอร์ บทช่วยสอนนี้อธิบายการเปลี่ยนเส้นทางพอร์ต


2
ใช่ดังนั้นจึงเป็นไปได้ที่จะตั้งค่าตัวเลือกเช่นการจับคู่พอร์ตที่การสร้างคอนเทนเนอร์
thasmo

20
FYI คำตอบนี้ไม่ถูกต้องทั้งหมด docker runสร้างและเริ่มคอนเทนเนอร์ใหม่ มันเทียบเท่ากับการทำตามด้วยdocker create docker start
Trevor Sullivan

19

การแก้ไขhostconfig.jsonดูเหมือนจะไม่ทำงานในขณะนี้ มันจะจบลงด้วยพอร์ตที่ถูกเปิดเผย แต่ไม่ได้เผยแพร่ไปยังโฮสต์ การผูกมัดและสร้างตู้คอนเทนเนอร์นั้นไม่ใช่วิธีที่ดีที่สุดสำหรับฉัน ไม่มีใครพูดถึงdocker network ?

ทางออกที่ดีที่สุดคือการใช้ reverse proxy ภายในเครือข่ายเดียวกัน

  1. สร้างเครือข่ายใหม่หากคอนเทนเนอร์ก่อนหน้าของคุณไม่ได้อยู่ในเครือข่ายที่มีชื่อ

    docker network create my_network

  2. เข้าร่วมคอนเทนเนอร์ที่มีอยู่ของคุณไปยังเครือข่ายที่สร้างขึ้น

    docker network connect my_network my_existing_container

  3. เริ่มบริการพร็อกซีย้อนกลับ (เช่น nginx) เผยแพร่พอร์ตที่คุณต้องการเข้าร่วมเครือข่ายเดียวกัน

    docker run -d --name nginx --network my_network -p 9000:9000 nginx

    เลือกที่จะลบ default.confใน nginx

    docker exec nginx rm /etc/nginx/conf.d/default.conf

  4. สร้างการกำหนดค่า nginx ใหม่

    server
    {
        listen 9000;
    
        location / {
            proxy_pass http://my_existing_container:9000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    

    คัดลอกการกำหนดค่าไปยังคอนเทนเนอร์ nginx

    docker cp ./my_conf.conf nginx:/etc/nginx/conf.d/my_conf.conf

  5. รีสตาร์ท nginx

    docker restart nginx

ข้อดี : เพื่อเผยแพร่พอร์ตใหม่คุณสามารถหยุด / อัปเดต / สร้างคอนเทนเนอร์ nginx ได้อย่างปลอดภัยตามที่คุณต้องการโดยไม่ต้องแตะที่คอนเทนเนอร์ของธุรกิจ หากคุณต้องการเวลาที่ไม่เป็นศูนย์สำหรับ nginx เป็นไปได้ที่จะเพิ่มบริการพร็อกซีย้อนกลับเพิ่มเติมเข้าร่วมเครือข่ายเดียวกัน นอกจากนี้คอนเทนเนอร์สามารถเข้าร่วมเครือข่ายมากกว่าหนึ่งเครือข่าย

แก้ไข:

หากต้องการย้อนกลับบริการที่ไม่ใช่ HTTP พร็อกซีไฟล์กำหนดค่าจะแตกต่างกันเล็กน้อย นี่คือตัวอย่างง่ายๆ:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}

1
มันน่าทึ่งและใช้งานได้จริง แต่สำหรับระบบองค์กรวิธีนี้ดูเหมือนว่าจะทำให้งงงวย เป็นการดีกว่ามากหากปล่อยให้ระบบเดียวควบคุมเวิร์กโฟลว์
Afshin

1
@Ashshin สำหรับระบบองค์กรหรือโครงการฉันคิดว่าวิธีนี้ดีกว่าการสร้างใหม่ (สาเหตุของเวลาที่หยุดทำงาน) หรือการแฮ็คไฟล์ hostconfig.json (อย่างน้อยก็ไม่ได้แนะนำอย่างเป็นทางการ) คอนเทนเนอร์พิเศษจะเปิดเผยพอร์ตภายในของคอนเทนเนอร์ธุรกิจของคุณแทนที่จะทำการเปลี่ยนแปลงใด ๆ
Sean C.

1
วิธีการที่ยอดเยี่ยม ฉันต้องการกำหนดค่า nginx แตกต่างกันเพื่อให้คอนเทนเนอร์ของฉันทำงานหลังพร็อกซี แต่ดูเหมือนว่าวิธีที่ถูกต้องในการทำสิ่งต่าง ๆ ใช้งานได้สำหรับการปรับใช้สีน้ำเงิน - เขียวด้วย
Brooks DuBois

18

ในตัวอย่างของ Fujimoto Youichi test01เป็นที่เก็บของtest02เป็นรูปภาพ

ก่อนที่จะทำdocker runคุณสามารถลบคอนเทนเนอร์เดิมจากนั้นกำหนดชื่อคอนเทนเนอร์อีกครั้ง:

$ docker stop container01
$ docker commit container01 image01
$ docker rm container01
$ docker run -d -P --name container01 image01

(การใช้-Pเพื่อแสดงพอร์ตไปยังพอร์ตสุ่มแทนที่จะกำหนดด้วยตนเอง)


12
โปรดระวัง คุณจะสูญเสียข้อมูลทั้งหมดของคุณขึ้นอยู่กับแอปพลิเคชันภายใน
Barry

14

ถ้าคุณวิ่ง docker run <NAME>มันจะวางไข่ภาพใหม่ซึ่งน่าจะไม่ใช่สิ่งที่คุณต้องการ

หากคุณต้องการเปลี่ยนภาพปัจจุบันให้ทำดังต่อไปนี้:

docker ps -a

ใช้รหัสของภาชนะเป้าหมายของคุณและไปที่:

cd /var/lib/docker/containers/<conainerID><and then some:)>

หยุดภาชนะ:

docker stop <NAME>

เปลี่ยนไฟล์

vi config.v2.json

"Config": {
    ....
    "ExposedPorts": {
        "80/tcp": {},
        "8888/tcp": {}
    },
    ....
},
"NetworkSettings": {
....
"Ports": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],

และเปลี่ยนไฟล์

vi hostconfig.json

"PortBindings": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],
     "8888/tcp": [
         {
             "HostIp": "",
             "HostPort": "8888"
         } 
     ]
 }

รีสตาร์ทนักเทียบท่าของคุณและควรใช้งานได้


2
สิ่งนี้ไม่ได้ผลสำหรับฉันใน Docker รุ่น 17.09.0-ce หลังจากที่ฉันเริ่มต้นไฟล์กำหนดค่าคอนเทนเนอร์ได้ถูกเขียนทับกลับไปเป็นค่าเก่า
thegeko

3
รีสตาร์ทบริการตัวเทียบท่าในระบบโฮสต์ @thegeko
yurenchen

1
ใช้งานได้! TKS! 1. หยุดคอนเทนเนอร์ 2. เปลี่ยนไฟล์ 3. เริ่มต้นเทียบท่า 4. เริ่มต้นคอนเทนเนอร์กลับ
datdinhquoc

12

วิธีอื่น ๆ รอบตัวคุณถ้าคุณไม่พอใจกับการกำหนดค่าความลึกของ Docker IPtables จะเป็นเพื่อนของคุณ

iptables -t nat -A DOCKER -p tcp --dport ${YOURPORT} -j DNAT --to-destination ${CONTAINERIP}:${YOURPORT}

iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source ${CONTAINERIP} --destination ${CONTAINERIP} --dport ${YOURPORT}

iptables -A DOCKER -j ACCEPT -p tcp --destination ${CONTAINERIP} --dport ${YOURPORT}

นี่เป็นเพียงกลลวงไม่ใช่วิธีที่แนะนำกับสถานการณ์ของฉันเพราะฉันไม่สามารถหยุดภาชนะได้ฉันหวังว่าจะช่วยคุณได้เช่นกัน


นี่เป็นคำตอบที่ยอดเยี่ยม! ขอบคุณ! ถ้าฉันต้องการแมปDOCKER_PORTไปยังMACHINE_PORTส่วนใดที่ควรจะเปลี่ยน?
Ciprian Tomoiagă

หมายเหตุนักเทียบท่าจะไม่ทราบเกี่ยวกับการเพิ่มคู่มือนี้ รายการ SO จะไม่ถูกลบออกเมื่อคุณเริ่มบริการในภายหลังด้วยตัวเชื่อมต่อที่เปิดเผยพอร์ตอย่างถูกต้อง ดังนั้นเมื่อมีสิ่งใดเปลี่ยนแปลงตรวจสอบ iptables อย่างระมัดระวัง ค้นหารายการที่ซ้ำกันโดยเฉพาะ!
anthony

8

เราใช้เครื่องมือที่มีประโยชน์เช่น ssh เพื่อให้บรรลุสิ่งนี้ได้อย่างง่ายดาย

ฉันใช้อูบุนตูโฮสต์และอิมเมจจาก docker

  1. Inside docker ได้ติดตั้ง openssh-client ไว้
  2. Outside docker (host) ติดตั้ง openssh-server server ไว้

เมื่อจำเป็นต้องทำการแมปพอร์ตใหม่

ภายใน docker ให้รันคำสั่งต่อไปนี้

ssh -R8888:localhost:8888 <username>@172.17.0.1

172.17.0.1 เป็น ip ของส่วนต่อประสานนักเชื่อมต่อ (คุณสามารถรับสิ่งนี้ได้จากการทำงาน ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "บนโฮสต์)

ที่นี่ฉันมีพอร์ต 8888 ในเครื่องที่แมปกลับไปยังโฮสต์ 8888 คุณสามารถเปลี่ยนพอร์ตได้ตามต้องการ

หากคุณต้องการพอร์ตเพิ่มอีกหนึ่งพอร์ตคุณสามารถฆ่า ssh และเพิ่มหนึ่งบรรทัดของ -R ไปยังพอร์ตใหม่ด้วยพอร์ตใหม่

ฉันได้ทดสอบสิ่งนี้กับ netcat


2
  1. หยุดเครื่องยนต์นักเทียบท่าและที่เก็บ
  2. ไปที่/var/lib/docker/containers/${container_id}ไดเรกทอรีและแก้ไขhostconfig.json
  3. แก้ไขPortBindings.HostPortที่คุณต้องการเปลี่ยนแปลง
  4. สตาร์ทเครื่องยนต์นักเทียบท่าและตู้คอนเทนเนอร์

-1

สำหรับผู้ใช้ Windows & Mac มีวิธีอื่นที่ง่ายและเป็นมิตรในการเปลี่ยนพอร์ตการทำแผนที่:

  1. ดาวน์โหลด kitematic

  2. ไปที่หน้าการตั้งค่าของคอนเทนเนอร์บนแท็บพอร์ตคุณสามารถแก้ไขพอร์ตที่เผยแพร่ได้โดยตรง

  3. เริ่มภาชนะอีกครั้ง


2
ฉันลองวิธีนี้ จลนศาสตร์ใช้การแมปพอร์ตแน่นอน อย่างไรก็ตามเมื่อต้องการใช้มันจะสร้างคอนเทนเนอร์ของฉันขึ้นใหม่จากภาพต้นฉบับ ดังนั้นหากคุณกลัวว่าจะสูญเสียการเปลี่ยนแปลงที่เกิดขึ้นในตัวคอนเทนเนอร์อย่าใช้วิธีนี้
VeganHunter

1
ฉันชอบสิ่งนี้ฉันเข้าใจว่าไม่ได้ตอบคำถามและสร้างตู้คอนเทนเนอร์ใหม่ แต่อย่างน้อยก็ใช้งานได้และผลลัพธ์ SO นี้ปรากฏขึ้นระหว่างการค้นหาของฉัน +1
2b77bee6-5445-4c77-b1eb-4df3e5

-7

คำตอบสั้น ๆ : คุณไม่สามารถกำหนดการจับคู่พอร์ตให้กับคอนเทนเนอร์ Docker ที่มีอยู่ได้

คุณต้องมีคอนเทนเนอร์ใหม่ ... จัดการกับมัน


4
ไม่จำเป็นต้องมีทัศนคติ อีกทั้งคำตอบนี้ยังขาดรายละเอียดอย่างสมบูรณ์
lovefaithswing

1
ไม่ต้องการรายละเอียด น้ำเสียงมีความสำคัญต่อการถ่ายทอดคำตอบที่ประหยัดเวลานี้และลักษณะที่ไม่ยั่งยืนของภาชนะบรรจุ
stephen

-11

หากคุณเพียงต้องการเปลี่ยนพอร์ตของคอนเทนเนอร์ที่ใช้งานอยู่คุณจะต้อง:

  1. หยุดภาชนะที่มีอยู่

    sudo docker หยุด NAME

  2. ตอนนี้เริ่มต้นใหม่ด้วยการจับคู่พอร์ตใหม่

    sudo docker run -d -p 81:80 NAME

ที่ไหน:

"-d" เป็นพื้นหลัง / deamon the docker

"-p" เปิดใช้งานการแมปพอร์ต

พอร์ต "81" ภายนอก (เปิดเผย) ที่คุณใช้เพื่อเข้าถึงด้วยเบราว์เซอร์ของคุณ

คอนเทนเนอร์นักเทียบท่าภายใน "80" ฟังพอร์ต


4
นี่เป็นเพียงความผิด ในdocker runคำสั่งNAMEคือชื่อของอิมเมจเพื่อรันคอนเทนเนอร์ในขณะที่ในdocker stopการNAMEอ้างถึงชื่อของคอนเทนเนอร์ที่จะหยุด
jonatan

1
"นักเทียบท่าวิ่ง" จะสร้างที่เก็บใหม่ ไม่สามารถใช้ชื่อคอนเทนเนอร์เดียวกับชื่อที่หยุดทำงานเนื่องจากคุณสามารถมีคอนเทนเนอร์หนึ่งที่มีชื่อนั้นเท่านั้น ดังนั้นคุณต้องทำ: "นักเทียบท่าหยุด NAME", นักเทียบท่า container rm NAME จากนั้น "นักเทียบท่าเรียกใช้ -d -p 81:80 NAME" ตามที่คุณเขียน
แลนซ์ใจดี
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.