ให้ฉันเริ่มต้นด้วยคำสัญญาที่ยิ่งใหญ่ คุณจะรักบทความนี้อย่างแน่นอนในวันนี้ มันจะยาว มีรายละเอียดและมีประโยชน์มาก คิดว่าด้วง GRUB2 สิ่งเดียวกันที่นี่ มีเพียงเราเท่านั้นที่จะจัดการกับ Docker ซึ่งเป็นแพลตฟอร์มการกระจายที่ดีที่รวมเทคโนโลยี Linux Containers (LXC) ไว้ในวิธีที่ง่ายและสะดวก
ฉันจะแสดงวิธีเริ่มต้น จากนั้นเราจะสร้างคอนเทนเนอร์ของเราเองด้วย SSH และ Apache เรียนรู้วิธีใช้ Dockerfiles เปิดเผยพอร์ตบริการ และแก้ไขข้อบกพร่องและปัญหาเล็กน้อยจำนวนมหาศาลที่ปกติไม่เคยได้รับการกล่าวถึงในฟอรัมสาธารณะ . โปรดติดตามฉันโดยไม่ต้องกังวลใจอีกต่อไป
สารบัญ
- บทนำ
- การใช้งานนักเทียบท่า
- เริ่มต้นใช้งาน
- คำสั่งนักเทียบท่า
- ดึงรูปภาพ
- เริ่มคอนเทนเนอร์ Docker
- ติดตั้ง Apache &SSH
- เริ่มให้บริการ
- บริการ Apache
- บริการ SSH
- ตรวจสอบว่าเว็บเซิร์ฟเวอร์เปิดอยู่หรือไม่
- เปิดเผยพอร์ตขาเข้า
- ตรวจสอบที่อยู่ IP
- กำลังทดสอบการกำหนดค่าใหม่
- ตรวจสอบว่า SSH ใช้งานได้หรือไม่
- เดี๋ยวก่อน รหัสผ่านรูทคืออะไร?
- คอมมิตอิมเมจ
- ไฟล์นักเทียบท่า
- สร้างภาพ
- ภาพทดสอบ
- การสร้างทางเลือก
- คำสั่ง COPY
- ข้อดีของคอนเทนเนอร์
- ปัญหาที่คุณอาจพบ &การแก้ไขปัญหา
- คำสั่งเพิ่มเติม
- ความแตกต่างระหว่าง exec และแนบ
- ความแตกต่างระหว่างการเริ่มต้นและการเรียกใช้
- ความแตกต่างระหว่างการสร้างและการสร้าง
- นี่เป็นเพียงจุดเริ่มต้น ...
- อ่านเพิ่มเติม
- สรุป
บทนำ
ฉันได้ให้ภาพรวมโดยย่อของเทคโนโลยีในบทความฟรีแวร์ของ Gizmo เมื่อช่วงปีที่แล้ว ตอนนี้เราจะจริงจังกับการใช้ Docker ประการแรก สิ่งสำคัญคือต้องจำไว้ว่าเฟรมเวิร์กนี้ช่วยให้คุณใช้ LXC ในลักษณะที่สะดวก โดยไม่ต้องกังวลเกี่ยวกับรายละเอียดเล็กน้อยทั้งหมด มันคือก้าวต่อไปของโลกนี้ เช่นเดียวกับ OpenStack ที่เป็นก้าวต่อไปของวิวัฒนาการในโลกเวอร์ช่วลไลเซชั่น ให้ฉันให้ประวัติและการเปรียบเทียบแก่คุณ
การจำลองเสมือนเริ่มต้นด้วยซอฟต์แวร์ที่ให้คุณทำให้ฮาร์ดแวร์ของคุณเป็นนามธรรม จากนั้น เพื่อทำให้สิ่งต่าง ๆ เร็วขึ้น โปรแกรมเวอร์ชวลไลเซชันเริ่มใช้การเร่งด้วยฮาร์ดแวร์ จากนั้นคุณก็ได้รับ ในท้ายที่สุด ไฮเปอร์ไวเซอร์เริ่มผุดขึ้นราวกับดอกเห็ดหลังฝนตก และค่อนข้างยากที่จะจัดเตรียมและจัดการทั้งหมด นี่คือเหตุผลหลักสำหรับแนวคิดเช่น OpenStack ซึ่งซ่อนแพลตฟอร์มต่างๆ ภายใต้ API แบบรวม
ตู้คอนเทนเนอร์เริ่มดำเนินการในลักษณะเดียวกัน อย่างแรก เรามี chroot แต่กระบวนการที่ทำงานในสภาพแวดล้อมที่ถูกคุมขังใช้เนมสเปซเดียวกันและต่อสู้เพื่อทรัพยากรเดียวกัน จากนั้น เราได้รับการเรียกระบบ kexec ซึ่งช่วยให้เราบูตเข้าสู่บริบทของเคอร์เนลอื่นโดยไม่ต้องผ่าน BIOS จากนั้นกลุ่มควบคุมก็เข้ามา ทำให้เราสามารถแบ่งทรัพยากรระบบ เช่น CPU หน่วยความจำ และอื่นๆ ออกเป็นกลุ่มย่อยได้ จึงทำให้สามารถควบคุมได้ดีขึ้น ด้วยเหตุนี้จึงเป็นที่มาของชื่อกระบวนการที่ทำงานบนระบบ
ต่อมา เคอร์เนลของลีนุกซ์เริ่มเสนอการแยกทรัพยากรอย่างเต็มรูปแบบ โดยใช้ cgroups เป็นกลไกการแบ่งพาร์ติชันพื้นฐาน ในทางเทคนิคแล้ว นี่คือเทคโนโลยีเวอร์ชวลไลเซชันระดับระบบ ซึ่งช่วยให้คุณสามารถเรียกใช้เคอร์เนลที่กำลังรันได้หลายอินสแตนซ์ที่ด้านบนของโฮสต์ควบคุมภายในสภาพแวดล้อมแบบปิดตัวเอง โดยมีโบนัสเพิ่มเติมคือการปรับลดประสิทธิภาพและโอเวอร์เฮดเพียงเล็กน้อย
เทคโนโลยีที่แข่งขันกันหลายรายการพยายามเสนอโซลูชันที่คล้ายคลึงกัน เช่น OpenVZ แต่ในที่สุดชุมชนก็จำกัดการโฟกัสไปที่การเปิดใช้งานแบบเนทีฟภายในเคอร์เนลเมนไลน์ให้แคบลง และนี่ดูเหมือนจะเป็นทิศทางในอนาคต ถึงกระนั้น LXC ยังคงใช้งานค่อนข้างยาก เนื่องจากจำเป็นต้องมีความรู้ด้านเทคนิคและการเขียนสคริปต์พอสมควรเพื่อให้คอนเทนเนอร์ทำงาน
นี่คือที่มาของ Docker มันพยายามกำจัดชิ้นส่วนที่หยาบกร้านออกไปและนำเสนอวิธีการง่ายๆ ในการวางไข่อินสแตนซ์คอนเทนเนอร์ใหม่โดยไม่ต้องกังวลเกี่ยวกับแบ็กเอนด์ของโครงสร้างพื้นฐาน เกือบแล้ว แต่ระดับความยากจะน้อยกว่ามาก
ข้อดีอีกอย่างของ Docker คือการยอมรับจากชุมชนอย่างกว้างขวาง เช่นเดียวกับการเน้นที่การผสานรวมกับบริการคลาวด์ เรามาพูดถึงคำศัพท์แบบเต็ม ซึ่งหมายถึงการตั้งชื่อผู้เล่นรายใหญ่บางราย เช่น AWS, Hadoop, Azure, Jenkins และอื่นๆ จากนั้นเรายังสามารถพูดคุยเกี่ยวกับ Platform as a Service (Paas) และคุณสามารถจินตนาการได้ว่าเงินและการมุ่งเน้นนี้จะได้รับเท่าใดในปีต่อ ๆ ไป ภูมิทัศน์ทางเทคโนโลยีมีขนาดใหญ่และสับสน และแน่นอนว่าจะต้องเปลี่ยนแปลงและพัฒนาต่อไป ด้วยแนวคิดและเทคโนโลยี wrapper ที่มากขึ้นเรื่อย ๆ เข้ามาในชีวิตและสร้างต่อยอดจาก Docker
แต่เราต้องการมุ่งเน้นไปที่ด้านเทคโนโลยี เมื่อเราเชี่ยวชาญพื้นฐานแล้ว เราจะค่อยๆ ขยายและเริ่มใช้ความสามารถในการผสานรวมที่แข็งแกร่ง ความยืดหยุ่นของโซลูชัน และทำงานเพื่อทำให้ความเชี่ยวชาญในระบบนิเวศระบบคลาวด์ของเรามีความหลากหลาย เป็นอัตโนมัติและบริสุทธิ์ สิ่งนั้นจะไม่เกิดขึ้นในตอนนี้ แต่ฉันต้องการช่วยคุณนำทางในช่วง 2-3 ไมล์แรก หรือเรียกว่ากิโลเมตรของน้ำเริ่มต้นที่ขุ่นมัว เพื่อให้คุณสามารถเริ่มใช้ Docker ได้อย่างสมเหตุสมผลและมีประสิทธิภาพ เนื่องจากเป็นเทคโนโลยีใหม่ จึงอยู่ใน Wild West และเอกสารออนไลน์ เคล็ดลับ บทช่วยสอน และสิ่งที่ไม่ทันสมัยส่วนใหญ่ เวอร์ชันคัดลอกและวางที่ไม่ช่วยใครเลย และส่วนใหญ่ไม่สมบูรณ์ ฉันต้องการแก้ไขสิ่งนั้นในวันนี้
การใช้งานนักเทียบท่า
สิ่งที่น่าเบื่อมากกว่านี้ก่อนที่เราจะทำสิ่งดีๆ อย่างไรก็ตาม Docker ส่วนใหญ่เกี่ยวกับ LXC แต่ไม่ใช่แค่เท่านั้น ได้รับการออกแบบมาให้สามารถขยายได้ และยังสามารถเชื่อมต่อกับ libvirt และ systemd ในทางหนึ่ง สิ่งนี้ทำให้เกือบจะเหมือนกับไฮเปอร์ไวเซอร์เนื่องจากมีศักยภาพสำหรับการเติบโตในอนาคต และเมื่อมีการเพิ่มโมดูลเพิ่มเติม มันสามารถแทนที่ไฮเปอร์ไวเซอร์แบบคลาสสิกอย่าง Xen หรือ KVM หรืออะไรก็ตามที่ใช้ libvirt และเพื่อนได้อย่างมีประสิทธิภาพ
นี่เป็นภาพสาธารณสมบัติ หากคุณสงสัย
เริ่มต้นใช้งาน
เราจะสาธิตการใช้ CentOS 7 ไม่ใช่ Ubuntu เนื้อหาออนไลน์ส่วนใหญ่มุ่งเน้นไปที่ Ubuntu แต่ฉันต้องการแสดงให้คุณเห็นว่ามันทำได้อย่างไรโดยใช้ Linux ที่ใกล้เคียงกับระดับองค์กรมากที่สุดเท่าที่จะเป็นไปได้ เพราะถ้าคุณจะใช้ Docker มันจะเป็นธุรกิจที่ชอบ สิ่งแรกคือการติดตั้งนักเทียบท่า:
ยำติดตั้ง docker-io
เมื่อติดตั้งซอฟต์แวร์แล้ว คุณสามารถเริ่มใช้งานได้ อย่างไรก็ตาม คุณอาจพบปัญหาสองประการต่อไปนี้ในครั้งแรกที่คุณพยายามเรียกใช้คำสั่งนักเทียบท่า:
นักเทียบท่า <คำสั่งใดคำสั่งหนึ่ง>
FATA[0000] รับ https://var/run/docker.sock/v1.18/images/json:dial unix /var/run/docker.sock:ไม่มีไฟล์หรือไดเร็กทอรีดังกล่าว คุณกำลังพยายามเชื่อมต่อกับ daemon ที่เปิดใช้งาน TLS โดยไม่มี TLS หรือไม่
และข้อผิดพลาดอื่นคือ:
นักเทียบท่า <คำสั่งใดคำสั่งหนึ่ง>
FATA[0000] รับ https://var/run/docker.sock/v1.18/containers/json:เรียกเลขหมายยูนิกซ์ /var/run/docker.sock:สิทธิ์ถูกปฏิเสธ คุณกำลังพยายามเชื่อมต่อกับ daemon ที่เปิดใช้งาน TLS โดยไม่มี TLS หรือไม่
เหตุผลก็คือ คุณต้องเริ่มบริการ Docker ก่อน ยิ่งไปกว่านั้น คุณต้องรันเทคโนโลยีในฐานะรูท เนื่องจาก Docker ต้องการเข้าถึงส่วนที่ค่อนข้างละเอียดอ่อนของระบบ และโต้ตอบกับเคอร์เนล นั่นคือวิธีการทำงาน
systemctl เริ่มนักเทียบท่า
ตอนนี้เราสามารถคลั่งไคล้และเริ่มใช้ Docker
คำสั่งนักเทียบท่า
สิ่งพื้นฐานคือการเรียกใช้ docker help เพื่อรับรายการคำสั่งที่มีอยู่ ฉันจะไม่ผ่านตัวเลือกทั้งหมด เราจะเรียนรู้เพิ่มเติมเกี่ยวกับพวกเขาเมื่อเราไปพร้อมกัน โดยทั่วไป หากคุณมีข้อสงสัย คุณควรศึกษาเอกสารออนไลน์ที่เหมาะสม การอ้างอิง CLI ที่สมบูรณ์ยังเตะตูด จากนั้นยังมีเอกสารสรุปที่ยอดเยี่ยมเกี่ยวกับ GitHub แต่ภารกิจแรกของเราคือดาวน์โหลดอิมเมจ Docker ใหม่ จากนั้นเรียกใช้อินสแตนซ์แรกของเรา
ดึงรูปภาพ
มีภาพให้เลือกมากมาย เราต้องการฝึกกับ CentOS นี่เป็นจุดเริ่มต้นที่ดี มีพื้นที่เก็บข้อมูลอย่างเป็นทางการและแสดงรายการรูปภาพและแท็กที่รองรับทั้งหมด ณ จุดนี้เราต้องเข้าใจว่าอิมเมจของนักเทียบท่ามีป้ายกำกับอย่างไร
หลักการตั้งชื่อคือ repository:tag เช่น centos:latest กล่าวอีกนัยหนึ่งคือเราต้องการอิมเมจ CentOS ล่าสุด แต่ภาพที่ต้องการอาจเป็น centos:6.6 เอาล่ะมาทำกัน
ตอนนี้ เรามาแสดงรายการอิมเมจโดยใช้คำสั่ง docker images:
เริ่มคอนเทนเนอร์ Docker
ดังที่เราได้เห็นในบทช่วยสอนดั้งเดิมของฉัน ตัวอย่างที่ง่ายที่สุดคือการเรียกใช้เชลล์:
นักเทียบท่ารัน -ti centos:centos7 /bin/bash
แล้วเรามีอะไรที่นี่? เรากำลังเรียกใช้อินสแตนซ์คอนเทนเนอร์ใหม่ที่มี TTY (-t) และ STDIN (-i) ของตัวเองจากอิมเมจ CentOS 7 พร้อมเชลล์ BASH ในไม่กี่วินาที คุณจะได้เปลือกใหม่ภายในคอนเทนเนอร์ ตอนนี้มันเป็นระบบปฏิบัติการพื้นฐานที่ล้าสมัยมาก แต่คุณสามารถเริ่มสร้างสิ่งต่างๆ ภายในมันได้
ติดตั้ง Apache &SSH
มาตั้งค่าเว็บเซิร์ฟเวอร์ซึ่งจะมีการเข้าถึง SSH ด้วย ด้วยเหตุนี้เราจะต้องทำการติดตั้งพื้นฐานบางอย่าง หยิบ Apache (httpd) และ SSHD (openssh-server) และกำหนดค่า สิ่งนี้ไม่เกี่ยวข้องกับ Docker แต่เป็นแบบฝึกหัดที่มีประโยชน์
พวกคุณบางคนอาจบ่นว่า เดี๋ยวก่อน คุณไม่จำเป็นต้องมี SSH ภายในคอนเทนเนอร์ มันเสี่ยงต่อความปลอดภัยและอะไรก็ตาม อาจจะใช่และไม่ใช่ขึ้นอยู่กับสิ่งที่คุณต้องการและสิ่งที่คุณตั้งใจจะใช้คอนเทนเนอร์ แต่ให้คำนึงถึงความปลอดภัยกัน จุดประสงค์ของแบบฝึกหัดคือเพื่อเรียนรู้วิธีตั้งค่าและเรียกใช้บริการต่างๆ
เริ่มบริการ
คุณอาจต้องการเริ่ม Apache ของคุณโดยใช้สคริปต์เริ่มต้นหรือคำสั่ง systemd สิ่งนี้จะไม่ทำงานทีเดียว โดยเฉพาะสำหรับ CentOS มันมาพร้อมกับ systemd แต่ที่สำคัญกว่านั้น คอนเทนเนอร์ไม่มี systemd ของตัวเอง หากคุณพยายาม คำสั่งจะล้มเหลว
systemctl เริ่ม httpd
ไม่สามารถรับการเชื่อมต่อ D-Bus:ไม่มีการเชื่อมต่อกับผู้จัดการบริการ
มีการแฮ็กเกี่ยวกับปัญหานี้ และเราจะได้เรียนรู้เกี่ยวกับสิ่งเหล่านี้ในบทช่วยสอนในอนาคต แต่โดยทั่วไปแล้ว เนื่องจากคอนเทนเนอร์มีน้ำหนักเบาและเรียบง่าย คุณจึงไม่จำเป็นต้องมีบริการเริ่มต้นที่สมบูรณ์เพื่อรันกระบวนการของคุณ สิ่งนี้จะเพิ่มความซับซ้อน
บริการ Apache
หากต้องการเรียกใช้ Apache (HTTPD) ให้ดำเนินการ /usr/sbin/httpd - หรือคำสั่งที่เทียบเท่าใน distro ของคุณ บริการควรเริ่มทำงาน โดยส่วนใหญ่จะมีคำเตือนว่าคุณไม่ได้กำหนดค่าคำสั่ง ServerName ใน httpd.conf เราได้เรียนรู้วิธีการทำเช่นนี้ในคู่มือ Apache ที่ค่อนข้างครอบคลุมของฉัน
/usr/sbin/httpd
AH00558:httpd:ไม่สามารถระบุชื่อโดเมนแบบเต็มของเซิร์ฟเวอร์ได้อย่างน่าเชื่อถือ โดยใช้ 172.17.0.4 ตั้งค่าคำสั่ง 'ชื่อเซิร์ฟเวอร์' ทั่วโลกเพื่อระงับข้อความนี้
บริการ SSH
ด้วย SSHD ให้รัน /usr/sbin/sshd
/usr/sbin/sshd -f /etc/ssh/sshd_config
ไม่สามารถโหลดรหัสโฮสต์:/etc/ssh/ssh_host_rsa_key
ไม่สามารถโหลดรหัสโฮสต์:/etc/ssh/ssh_host_dsa_key
ไม่สามารถโหลดรหัสโฮสต์:/etc/ssh/ssh_host_ecdsa_key
ไม่สามารถโหลดรหัสโฮสต์:/etc/ssh/ssh_host_ed25519_key
คุณจะล้มเหลวเพราะคุณไม่มีกุญแจทั้งหมด โดยปกติแล้ว สคริปต์เริ่มต้นใช้งานสิ่งนี้ ดังนั้นคุณจะต้องเรียกใช้คำสั่ง ssh-keygen หนึ่งครั้งก่อนที่จะเริ่มบริการได้อย่างถูกต้อง คำสั่งใดคำสั่งหนึ่งจะทำงาน:
/usr/bin/ssh-keygen -t rsa -f <พาธไปยังไฟล์>
/usr/bin/ssh-keygen -A
ssh-keygen:สร้างคีย์โฮสต์ใหม่:RSA1 RSA DSA ECDSA ED25519
ตรวจสอบว่าเว็บเซิร์ฟเวอร์เปิดอยู่หรือไม่
ตอนนี้ภายในคอนเทนเนอร์ เราจะเห็นว่า Apache กำลังทำงานอยู่
ps -ef|grep อาปาเช่
อาปาเช่ 87 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
apache 88 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
อาปาเช่ 89 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
apache 90 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
อาปาเช่ 91 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
แต่ถ้าเราต้องการตรวจสอบการเชื่อมต่อภายนอกล่ะ ณ จุดนี้เรามีปัญหาสองสามข้อ ประการแรก เรายังไม่ได้ตั้งค่าพอร์ตที่เปิดอยู่ สอง เราไม่รู้ว่าที่อยู่ IP ของคอนเทนเนอร์ของเราคืออะไร ตอนนี้ หากคุณพยายามรัน ifconfig ภายในเชลล์ BASH คุณจะไปไม่ถึงไหน เพราะไม่ได้ติดตั้งแพ็คเกจที่จำเป็นที่มีคำสั่งเครือข่ายพื้นฐาน ดี เพราะทำให้ภาชนะของเราบางและปลอดภัย
เปิดเผยพอร์ตขาเข้า
เช่นเดียวกับเว็บเซิร์ฟเวอร์อื่น ๆ เราจะต้องอนุญาตการเชื่อมต่อขาเข้า เราจะใช้พอร์ตเริ่มต้น 80 ซึ่งไม่ต่างจากการส่งต่อพอร์ตในเราเตอร์ของคุณ อนุญาตนโยบายไฟร์วอลล์และอื่นๆ ด้วย Docker มีหลายวิธีที่คุณสามารถบรรลุผลลัพธ์ที่ต้องการได้
เมื่อเริ่มคอนเทนเนอร์ใหม่ด้วยคำสั่ง run คุณสามารถใช้ตัวเลือก -p เพื่อระบุพอร์ตที่จะเปิด คุณสามารถเลือกพอร์ตเดียวหรือหลายพอร์ต และคุณยังสามารถแมปทั้งพอร์ตโฮสต์ (hostPort) และพอร์ตคอนเทนเนอร์ (containerPort) ตัวอย่างเช่น:
- -p 80 จะเปิดเผยคอนเทนเนอร์พอร์ต 80 ซึ่งจะถูกแมปโดยอัตโนมัติกับพอร์ตแบบสุ่มบนโฮสต์ เราจะเรียนรู้วิธีระบุพอร์ตที่ถูกต้องในภายหลัง
- -p 80:80 จะจับคู่พอร์ตคอนเทนเนอร์กับพอร์ตโฮสต์ 80 ซึ่งหมายความว่าคุณไม่จำเป็นต้องทราบที่อยู่ IP ภายในของคอนเทนเนอร์ มีองค์ประกอบของ NAT ภายในที่เกี่ยวข้อง ซึ่งต้องผ่านอินเทอร์เฟซเสมือนของ Docker เราจะหารือเกี่ยวกับเรื่องนี้ในไม่ช้า ยิ่งไปกว่านั้น หากคุณใช้วิธีนี้ คอนเทนเนอร์เดียวเท่านั้นที่จะสามารถผูกกับพอร์ต 80 ได้ หากคุณต้องการใช้เว็บเซิร์ฟเวอร์หลายตัวที่มีที่อยู่ IP ต่างกัน คุณจะต้องตั้งค่าแต่ละเซิร์ฟเวอร์บนพอร์ตที่แตกต่างกัน
นักเทียบท่ารัน -ti -p 22:22 -p 80:80 image-1:latest
FATA [0000] การตอบสนองข้อผิดพลาดจากภูต:ไม่สามารถเริ่มคอนเทนเนอร์ 64bd520e2d95a699156f5d40331d1aba972039c3c201a97268d61c6ed17e1619:ผูกสำหรับ 0.0.0.0:80 ล้มเหลว:พอร์ตได้รับการจัดสรรแล้ว
มีข้อควรพิจารณาเพิ่มเติมหลายประการ การส่งต่อ IP, เครือข่ายบริดจ์, เครือข่ายสาธารณะและส่วนตัว, ช่วงเครือข่ายย่อย, กฎไฟร์วอลล์, การจัดสรรภาระงาน และอื่นๆ ในขณะนี้ เราไม่จำเป็นต้องกังวลเกี่ยวกับสิ่งเหล่านี้
นอกจากนี้ยังมีวิธีการเพิ่มเติมในการเปิดเผยพอร์ต แต่เราจะพูดถึงเรื่องนี้ในภายหลัง เมื่อเราพูดถึงหัวข้อของ Dockerfiles ซึ่งเป็นเทมเพลตสำหรับสร้างรูปภาพใหม่ สำหรับตอนนี้ เราต้องจำไว้ว่าให้รันอิมเมจของเราด้วยตัวเลือก -p
ตรวจสอบที่อยู่ IP
หากคุณต้องการปล่อยให้พอร์ตโฮสต์ว่าง คุณสามารถละเว้นส่วน hostPort ได้ ในกรณีนั้น คุณสามารถเชื่อมต่อกับคอนเทนเนอร์ได้โดยตรง โดยใช้ที่อยู่ IP และพอร์ตเว็บเซิร์ฟเวอร์ ในการทำเช่นนั้น เราต้องคิดรายละเอียดคอนเทนเนอร์ของเรา:
นักเทียบท่าตรวจสอบ <ชื่อคอนเทนเนอร์หรือรหัส>
นี่จะให้รายการรายละเอียดที่ยาวมาก เหมือนกับการกำหนดค่า KVM XML ยกเว้นว่าอันนี้เขียนด้วย JSON ซึ่งเป็นอีกรูปแบบที่ทันสมัยและน่าเกลียดสำหรับข้อมูล อ่านได้ แต่น่าเกลียดมาก
นักเทียบท่าตรวจสอบฟุ้งซ่าน_euclid
[{
"AppArmorProfile":"",
"อาร์กส์":[],
"กำหนดค่า":{
"AttachStderr":จริง
"AttachStdin":จริง
"AttachStdout":จริง
"คำสั่ง":[
"/ถังขยะ/ทุบตี"
]
"CpuShares":0,
"ซีพียู":"",
"ชื่อโดเมน":"",
"จุดเข้าใช้งาน":null,
"เอ็น":[
...
"พอร์ตที่เปิดเผย":{
"80/tcp":{}
},
"ชื่อโฮสต์":"43b179c5aec7",
"รูปภาพ":"centos:centos7",
"ป้ายกำกับ":{},
"หมายเลขทางกายภาพ":"",
...
เราสามารถจำกัดให้เหลือแค่ IP Address
นักเทียบท่าตรวจสอบ <ชื่อคอนเทนเนอร์หรือ ID> | grep -i "ไอแพดเดอร์"
"ที่อยู่ IP":"172.17.0.20",
กำลังทดสอบการกำหนดค่าใหม่
มาเริ่มต้นกันใหม่ เปิดตัวอินสแตนซ์ใหม่ ตั้งค่า Apache เริ่มต้น เปิดเว็บเบราว์เซอร์และทดสอบ หากใช้งานได้ แสดงว่าคุณได้กำหนดค่าเว็บเซิร์ฟเวอร์ของคุณอย่างถูกต้องแล้ว สิ่งที่เราต้องการ
นักเทียบท่ารัน -it -p 80:80 centos:centos7 /bin/bash
หากเราตรวจสอบคอนเทนเนอร์ที่กำลังทำงานอยู่ เราสามารถเห็นการแมปพอร์ต - เอาต์พุตถูกแบ่งออกเป็นหลายบรรทัดเพื่อความกะทัดรัด ดังนั้นโปรดแก้ตัว โดยปกติ ชื่อเรื่องตัวพิมพ์ใหญ่ทั้งหมดจะแสดงเป็นส่วนหัวของแถว จากนั้น คุณจะได้พิมพ์ส่วนที่เหลือทั้งหมดด้านล่าง หนึ่งคอนเทนเนอร์ต่อบรรทัด
#นักเทียบท่า ps
รหัสคอนเทนเนอร์ รูปภาพ คำสั่ง
43b179c5aec7 centos:centos7 "/bin/bash"
สร้างแล้ว สถานะ พอร์ต
2 ชั่วโมงที่แล้ว เพิ่มขึ้น 2 ชั่วโมง 0.0.0.0:80->80/tcp
NAMES ฟุ้งซ่าน_euclid
และในเบราว์เซอร์ เราได้รับ:
ทางเลือก:ตอนนี้ช่วงที่อยู่ IP ภายในจะสามารถเข้าถึงได้บนโฮสต์เท่านั้น หากคุณต้องการให้มันสามารถเข้าถึงได้จากเครื่องอื่น คุณจะต้องส่งต่อ NAT และ IP ของคุณ และถ้าคุณต้องการใช้ชื่อ คุณจะต้องกำหนดค่า /etc/hosts และ DNS ให้ถูกต้อง สำหรับคอนเทนเนอร์ สามารถทำได้โดยใช้คำสั่ง --add-host="host:IP" เมื่อเรียกใช้อินสแตนซ์ใหม่
หมายเหตุอื่น:โปรดจำไว้ว่า Docker มีเครือข่ายภายในของตัวเอง เช่นเดียวกับ VirtualBox และ KVM ดังที่เราได้เห็นในบทช่วยสอนอื่นๆ ของฉัน เป็นเครือข่ายที่ค่อนข้างกว้างขวาง /16 ดังนั้นคุณจึงมีอิสระค่อนข้างมาก บนโฮสต์:
# /sbin/ifconfig
docker0:flags=4163
inet 172.17.42.1 เน็ตมาสก์ 255.255.0.0 ออกอากาศ 0.0.0.0
inet6 fe80::5484:7aff:fefe:9799 คำนำหน้า 64 scopeid 0x20
อีเธอร์ 56:84:7a:fe:97:99 txqueuelen 0 (อีเธอร์เน็ต)
แพ็กเก็ต RX 6199 ไบต์ 333408 (325.5 KiB)
ข้อผิดพลาด RX 0 หลุด 0 โอเวอร์รัน 0 เฟรม 0
แพ็กเก็ต TX 11037 ไบต์ 32736299 (31.2 MiB)
ข้อผิดพลาด TX 0 หลุด 0 โอเวอร์รัน 0 พาหะ 0 ชนกัน 0
ตรวจสอบว่า SSH ทำงานได้หรือไม่
เราต้องทำแบบฝึกหัดเดียวกันกับ SSH นี่หมายถึงการเปิดเผยพอร์ต 22 และเรามีตัวเลือกมากมาย เพื่อให้น่าสนใจยิ่งขึ้น ลองกำหนดพอร์ตแบบสุ่ม:
นักเทียบท่ารัน -ti -p 20 -p 80 centos:centos7 /bin/bash
และถ้าเราตรวจสอบกับ docker ps โดยเฉพาะสำหรับพอร์ต:
0.0.0.0:49176->22/tcp, 0.0.0.0:49177->80/tcp เบื่อ_mcclintock
ซึ่งหมายความว่าคุณสามารถเชื่อมต่อกับที่อยู่ IP ของ docker0, พอร์ตตามที่ระบุข้างต้นในเอาต์พุตคำสั่ง docker ps และเทียบเท่ากับการเชื่อมต่อกับคอนเทนเนอร์ IP โดยตรงบนพอร์ตบริการ สิ่งนี้มีประโยชน์ เพราะคุณไม่จำเป็นต้องกังวลเกี่ยวกับที่อยู่ IP ภายในที่คอนเทนเนอร์ของคุณใช้ และสามารถทำให้การส่งต่อง่ายขึ้น ทีนี้มาลองเชื่อมต่อกัน เราสามารถใช้พอร์ตโฮสต์หรือใช้ IP ของคอนเทนเนอร์โดยตรงก็ได้
ssh 172.17.42.1 -p 49117
ไม่ว่าจะด้วยวิธีใด เราจะได้สิ่งที่ต้องการ เช่น
ssh 172.17.0.5
ไม่สามารถสร้างความถูกต้องของโฮสต์ '172.17.0.5 (172.17.0.5)' ได้ ลายนิ้วมือของคีย์ ECDSA คือ 00:4b:de:91:60:e5:22:cc:f7:89:01:19:3e:61:cb:ea
คุณแน่ใจหรือไม่ว่าต้องการเชื่อมต่อต่อ (ใช่/ไม่ใช่) ใช่
คำเตือน:เพิ่ม '172.17.0.5' (ECDSA) อย่างถาวรในรายการโฮสต์ที่รู้จัก
รหัสผ่านของ [email protected]:
เดี๋ยวก่อน รหัสผ่านรูทคืออะไร?
เราจะล้มเหลวเพราะเราไม่มีรหัสผ่านรูท ดังนั้นสิ่งที่เราจะทำในขณะนี้? อีกครั้ง เรามีหลายทางเลือก ขั้นแรก ให้ลองเปลี่ยนรหัสผ่านรูทภายในคอนเทนเนอร์โดยใช้คำสั่ง passwd แต่จะไม่ทำงานเนื่องจากไม่ได้ติดตั้งยูทิลิตี passwd จากนั้นเราสามารถคว้า RPM ที่จำเป็นและตั้งค่าภายในคอนเทนเนอร์ได้ บนโฮสต์ ตรวจสอบการพึ่งพา:
รอบต่อนาที -q --สิ่งที่ให้ /etc/passwd
การตั้งค่า-2.8.71-5.el7.noarch
แต่นี่เป็นช่องโหว่ด้านความปลอดภัย เราต้องการให้ภาชนะของเราเป็นแบบลีน ดังนั้นเราจึงสามารถคัดลอกแฮชรหัสผ่านจาก /etc/shadow บนโฮสต์ลงในคอนเทนเนอร์ ในภายหลัง เราจะได้เรียนรู้เกี่ยวกับวิธีที่คล่องตัวมากขึ้นในการดำเนินการดังกล่าว
อีกสิ่งหนึ่งที่เห็นได้ชัดคือเรากำลังทำซ้ำการกระทำทั้งหมดของเรา การดำเนินการนี้ไม่มีประสิทธิภาพ และนี่คือเหตุผลที่เราต้องการรักษาการเปลี่ยนแปลงที่เราได้ทำกับคอนเทนเนอร์ของเรา ส่วนถัดไปจัดการที่
คอมมิตอิมเมจ
หลังจากที่คุณทำการเปลี่ยนแปลงกับคอนเทนเนอร์แล้ว คุณอาจต้องยอมรับการเปลี่ยนแปลงนั้น กล่าวอีกนัยหนึ่ง เมื่อเริ่มต้นคอนเทนเนอร์ใหม่ในภายหลัง คุณไม่จำเป็นต้องทำขั้นตอนทั้งหมดซ้ำตั้งแต่เริ่มต้น คุณจะสามารถใช้งานที่มีอยู่ซ้ำได้ และประหยัดเวลาและแบนด์วิธ คุณสามารถคอมมิตอิมเมจตาม ID หรือนามแฝง:
นักเทียบท่ายอมรับ <ชื่อคอนเทนเนอร์หรือรหัส> <รูปภาพใหม่>
ตัวอย่างเช่น เราได้รับสิ่งต่อไปนี้:
นักเทียบท่ายอมรับ 43b179c5aec7 myapache3.dll
1ee373ea750434354faeb1cb70b0177b463c51c96c9816dcdf5562b4730dac54
ตรวจสอบรายชื่อภาพอีกครั้ง:
ไฟล์เทียบท่า
วิธีที่มีประสิทธิภาพมากขึ้นในการสร้างรูปภาพของคุณคือการใช้ Dockerfiles ในทางหนึ่ง มันก็เหมือนกับการใช้ Makefile ในการคอมไพล์ ในรูปแบบ Docker เท่านั้น Or an RPM specfile if you will. Basically, in any one "build" directory, create a Dockerfile. We will learn what things we can put inside one, and why we want it for our Apache + SSH exercise. Then, we will build a new image from it. We can combine it with our committed images to preserve changes already done inside the container, like the installation of software, to make it faster and save network utilization.
Before we go any further, let's take a look at a Dockerfile that we will be using for our exercise. At the moment, the commands may not make much sense, but they soon will.
FROM myhttptest2:latest
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
EXPOSE 80
RUN mkdir -p /run/httpd
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
What do we have here?
- The FROM directory tells us what repo:tag to use as the baseline. In our case, it's one of the committed images that already contains the httpd and sshd binaries, SSH keys, and a bit more.
- EXPOSE 22 - This line exposes port 22 inside the container. We can map it further using the -p option at runtime. The same is true for EXPOSE 80, which is relevant for the Web server.
- CMD ["/usr/sbin/sshd", "-D"] - This instructions runs an executable, with optional arguments. มันเป็นเรื่องง่ายเหมือนที่.
- RUN mkdir -p /run/httpd - This instruction runs a command in a new layer on top of the base image - and COMMITS the results. This is very important to remember, as we will soon discuss what happens if you don't use the RUN mkdir thingie with Apache.
- CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] - We run the server, in the foreground. The last bit is optional, but for the time being, you can start Apache this way. Good enough.
As you can see, Dockerfiles aren't that complex or difficult to write, but they are highly useful. You can pretty much add anything you want. Using these templates form a basis for automation, and with conditional logic, you can create all sorts of scenarios and spawn containers that match your requirements.
Build image
Once you have a Dockerfile in place, it's time to build a new image. Dockerfiles must follow a strict convention, just like Makefiles. It's best to keep different image builds in separate sub-directories. ตัวอย่างเช่น:
docker build -t test5 .
Sending build context to Docker daemon 41.47 kB
Sending build context to Docker daemon
Step 0 :FROM myapache4:latest
---> 7505c70235e6
Step 1 :EXPOSE 22 80
---> Using cache
---> 58f11217c3e3
Step 2 :CMD /usr/sbin/sshd -D
---> Using cache
---> 628c3d6b5399
Step 3 :RUN mkdir -p /run/httpd
---> Using cache
---> 5fc118f61a4d
Step 4 :CMD /usr/sbin/httpd -D FOREGROUND
---> Using cache
---> d892acd86198
Successfully built d892acd86198
The command tells us the following:-t repository name from a Dockerfile stored in the current directory (.). นั่นคือทั้งหมด Very simple and elegant.
Test image
Run a new container from the created image. If everything went smoothly, you should have both SSH connectivity, as well as a running Web server in place. Again, all the usual network related rules apply.
Alternative build
Once you have the knowledge how do it on your own, you can try one of the official Apache builds. Indeed, the Docker repository contains a lot of good stuff, so you should definitely invest time checking available templates. For Apache, you only need the following in your Dockerfile - the second like is optional.
FROM httpd:2.4
COPY ./public-html/ /usr/local/apache2/htdocs/
COPY instruction
What do we have above? Basically, in the Dockerfile, we have the declaration what template to use. And then, we have a COPY instructions, which will look for a public-html directory in the current folder and copy it into the container during the build. In the same manner, you can also copy your httpd.conf file. Depending on your distribution, the paths and filenames might differ. Finally, after building the image and running the container:
docker run -ti -p 22 -p 80 image-1:latest
AH00558:httpd:Could not reliably determine the server's fully qualified domain name, using 172.17.0.17. Set the 'ServerName' directive globally to suppress this message
[Thu Apr 16 21:08:35.967670 2015] [mpm_event:notice] [pid 1:tid 140302870259584] AH00489:Apache/2.4.12 (Unix) configured -- resuming normal operations
[Thu Apr 16 21:08:35.976879 2015] [core:notice] [pid 1:tid 140302870259584] AH00094:Command line:'httpd -D FOREGROUND'
Advantages of containers
There are many good reasons why you want to use this technology. But let's just briefly focus on what we gain by running these tiny, isolated instances. Sure, there's a lot happening under the hood, in the kernel, but in general, the memory footprint of spawned containers is fairly small. In our case, the SSH + Apache containers use a tiny fraction of extra memory. Compare this to any virtualization technology.
Problems you may encounter &troubleshooting
Let's go back to the Apache example, and now you will also learn why so many online tutorials sin the sin of copy &pasting information without checking, and why most of the advice is not correct, unfortunately. It has to do with, what do you do if your Apache server seems to die within a second or two after launching the container? Indeed, if this happens, you want to step into the container and troubleshoot. To that end, you can use the docker exec command to attach a shell to the instance.
docker exec -ti boring_mcclintock /bin/bash
Then, it comes down to reading logs and trying to figure out what might have gone wrong. If your httpd.conf is configured correctly, you will have access and error logs under /var/log/httpd:
[auth_digest:error] [pid 25] (2)No such file or directory:AH01762:Failed to create shared memory segment on file /run/httpd/authdigest_shm.25
A typical problem is that you may be a missing /run/httpd directory. If this one does not exist in your container, httpd will start and die. Sounds so simple, but few if any reference mentions this.
While initially playing with containers, I did encounter this issue. Reading online, I found several suggestions, none of which really helped. But I do want to elaborate on them, and how you can make progress in your problem solving, even if intermediate steps aren't really useful.
Suggestion 1:You must use -D FOREGROUND to run Apache, and you must also use ENTRYPOINT rather than CMD. The difference between the two instructions is very subtle. And it does not solve our problem in any way.
ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]
Suggestion 2:Use a separate startup script, which could work around any issues with the starting or restarting of the httpd service. In other words, the Dockerfile becomes something like this:
...
EXPOSE 80
COPY ./run-httpd.sh /run-httpd.sh
RUN chmod -v +x /run-httpd.sh
CMD ["/run-httpd.sh"]
And the contents of the run-httpd.sh script are along the lines of:
#!/bin/bash
rm -rf /run/httpd/*
exec /usr/sbin/apachectl -D FOREGROUND
เกือบจะมี. Remove any old leftover PID files, but these are normally not stored under /run/httpd. Instead, you will find them under /var/run/httpd. Moreover, we are not certain that this directory exists.
Finally, the idea is to work around any problems with the execution of a separation shell inside which the httpd thread is spawned. While it does provide us with additional, useful lessons on how to manage the container, with COPY and RUN instructions, it's not what we need to fix the issue.
Step 3 :EXPOSE 80
---> Using cache
---> 108785c8e507
Step 4 :COPY ./run-httpd.sh /run-httpd.sh
---> 582d795d59d4
Removing intermediate container 7ff5b58b40bf
Step 5 :RUN chmod -v +x /run-httpd.sh
---> Running in 56fadf4dd2d4
mode of '/run-httpd.sh' changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)
---> 928640f680cf
Removing intermediate container 56fadf4dd2d4
Step 6 :CMD /run-httpd.sh
---> Running in f9c6b30795e2
---> b2dcc2818a27
Removing intermediate container f9c6b30795e2
Successfully built b2dcc2818a27
This won't work, because apachectl is an unsupported command for managing httpd, plus we have seen problems using startup scripts and utilities earlier, and we will work on fixing this in a separate tutorial.
docker run -ti -p 80 image-2:latest
Passing arguments to httpd using apachectl is no longer supported. You can only start/stop/restart httpd using this script. If you want to pass extra arguments to httpd, edit the /etc/sysconfig/httpd config file.
But it is useful to try these different things, to get the hang of it. Unfortunately, it also highlights the lack of maturity and the somewhat inadequate documentation for this technology out there.
Additional commands
There are many ways you can interact with your container. If you do not want to attach a new shell to a running instance, you can use a subset of docker commands directly against the container ID or name:
docker
For instance, to get the top output from the container:
docker top boring_stallman
If you have too many images, some of which have just been used for testing, then you can remove them to free up some of your disk space. This can be done using the docker rmi command.
# docker rmi -f test7
Untagged:test7:latest
Deleted: d0505b88466a97b73d083434b2dd0e7b59b9a5e8d0438b1bf8c6c
Deleted:5fc118f61bf856f6f3d90e0e71076b737fa7cc58cd56785ea7904
Deleted:628c3d6b53992521c9c1fdda4148693347c3d10b1d130f7e091e7
Deleted:58f11217c3e31206b4e41d07100a797cd4d17e4569b0fdb8b7a18
Deleted:7505c70235e638c54028ea5b63eba2b691de6bee67c2cb5e2861a
...
Then, you can also run your containers in the background. Using the -d flag will do exactly that, and you will get the shell prompt back. This is also useful if you do not mask signals, so if you accidentally break in your shell, you might kill the container when it's running in the foreground.
docker run -d -ti -p 80 image-3:latest
You can also check events, examine changes inside a container's filesystem as well as check history, so you basically have a version control in place, export or import tarred images to and from remote locations, including over the Web, and more.
Differences between exec and attach
If you read through the documentation, you will notice you can connect to a running container using either exec or attach commands. So what's the difference, you may ask? If we look at the official documentation, then:
The docker exec command runs a new command in a running container. The command started using docker exec only runs while the container's primary process (PID 1) is running, and it is not restarted if the container is restarted.
On the other hand, attach gives you the following:
The docker attach command allows you to attach to a running container using the container's ID or name, either to view its ongoing output or to control it interactively. You can attach to the same contained process multiple times simultaneously, screen sharing style, or quickly view the progress of your daemonized process. You can detach from the container (and leave it running) with CTRL-p CTRL-q (for a quiet exit) or CTRL-c which will send a SIGKILL to the container. When you are attached to a container, and exit its main process, the process's exit code will be returned to the client.
In other words, with attach, you will get a shell, and be able to do whatever you need. With exec, you can issue commands that do not require any interaction, but with you use a shell in combination with exec, you will achieve the same result as if you used attach.
Differences between start and run
Start is used to resume the execution of a stopped container. It is not used to start a fresh instance. For that, you have the run command. The choice of words could have been better.
Differences between build and create
The first command is used to create a new image from a Dockerfile. On the other hand, the latter is used to create a new container using command line options and arguments. Create lets you specify container settings, too, like network configurations, resource limitations and other settings, which affect the container from the outside, whereas the changes implemented by the build command will be reflected inside it, once you start an instance. And by start, I mean run. รับมัน?
This is just a beginning ...
There are a million more things we can do: using systemd enabled containers, policies, security, resource constraints, proxying, signals, other networking and storage options including the super-critical question of how to mount data volumes inside containers so that data does not get destroyed when containers die, additional pure LXC commands, and more. We've barely scratched the surface. But now, we know what to do. And we'll get there. Slowly but surely.
อ่านเพิ่มเติม
I recommend you allocate a few hours and then spend some honest time reading all of the below, in detail. Then practice. This is the only way you will really fully understand and embrace the concepts.
My entire virtualization section
Dockerizing an SSH Deamon Service
Differences between save and export in Docker
Docker Explained:Using Dockerfiles to Automate Building of Images
สรุป
We're done with this tutorial for today. Hopefully, you've found it useful. In a nutshell, it does explain quite a few things, including how to get started with Docker, how to pull new images, run basic containers, add services like SSH and Apache, commit changes to a file, expose incoming ports, build new images with Dockerfiles, lots of troubleshooting of problems, additional commands, and more. Eventful and colorful, I'd dare say.
In the future, we will expand significantly on what we learned here, and focus on various helper technologies like supervisord for instance, we will learn how to mount filesystems, work on administration and orchestration, and many other cool things. Docker is a very nice concept, and if used correctly, it can make your virtual world easier and more elegant. The initial few steps are rough, but with some luck, this guide will have provided you with the right dose of karma to get happily and confidently underway. Ping me if you have any requests or desires. Technology related, of course. เสร็จแล้ว
ป.ล. If you like this article, then you'd better give some love back to Dedoimedo!ไชโย