Jaynarol Blog

Docker : สร้าง Private Registry ของตัวเองด้วย Nexus

สวัสดีครับ ห่างหายจากการเขียน Blog ไปเป็นเดือนเลย เนื่องจากติดงาน(และติดเกมส์ 55+) ในหัวข้อนี้เป็นการแบ่งปันที่ผมลองผิดลองถูกเกือบทั้งวัน เรื่องของเรื่องคือโปรเจคที่ผมดูแลจะใช้วิธีการแบ่งส่วนงานเป็นส่วนๆแบบแยกจากกันขาดและเรียกมารวมกันทีหลัง เช่นในระดับโปรแกรมที่เขียนด้วย Java ต้องเขียนแต่ละส่วนเป็น jar และ import ผ่าน Maven โปรเจคที่เขียนด้วย Node ก็ใช้ NPM และสุดท้ายคือในระดับ Infrastructure ก็ต้องใช้ Docker Image แยกแต่ละส่วนและมาประกอบกันด้วย Docker Compose นั่นเองครับ เพื่อให้สามารถดูแลง่ายและใช้ซ้ำได้นั่นเอง (แนวคิดนี้ดีนะ)

ปัญหาคือไฟล์งานมันไม่ควรเป็นสาธารณะ อยากมี Repository ทั้ง Mavan NPM และ Docker แบบส่วนตัว อยากให้มันดูแลง่ายที่สุด อยากให้มันมีระบบจัดการสิทธิ์ และสุดท้ายคือใช้ Cost น้อยที่สุดครับ

บทความนี้จะเน้นพูดถึงเพียง Docker Registry ละกันครับไม่งั้นมันจะยาวมาก ซึ่งผมลองแวะไปดู Private Registry มาหลายที่มาก ตั้งแต่ของ Docker Hub เอง ราคาปวดตับมากจะใช้ Image ทีคิดหนักครับ(โปรเจคผมมี 20 image++ ชัว) ลองไปใช้ GitLab พบว่าการ Pull/Push ช้ามาก รับไม่ได้จริงๆ ครั้นจะสร้าง Registry เองแบบโดดๆก็ยังตอบโจทย์ไม่ครบอยู่ดีครับ

สุดท้ายหลังจากหาข้อมูลไปพักนึงก็เจอเจ้า Nexus ครับที่ตอบโจทย์ผมหมดเลย เพื่อไม่เสียเวลามาดูวิธีการกันดีกว่าครับ

บทความค่อนข้างยาว โปรดทำใจไว้ด้วยนะครับ

คนอ่านใช้เวลา 10 นาที คนเขียนเสียเวลา 10 ชั่วโมงครับ หวังว่าคงมีประโยชน์ครับ 😀 

 

– ขั้นตอนตั้งแต่ Zero ยัน Hero ดังนี้

  1. เข้าใจภาพรวมระบบที่เรากำลังจะทำกัน
  2. เตรียมพร้อมโครงสร้างระบบด้วย Docker Compose
  3. สร้าง Key Store สำหรับใช้งาน Nexus แบบ Self-signed Certificate
  4. ตั้งค่าไฟล์ Config ของ Nexus สำหรับเชื่อมต่อผ่าน HTTPS
  5. สร้างและตั้งค่า Droplet ที่ DigitalOcean ผ่าน Docker Machine
  6. สั่งรัน Nexus บน Droplet ด้วย Docker Compose
  7. ตั้งค่า Cloudflare สำหรับการเชื่อมต่อผ่าน HTTPS
  8. เริ่มใช้งาน Nexus และสร้าง Docker Private Registry
  9. ทดลองใช้งาน Docker Private Registry ของเรา

 

– สิ่งที่เรา ต้องมี/ใช้ มีดังนี้

  1. มี Git ในเครื่องเพื่อ Clone Base Docker Compose จากผม
  2. มี Java ในเครื่องสำหรับสร้าง Key Store
  3. มี Docker ในเครื่องเพื่อใช้งาน Docker Machine
  4. มี DigitalOcean Account สำหรับ Cloud ที่ใช้รัน Nexus (หรือใช้ Cloud Provider ตัวอื่นที่ Docker Machine รองรับก็ได้ครับ)
  5. มี Cloudfare Account สำหรับการเชื่อมต่อผ่าน HTTPS ฟรีๆ
  6. มี Domain ของตัวเอง
  7. มีค่าใช้จ่ายทั้งหมดประมาณ 0.24 บาทต่อชั่วโมง หรือราวๆ 175 บาทต่อเดือน (DigitalOcean Smaill Size)
  8. มีเวลาและอ่านหนังสือเกิน 7 บรรทัดต่อวัน (อันนี้เอาฮาครับ)
  9. เมื่อพร้อมแล้วก็ลุยกันเลยครับ

 

1. เข้าใจภาพรวมระบบที่เรากำลังจะทำกัน

nexus

 

หลังจากดูภาพแล้วคิดว่าคงจะเข้าใจไม่ก็งงมากขึ้นแน่นอน ช่างมันครับ พักมันไว้ก่อน ไว้เราทำขั้นตอนอื่นๆแล้วงงว่ามันอยู่ตรงไหนของระบบ/มันคืออะไร เราค่อยเลื่อนขึ้นมาดูครับ 🙂

 

2. เตรียมพร้อมโครงสร้างระบบด้วย Docker Compose

เพื่อความรวดเร็ว Clone Base มาจากผมเลยดีกว่าครับ

หลังจาก Clone แล้วข้อมูลจะอยู่ที่ ~/my-nexus ใครอยากย้ายก็ทำได้ครับ (แต่ต้องชี้ path ใน terminal ไปถูกนะ)

 

เมื่อเปิดไฟล์ Docker Compose มาดูเล่นๆจะเห็นว่ามี Container ตัวเดียวชื่อว่า repo บางคนอาจงงว่ามีแค่ตัวเดียวทำไมต้องใช้ Docker Compose ด้วย เหตุผลสั้นๆคือมันสะดวกเวลา start/stop ครับ 🙂

 

Image หลักของเราคือ sonatype/nexus3 ครับ เป็น Official Image จาก sonatype

ส่วนข้อมูลอื่นๆเช่น Ports คือ

  • 443 สำหรับเข้าใช้งานระบบ Management ของ Nexus ผ่าน Browser
  • 8443 สำหรับใช้งาน Docker Registry

และ Volume

  • ./src เก็บข้อมูลที่เป็น Repository ทั้งหมดของ Nexus
  • ./ssl เก็บ Key Store สำหรับสร้างคีย์ต่างๆในระบบ (เราจะได้ทำกันในขั้นตอนถัดไป)
  • ./config สำหรับแก้ไข Config ใน Nexus ให้ใช้งานผ่าน HTTPS

 

3. สร้าง Key Store สำหรับใช้งาน Nexus แบบ Self-signed Certificate

ขั้นตอนนี้จำเป็นต้องติดตั้ง Java เพื่อใช้งานคำสั่ง keytool ใครพบปัญหาลองอ่านวิธีแก้ ที่นี่ ครับ และจำเป็นต้องมี Domain ของตัวเองด้วยครับ

หลายๆคนเห็นคำว่า Self-signed Certificate อาจจะอุทานแปลกๆออกมาเพราะคงมีอดีตกับมันมาเยอะ แต่ไม่ต้องตกใจครับ เราไม่ได้ใช้งานมันโดยตรง เอามาใช้แค่เพิ่มระดับความปลอดภัยเท่านั้นเอง 🙂

คำสั่งการสร้าง Key Store ผมเตรียมมาให้แล้ว เหลือเพียงแก้ Domain เป็นของตัวเองและรันคำสั่งครับ

 

หลังสั่งรันคำสั่งถ้าไม่มีอะไรผิดพลาดมันจะให้เราตั้งรหัสผ่าน(ห้ามลืมนะครับต้องใช้ในขั้นตอนต่อไป) กรอกไปเหมือนกันทั้ง 4 รอบครับ และเราจะได้ไฟล์ keystore.jks ใน Folder ./ssl ครับ

เราสามารถทดสอบไฟล์ Key Store ของเราว่ามัน Work และข้อมูลตรงจริงไหม ด้วยคำสั่ง

 

4. ตั้งค่าไฟล์ Config ของ Nexus สำหรับเชื่อมต่อผ่าน HTTPS

ในขั้นตอนนี้เราจะไปแก้ไขไฟล์ ./config/jetty-https.xml ให้เปลี่ยนตรงที่ผม Highlight สีเหลืองไว้ทั้ง 3 ที่ให้เป็น รหัสผ่าน ที่ได้ตั้งไว้ในขั้นตอนที่แล้วครับ

 

5. สร้างและตั้งค่า Droplet ที่ DigitalOcean ผ่าน Docker Machine

1. ขั้นตอนนี้จำเป็นต้องมี Docker Machine ในเครื่องใครยังไม่ได้ติดตั้ง Docker ต้องไปติดตั้งก่อนนะครับ (Mac / Windows)

2. และขั้นตอนนี้ยังจำเป็นต้องมี DigitalOcean Personal Access Tokens สำหรับใช้คู่กับ Docker Machine ใครยังไม่มีแนะนำ สมัคร DigitalOcean / วิธีสร้าง Personal Access Tokens ครับ

4 ขั้นตอนแรกที่ผ่านมานี่ยังดูชิวๆอยู่ครับเพราะทำในเครื่องเรา จากขั้นตอนนี้ไปเราจะเริ่มขยับไปจัดการระบบภายนอกบ้าง เริ่มจากสร้าง Droplet ที  DigitalOcean ด้วย Docker Machine ดังนี้ครับ

ก่อนสั่งรันอย่าลืมแก้ DIGITALOCEAN_ACCESS_TOKEN เป็นของตัวเองก่อนนะครับ ส่วน MC คือชื่อของเครื่องเราเมื่อสั่งผ่าน Docker Machine จะแก้หรือไม่ก็ได้ครับ (ถ้าไม่อยากงงตั้งเหมือนผมไว้ก่อนดีกว่านะ) 
ในคำสั่งนี้ผมได้ยำทุกอย่างที่เราต้องทำเวลาสร้าง Droplet สักตัวมาหมดแล้ว ได้แก่

  1. สร้าง Droplet ตัวใหม่ขึ้นมา
  2. ติดตั้ง Docker Compose ลงไป
  3. ตั้งค่าสิทธิ์ต่างๆ
  4. สร้าง swap เผื่อเมมไม่พอ (เหมาะกับ Droplet เล็กๆ)

การทำงานของคำสั่งอาจใช้เวลา 1-2 นาที หลังรันเสร็จเราสามารถตรวจสอบการเชื่อมต่อและเอา IP ของ Droplet ด้วยคำสั่ง docker-machine ls (เราต้องใช้ IP ของ Droplet ในขั้นตอนถัดๆไป)

 

 

6. สั่งรัน Nexus บน Droplet ด้วย Docker Compose

ในตอนนี้ Droplet ที่ DO (DigitalOcean) ของเรายังว่างเปล่าอยู่ ดังนั้นก่อนเราจะเข้าไปสั่งรันอะไรได้เราต้องอัพโหลดข้อมูลไปให้มันก่อน จริงๆมันก็มีหลายวิธี อาจจะวิ่งผ่าน git หรือ ftp(โบราณมาก)

แต่…ตอนนี้เรากำลังใช้ Docker Machine นะ แน่นอนว่าได้ยินคำว่า Docker เมื่อไหร่ ได้เจอ Surprise เสมอ เราจะอัพโหลดข้อมูลทั้งหมดของเราไปยัง Droplet ด้วย คำสั่ง scp ดังนี้

เสร็จแล้วก็ลองเชื่อมต่อไปยัง Droplet ผ่าน Docker Machine ด้วยคำสั่ง SSH ดังนี้

 

เมื่อเข้ามาแล้วลองตรวจสอบด้วยคำสั่ง ls -la ก็จะเจอ Folder mynexus ที่เราเพิ่งโยนมาเมื่อสักครู่ 🙂

ต่อไปเราก็จะตั้งค่า permission กันนิดหน่อยเพื่อความปลอดภัย และสั่งให้ Nexus เริ่มทำงานครับ อาจใช้เวลาสักนิดในการ pull image

ตอนนี้ Container เริ่มทำงานแล้ว แต่ Nexus ยังไม่พร้อมครับเพราะกำลัง Setup ตัวเองอยู่ เราสามารถดูการทำงานของ Nexus ด้วยคำสั่ง

รอจนมันขึ้นหน้า Started ดังภาพ ถือเป็นอันพร้อมใช้งานครับ (อาจใช้เวลา 5-10 นาที)

 

7. ตั้งค่า Cloudflare สำหรับการเชื่อมต่อผ่าน HTTPS

ขั้นตอนนี้จำเป็นต้องมี Account ของ Cloudflare (สมัคร) และใช้งาน DNS ของ Cloudflare โดยผูกโดเมนของเราเข้ากับ IP ของ Droplet (ขั้นตอนที่ 5)  ซึ่งผมขอข้ามเพราะมันง่ายมาก เดพที่มาถึงจุดนี้ได้ น่าจะทำเองได้ไม่ยากครับ

เมื่อ Account Cloudflare เราพร้อมแล้วก็เข้าไปที่หน้า DNS ดังรูปครับ

DNS jaynarol.com CloudFlare Web Performance Security

 

  1. คือ domain ของเราครับ
  2. ใส่ชื่อ sub domain ที่เราต้องการ
  3. ใส่ IP ของ Droplet เราจากขั้นตอนที่ 5 ลงไป
  4. กดปุ่มนี้
  5. หลังกดปุ่มจะมีแถวแบบนี้ขึ้นมาครับ
  6. ต้องให้รูปเมฆเป็นสีส้ม หากไม่ใช่สีนี้ให้คลิ๊กที่ตัวมันครับ

 

ต่อไปเราจะไปตั้งค่าให้ User เชื่อมต่อกับ Cloudflare ผ่าน HTTPS ที่มีใบรับรอง และ Cloudflare เชื่อมต่อกับ Droplet เราผ่าน HTTPS เช่นกัน แต่เป็นใบรับรองแบบ Self-signed Certificate เหมือนรูปนี้ครับ

 

ให้ไปที่หน้า Page Rules กดปุ่ม Create Page Rule แล้วใส่ข้อมูล domain (เปลี่ยนจาก nexus.jaynarol.com เป็นของตัวเอง) เลือก SSL -> Full แล้วกด Save and Deploy ครับ

Page Rules jaynarol.com CloudFlare Web Performance Security

 

บางคนอาจจะงงว่าทำไมเราต้องมาทำที่ Page Rule ทำที่ เมนู Crypto เลยได้ไหม “ตอบว่าได้ครับ” แต่เนื่องจากในเคสผมโดเมนมีหลาย subdomain แต่ละอันก็มีเคสที่ต่างไป บางอันก็ http ธรรมดา บางอันก็ใช้ SSL แบบ Flexible ดังนั้นการมาตั้งตรงนี้มันจะเจาะจงและแยกเป็นสัดส่วนดีครับ 🙂

 

8. เริ่มใช้งาน Nexus และสร้าง Docker Private Registry

ผ่านขั้นตอนโหดๆมาหมดละครับ จากนี้ไปจิ้มๆ อย่างเดียวละ 🙂

เริ่มจากเปิด browser ไปยังเว็บของเรา เช่นของผมก็ https://nexus.jaynarol.com แล้วเข้าสู่ระบบด้วย admin/admin123 ซึ่งเป็นค่า default ของระบบ (อย่าลืมไปเปลี่ยนกันด้วยละครับ)

Welcome Nexus Repository Manager

 

กดรูปเฟืองด้านบนเพื่อไปหน้าตั้งค่า กดปุ่ม Repositories ด้านซ้าย จะมี Default Repositories ของ Maven มาให้ เราไม่ได้ใช้ก็ลบให้เหี้ยนเลยครัช

Repositories Nexus Repository Manager

 

จากนั้นก็กด Create repository แล้วเลือก docker (hosted) จะเจอหน้าตาแบบภาพด้านล่าง ถ้าไม่อยากงงใส่ตามผมไปเลยก็ได้ครับ (ใครที่อยากเปลี่ยน ก็จะมี Name และ Storage เราสามารถไปสร้างอันใหม่ได้ที่เมนู Blob Stores แต่ตอนนี้ใช้ default ไปก่อนเพื่อความเข้าใจง่ายครับ ส่วน port ห้ามเปลี่ยนครับ เพราะมันผูกกับ Docker อยู่นะ) เสร็จแล้วก็กด Create repository ด้านล่าง เป็นอันเรียบร้อยครับ

Repositories Nexus Repository Manager

 

9. ทดลองใช้งาน Docker Private Registry ของเรา

ตอนนี้ทุกอย่างพร้อมใช้งานแล้วครับ แต่ก่อนอื่นเราต้องมาเข้าใจโครงสร้างของ Registry เราก่อน

<hostname>:<port>/<namespace>/<image>:<tag> 
  1. hostname คือ domain ของเรา เช่นของผมก็ nexus.jaynarol.com
  2. port คือ 8443 เป็นค่านี้เพราะผูกกับ Cloudflare และ Docker ไว้ (ใครเซียนๆไปเปลี่ยนทีหลังเอาเองได้ครับ)
  3. namespace ส่วนใหญ่ใช้เป็นชื่อ user ในระบบของเรา ค่านี้สามารถว่างได้นะครับ แต่ระบบจะใส่เป็น library ให้อัตโนมัติ
  4. image คือชื่อ Docker Image ของเราเองเลย
  5. tag ก็ตามนั้น คือ tag ของ image ครับ

ตัวอย่างเช่นบน Docker Hub คือ  username/php:7.0 เหมือนกับของเรา nexus.jaynarol.com:8443/username/php:7.0 ครับ

ว่าแล้วก็ลองเล่นกันครับ เริ่มจาก login ก่อนเลยด้วย user/pass เดียวกับ Nexus ใครยังไม่เปลี่ยนก็ admin/admin123 ครับ (อย่าลืมเปลี่ยน domain เป็นของตัวเองนะครับ)

ขึ้นว่า Login Succeeded ก็เป็นอันเรียบร้อยครับ ใช้งานได้ ต่อไปเราจะลอง push image ขึ้นไปที่ Registry ของเราครับ

อธิบายเผื่อบางคนงงก็คือ เรา pull image hello-world มาจาก Docker Hub จากนั้น ก็ใส่ Tag Image นั้นให้เป็น Registry ของเรา แล้วก็ Push ครับ

push สำเรีจลองเข้าไปตรวจสอบที่ Nexus เราได้เลยครับ โผล่มาแล้ว

Components Nexus Repository Manager

 

ปิดท้าย

Nexus นั้นสามารถเอาไปใช้งาน Repository ได้หลายตระกูลอย่างที่ผมเคยบอกไปครับ ความเจ๋งของมันคือเราสามารถควบคุมดูแลได้ทุกอย่างในจุดเดียวเลย ไม่ว่าจะเรื่อง access control ที่เราแบ่งให้แต่ละคนเข้าถึงในแต่ละส่วนได้ แบ่งโปรเจค แบ่งระบบได้ ที่สำคัญคือมันไม่มีลิมิทเสียเดือนละ 175 บาท ได้ระดับนี้ผมว่าคุ้มค่ามากๆ แต่มันก็อาจจะไม่เหมาะกับคนที่โปรเจคเล็กๆหรือ คนที่ลงทุนใช้ทางเลือกอื่นอย่าง gitlab ไปแล้ว ซึ่งก็แล้วแต่งานและสถานการณ์ไปครับ จริงรายละเอียดของมันค่อนข้างเยอะ อย่างพวก Privileges Rules ต่างๆ เชื่อมกับ LDAP ได้ด้วย ต้องลองไปกดเล่นกันดูครับ

บทความนี้ผ่านการลองผิดลองถูกของผมด้วยเวลาทั้งวันส่วนใหญ่จะติดปัญหาด้าน SSL เพราะผมไม่อยากเสียเงิน Certificates รายปี 555+ ตอนแรกไม่ใช้ SSL แต่รู้สึกไม่ใช่อย่างแรง ไม่มีความปลอดภัยเลย ต่อมาเลยลองใช้ Self-signed Certificate อย่างเดียว แต่ไม่รอดฮะ Docker ไม่ยอมและก็เว็บดูกากๆด้วย เข้า Browser ทีขึ้นตัวแดง 555+ ไม่ไหวๆ ต่อมาก็ลอง Let’s Encrypt แต่พบว่ามันเพิ่มความซับซ้อนให้ระบบโดยไม่จำเป็น เลยวิ่งไปซบอก Cloudflare อย่างที่เห็นในบทความนี่แหละครับ แต่ก็ใช้ว่าหนทางจะโรยด้วยกรีบดอกไม้ Cloudflare ยอมให้ใช้ HTTPS ผ่านแค่ 443 คือเว็บ Nexus ตัวเดียว อ้าวแล้ว Docker ละ มันก็ต้องวิ่ง HTTPS นะ ลองเปลี่ยนโดเมนเป็นสองตัว รู้สึกเริ่มไม่ใช่ละ ลองวิ่งอ้อมก็ไม่ใช่อีก สุดท้ายกลับมาหาข้อมูลพักนึงถึงรู้ว่า Clouflare ยอมให้ผ่านอีกหลายๆ Port และสุดท้ายก็มาลงที่ 8443 นี่แหละครับ สนุกมาก 555+

บางคนเข้ามาเห็นบทความยาวๆ อาจจะท้อและปิดไปก่อน จริงๆขั้นตอนมันน้อยมากครับ ผมทำแปปเดียวเอง แต่ที่มันดูยาวเพราะผมใส่ข้อมูลละเอียด 555+ เผื่อไว้ตัวผมกลับมาดูเองด้วยครับ ยังไงผิดพลาดตรงไหนฝากท้วงติงได้เลยนะครับ

ขอบคุณครับ