1 คะแนน โดย GN⁺ 2024-07-13 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • โดยปกติคอนเทนเนอร์อิมเมจจะถูกอัปโหลดไปยังรีจิสทรีเฉพาะทาง แต่หาก เปิดเผย S3 bucket ผ่าน HTTP และวางไฟล์ไว้ตามพาธที่กำหนด ก็สามารถใช้งานเป็นเป้าหมายของ docker pull ได้
  • ใน custom image builder ขั้นตอนการสร้างอิมเมจที่สามารถ pull ได้ให้เสร็จ ภายในไม่กี่วินาที กลายเป็นคอขวด และเวลาในการ push เลเยอร์กินสัดส่วนมาก
  • ในเบนช์มาร์กการอัปโหลดเลเยอร์ขนาด 198 MiB พบว่า ECR ทำได้ 24–28 MiB/s ส่วน S3 ทำได้ 115–190 MiB/s ทำให้ S3 เร็วกว่าได้สูงสุด 8 เท่า
  • ความต่างเกิดจาก S3 สามารถ อัปโหลดชังก์ของเลเยอร์เดียวแบบขนาน ได้ ขณะที่ ECR ซึ่งอิงตาม OCI Distribution Spec ต้องประมวลผลชังก์แบบลำดับ
  • วิธีนี้ยังไม่สามารถทดแทน ความสามารถของรีจิสทรี เช่น docker push, การตรวจสอบความถูกต้องของอิมเมจ, การสแกนความปลอดภัย, หรือการควบคุมสิทธิ์เข้าถึงรีโพสิตอรีแบบ private ได้ จึงควรมองว่าเป็นการปรับแต่งเชิงทดลอง

เงื่อนไขที่ทำให้ docker pull จาก S3 bucket ใช้งานได้

  • หากต้องการใช้ S3 เสมือนเป็นคอนเทนเนอร์รีจิสทรี ต้อง เปิดเผย bucket ผ่าน HTTP และอัปโหลดไฟล์อิมเมจไปยังพาธที่ Docker คาดหวัง
  • หากเงื่อนไขตรงกัน ก็สามารถดึงอิมเมจด้วย docker pull ได้เหมือนรีจิสทรีทั่วไป
  • อิมเมจสาธิตจะรัน cowsay และใช้ URL ของ bucket เป็นชื่ออิมเมจ ทำงานได้ด้วย docker run --rm .../cowsay
  • ในเดโมใช้ Cloudflare R2
    • เลือกเพราะไม่มีค่า egress
    • R2 และ S3 เข้ากันได้ในระดับ API จึงใช้อัปโหลดอิมเมจไปยัง R2 ผ่าน AWS SDK

ทำไมถึงพิจารณา S3 แทนรีจิสทรีเฉพาะทาง

  • โดยทั่วไปคอนเทนเนอร์อิมเมจจะโฮสต์บน รีจิสทรีเฉพาะทาง อย่าง DockerHub, GitHub Container Registry, หรือ ECR
  • เป้าหมายของ custom image builder คือไปให้ถึงอิมเมจที่ pull ได้จากข้อกำหนดต่าง ๆ ภายในไม่กี่วินาที
  • ในสภาพแวดล้อม AWS, ECR เป็นตัวเลือกที่ง่ายที่สุด แต่ในความเร็วการอัปโหลดจริงกลับเห็น ความต่างระหว่าง S3 กับ ECR อย่างชัดเจน
  • เมื่อลองใส่ execution trace ลงในโค้ดเพื่อปรับแต่งประสิทธิภาพ ก็พบว่าเวลาที่ใช้ push เลเยอร์ไปยังคอนเทนเนอร์รีจิสทรีเป็นคอขวดสำคัญ

ผลการอัปโหลดเลเยอร์ขนาด 198 MiB

  • เบนช์มาร์กขนาดเล็กนี้เปรียบเทียบเวลาและอัตรารับส่งข้อมูลในการอัปโหลด เลเยอร์ขนาด 198 MiB ไปยัง ECR และ S3 ตามลำดับ
  • ความเร็วที่สังเกตได้มีดังนี้
    • ECR: ต่ำสุด 24 MiB/s, 8.2 วินาที
    • ECR: สูงสุด 28 MiB/s, 7.0 วินาที
    • S3: ต่ำสุด 115 MiB/s, 1.7 วินาที
    • S3: สูงสุด 190 MiB/s, 1.0 วินาที
  • จากผลลัพธ์ S3 เร็วกว่า ECR ได้สูงสุด 8 เท่า
  • โค้ดทดสอบรันอยู่บน AWS และทั้ง S3 กับ ECR เชื่อมต่อกันภายในผ่าน VPC โดยไม่ผ่านอินเทอร์เน็ตสาธารณะ
    • เงื่อนไขนี้ช่วยให้ได้ latency และแบนด์วิดท์ที่ดีที่สุดเท่าที่เป็นไปได้

ความต่างของความเร็วจากการอัปโหลดชังก์แบบขนาน

  • การอัปโหลดไปยัง S3 สามารถ อัปโหลดชังก์ของเลเยอร์เดียวแบบขนาน ได้
  • หากมีแบนด์วิดท์เพียงพอ การอัปโหลดชังก์แบบขนานจะเพิ่ม throughput ได้มาก
  • เอกสารของ AWS ก็แนะนำการอัปโหลดชังก์แบบขนานเพื่อใช้แบนด์วิดท์ให้เต็มประสิทธิภาพ
  • ECR นั้นอิมพลีเมนต์ OCI Distribution Spec
    • สเปกนี้คือมาตรฐานที่ทำให้ docker pull และ docker push ใช้งานข้ามหลายรีจิสทรีได้
    • การ push เลเยอร์ต้องดำเนินไปแบบลำดับ ดังนั้นแม้จะอัปโหลดเป็นชังก์ ก็ต้องรอให้ชังก์ก่อนหน้าจบก่อนจึงไปต่อชังก์ถัดไปได้
  • เมื่อทดสอบการอัปโหลดแบบลำดับบน S3 เช่นกัน throughput จะลดลงมาอยู่ในระดับ ใกล้เคียงกับ ECR

โครงสร้างคำขอจริงของ docker pull

  • คำขอภายในของ docker pull ประกอบด้วยคำขอ HEAD และ GET หลายรายการ
  • ตัวอย่างลำดับการทำงานมีดังนี้
    • ตรวจสอบว่ามี image manifest หรือไม่: HEAD /v2/my-image/manifests/latest
    • ดาวน์โหลด image manifest: GET /v2/my-image/manifests/latest
    • ดาวน์โหลดอีกครั้งโดยอ้างอิงแฮชของ manifest: GET /v2/my-image/manifests/sha256:...
    • ดาวน์โหลด blob เมทาดาทาของอิมเมจ: GET /v2/my-image/blobs/sha256:...
    • ดาวน์โหลด blob เลเยอร์ของอิมเมจ: GET /v2/my-image/blobs/sha256:...
  • โดยสรุปแล้ว docker pull ใกล้เคียงกับกระบวนการดาวน์โหลดไฟล์ที่จำเป็นผ่าน HTTP
  • หาก static file server วางไฟล์ที่ต้องใช้ไว้ในพาธที่คาดหวัง และตั้งค่าเฮดเดอร์ Content-Type ให้ตรงกับแต่ละคำขอ ก็จะสามารถ pull คอนเทนเนอร์อิมเมจได้
  • S3 bucket สามารถตอบโจทย์ทั้งสองเงื่อนไขนี้ได้ จึงอาจตั้งค่าอย่างระมัดระวังให้ทำงานเสมือนคอนเทนเนอร์รีจิสทรีได้

ข้อจำกัดของแนวทางเชิงทดลองนี้

  • วิธีนี้ยังถือเป็น การทดลอง และยังยากจะสรุปแบบหนักแน่นก่อนจะมีการตรวจสอบเพิ่มเติม
  • S3 ไม่ใช่คอนเทนเนอร์รีจิสทรีในความหมายที่เคร่งครัด
    • ไม่สามารถทำ docker push ได้
    • ที่ docker pull ใช้งานได้ เป็นผลจากโครงสร้างคำขอ HTTP และวิธีเสิร์ฟไฟล์แบบ static ที่สอดคล้องกัน
  • คอนเทนเนอร์รีจิสทรีทั่วไปมีความสามารถมากกว่าการอัปโหลดไฟล์ขึ้น bucket
    • เชื่อถือได้ว่าอิมเมจที่อัปโหลดผ่านวิธี push มาตรฐานนั้นถูกต้องจริง
    • สามารถมีการสแกนความปลอดภัยของเลเยอร์และแจ้งเตือนโดยอัตโนมัติ
    • กำหนดสิทธิ์เข้าถึงรีโพสิตอรีแบบ private ได้ในตัว
  • หากทำงานได้ตามที่คาดไว้ ก็อาจเปิดทางให้โฮสต์คอนเทนเนอร์อิมเมจแบบ public บน Cloudflare R2 ได้เช่นกัน

1 ความคิดเห็น

 
GN⁺ 2024-07-13
ความคิดเห็นบน Hacker News
  • รู้สึกเสียดายที่ OCI Distribution Spec อ่านแล้วไม่เหมือนสเปกที่ออกแบบมาอย่างดี
    ตามสเปก การ push เลเยอร์ต้องทำแบบลำดับต่อเนื่อง ดังนั้นถึงจะอัปโหลดแบบ chunk ก็ต้องรอให้แต่ละ chunk เสร็จก่อนถึงไปต่ออันถัดไปได้ จากที่ทดสอบกับ DockerHub และ GHCR ดูเหมือนว่าตัว chunk upload เองก็พังอยู่ดี และฝั่งไคลเอนต์ก็มักจะอัปโหลดแต่ละ blob/เลเยอร์แบบทั้งก้อนอยู่แล้ว อีกทั้งสเปกยังแนะนำรูปแบบค่า Content-Range ที่ไม่สอดคล้องกับรูปแบบ RFC7233 ด้วย
    แน่นอนว่ายังมีการทำงานขนานกันได้ในระดับ blob แต่ไม่มีการทำงานขนานภายใน blob และยังน่าเสียดายที่พลาดโอกาสในการ ทำมาตรฐาน pagination สำหรับรายการแท็กด้วย เพราะข้อความที่เกี่ยวข้องในสเปกถูกลบออกไปโดยไม่ตั้งใจ [1] ทำให้แต่ละ registry ไปทำกันคนละแบบ
    [1] https://github.com/opencontainers/distribution-spec/issues/4...

    • Docker และเทคโนโลยีรอบ ๆ คอนเทนเนอร์ส่วนใหญ่ก็เป็นแบบนี้แหละ ในฐานะประสบการณ์ผู้ใช้ Docker นั้นยอดเยี่ยม แต่ในฐานะเทคโนโลยีถือว่าเกือบจะเละเทะ
      ไม่ได้จะด่าเสียทั้งหมดนะ เพราะมันปฏิวัติวงการจริง ๆ ทำให้การใช้ Linux namespace ง่ายกว่าสมัยก่อนมาก และเปลี่ยนโลกไปในทางที่ดีขึ้น เพียงแต่มันให้ความสำคัญกับ ประสบการณ์ผู้ใช้ มากกว่าความสมบูรณ์ทางเทคนิคมาโดยตลอด ซึ่งตัวมันเองก็ไม่ใช่เรื่องแย่เสมอไป เหมือนกับที่มีบริษัทน่าเบื่อจำนวนมากแก้ปัญหาราคาแพงด้วย Perl หรือ CSV ที่ส่งกันผ่าน FTP เทคโนโลยีที่น่าเบื่อหรือกระทั่งแย่ ถ้าจัดแพ็กเกจมาดีก็สร้างคุณค่าได้มาก
      ถึงอย่างนั้นบางทีก็อดรู้สึกขมขื่นไม่ได้ว่ามันน่าจะดีกว่านี้ได้มาก
    • นอกจากนั้นก็ไม่แน่ใจว่าเป็นปัญหาของสเปก OCI หรือว่า AWS แปลกเอง แต่ต่างจาก GitLab หรือ Nexus ตรงที่ AWS ECR ไม่รองรับการสร้างโฟลเดอร์อัตโนมัติ
      ตัวอย่างเช่น รูปแบบอย่าง .dkr.ecr..amazonaws.com/foo/bar/baz:tag ใช้ไม่ได้ และเก็บได้แค่แบบแบน ๆ ทำให้ชื่ออิมเมจหรือแท็กยาวเกินจำเป็น ตามทฤษฎีก็พอจะสร้างอ็อบเจ็กต์ ECR repository ใน Terraform เพื่อเลียนแบบพฤติกรรมคล้าย ๆ กันได้ แต่ก็ไม่เหมาะกับ pipeline ที่เส้นทางอิมเมจเป็นแบบไดนามิก ต้องให้สิทธิ์กับ IAM role ของ CI pipeline มากเกินน่ารำคาญ และก็ไม่ชอบที่ทรัพยากร AWS ถูกจัดการอยู่นอกที่เก็บ Terraform ส่วนกลางด้วย
      [1] https://stackoverflow.com/questions/64232268/storing-images-...
  • Cloudflare เคยโอเพนซอร์ส เซิร์ฟเวอร์คอนเทนเนอร์รีจิสทรี ที่ใช้ R2
    เลยสงสัยว่ามีใครเคยลองใช้บ้างไหม
    [1]: https://github.com/cloudflare/serverless-registry

    • ดูดีอยู่ แต่เห็นว่ามี ข้อจำกัด 500MB ต่อเลเยอร์
      สำหรับบางการใช้งานอาจไม่ใช่ปัญหาใหญ่ แต่บางกรณีก็อาจตัดทิ้งได้ตั้งแต่แรก
  • ผู้เขียนเอง ถ้าใครรู้ว่าทำไมในสเปก OCI การ push เลเยอร์ถึงต้องเป็นแบบลำดับ ก็อยากให้ช่วยบอกที
    สงสัยว่าเป็นแค่อุบัติเหตุทางประวัติศาสตร์เฉยๆ หรือมีเหตุผลแฝงอยู่กันแน่ เพื่อให้ชัดเจน หลายเลเยอร์แน่นอนว่าสามารถ push แบบขนานกันได้ และที่พูดถึงตรงนี้คือส่วนที่ต้อง push เนื้อหาของเลเยอร์เดียว แบบตามลำดับ

    • อาจเป็นเพราะทำให้การจัดการเรียบง่ายขึ้น ถ้ายังไปไม่ถึงชังก์ “สุดท้าย” ก็ชัดเจนว่านี่คืออัปโหลดที่ไม่เสร็จหลัง N+Timeout และลบทิ้งได้
      เท่ากับลดความซับซ้อนของรายละเอียดการ implement ว่าจะจัดการ partial upload อย่างไร ไม่อย่างนั้นทุกครั้งที่จบแต่ละชังก์ ก็ต้องคอยตรวจว่าชังก์อื่นมาครบหมดหรือยังแล้วค่อยปิดงาน แต่ก็ยังเป็นรายละเอียดระดับ implementation และก็น่าสงสัยว่าเป็นการออกแบบที่มีความหมายหรือตั้งใจไว้จริงหรือไม่ แนวทางแบบ S3 ดูน่าจะใช้ได้ดี และเคยทำอะไรคล้ายกันมาก่อนตอนอยู่บริษัทที่แจกจ่ายอิมเมจขนาดใหญ่ สุดท้ายค่าใช้จ่าย 0.10 ดอลลาร์ต่อ GB ต่อเดือน สะสมขึ้นมาไม่น้อย
      แม้จะเสียฟีเจอร์เสริมของ ECR ไป แต่ส่วนตัวมองว่าฟีเจอร์พวกนั้นค่อนข้างจำกัด
    • ไม่เคยทำฝั่ง push มาก่อน แต่ชอบแนวทางนี้มาก ยุคแรกๆ ของ Docker ยังไม่มีคอนเทนเนอร์ private registry ที่ใช้งานได้ดีนัก ก็เลยเคย วางอิมเมจไว้หลัง nginx แล้ว pull เลย ทำให้อ่านบทความนี้สนุกมาก
    • เคย implement รีจิสทรีที่เข้ากันได้กับ OCI [1] และสเปกซับซ้อนมากจนส่วนใหญ่ต้องตามพฤติกรรมของ reference implementation [2] มากกว่าตามสเปก
      ตอนที่ไคลเอนต์ปิดการอัปโหลด blob จะต้องส่ง digest ของ blob ทั้งก้อนมาด้วย ข้อกำหนดนี้ดูเหมือนมีไว้เพื่อให้เซิร์ฟเวอร์ตรวจสอบความถูกต้องของไบต์ที่ได้รับได้ ถ้าเซิร์ฟเวอร์เพิ่งเริ่มตรวจ digest ใน HTTP request สุดท้าย ก็ต้องย้อนกลับไปอ่านเนื้อหา blob ทั้งหมดที่เขียนลง storage จาก HTTP request ก่อนหน้าอีกครั้ง ซึ่งกับเลเยอร์ขนาดใหญ่ latency แบบนี้อาจรับไม่ไหว เคยตรวจให้รองรับได้ถึง 150GiB blob เพราะมีความต้องการจากไคลเอนต์บางราย
      ดังนั้นใน implementation จึงคำนวณ digest ต่อเนื่องตลอดทั้งลำดับของ request ไปเลย รับข้อมูล blob เป็นชังก์ๆ พร้อมกับคำนวณ digest และสตรีมลง blob storage ไปพร้อมกัน ระหว่างแต่ละ request จะ serialize สถานะการคำนวณ digest ใส่ไว้ใน upload URL ที่ส่งกลับไปให้ไคลเอนต์ผ่าน Location header จัดการประมาณนี้ในโค้ด: https://github.com/sapcc/keppel/blob/7e43d1f6e77ca72f0020645...
      เท่าที่ทราบ reference implementation ก็ใช้แนวทางเดียวกัน การคำนวณ digest ทำได้แบบลำดับเท่านั้น ดังนั้นการอัปโหลดจึงต้องดำเนินไปแบบลำดับด้วย
      [1] https://github.com/sapcc/keppel
      [2] https://github.com/distribution/distribution
    • ขอบคุณสำหรับบล็อกโพสต์ ในบทความบอกว่า “ตลอด 4 เดือนที่ผ่านมาได้ร่วมงานกับ Outerbounds เพื่อพัฒนาตัวสร้างคอนเทนเนอร์อิมเมจแบบกำหนดเอง” ถึงจะบอกว่าเป็นหัวข้ออีกโพสต์หนึ่ง แต่ก็อยากรู้รายละเอียดเพิ่มเติมสักหน่อยได้ไหม
      ถ้ามีลิงก์ไปยัง GitHub repository ด้วยจะดีมาก ที่ถามเพราะกำลังหาวิธีสร้าง OCI image แบบเป็นโปรแกรมใน $PROGRAMMING_LANGUAGE หรือไม่ก็คิดจะลงมือทำเอง อยากได้อะไรคล้าย Buildah แต่เป็น API สำหรับภาษาโปรแกรมจริงๆ ไม่ใช่ command-line interface แน่นอนว่าจะเรียก Buildah เป็น subprocess ก็ได้ แต่ค่อนข้างยุ่งยาก ต้องคอยจัดการปฏิสัมพันธ์กับสถานะภายในของ Buildah และการ cleanup ด้วย อีกทั้งตอนนี้ Buildah ก็ยังไม่รองรับ Mac
    • นึกเหตุผลชัดๆ ไม่ออกเหมือนกัน อาจเกี่ยวกับภาระโหลดก็ได้
      จำได้รางๆ ว่าเมื่อก่อนเหมือนเคยเพิ่ม parallel push ให้ Docker แต่อาจกำลังสับสนระหว่าง pull กับ push พอกลับไปดูอีกที งานที่เคยทำไม่ใช่การ push ขั้นสุดท้าย แต่เป็น การทำตรวจสอบแบบขนาน มากกว่า ถ้ามีการระบุว่าเลเยอร์หนึ่งอยู่ “บน” เลเยอร์ไหน ก็อาจเป็นเพราะ ID ที่อ้างถึงต้องมีอยู่ก่อนแล้วก็ได้
  • เป็น use case ที่เจ๋งมาก
    ส่วนตัวผมใช้ Nexus ไปเลย มันทำงานได้ดีพอสมควร และรองรับตั้งแต่ OCI image, apt package, Maven แบบกำหนดเอง, NuGet, ไปจนถึง npm repository เพียงแต่การตั้งค่าและการใช้ทรัพยากรค่อนข้างน่าปวดหัว โดยเฉพาะเรื่อง นโยบายการ cleanup: https://www.sonatype.com/products/sonatype-nexus-repository
    แต่ถึงอย่างนั้น สิ่งที่ดีมากจริงๆ คือ docker pull มัน “ก็แค่” ชุดของคำขอ HEAD กับ GET เท่านั้น เป็นการเอาสิ่งที่ใช้ได้ดีมานานแล้วมาใช้ต่อ โดยไม่ทำให้ซับซ้อนเกินจำเป็น อยากเห็นการตัดสินใจแบบมีสามัญสำนึกเช่นนี้ในเทคโนโลยีอื่นๆ มากกว่านี้ น่าแปลกที่คอนเทนเนอร์สโตร์แบบเรียบง่ายที่มีทั้งการยืนยันตัวตนและฟีเจอร์ cleanup กลับมีไม่มากนัก ทั้ง Nexus และ Harbor ต่างก็ซับซ้อนพอสมควรถ้าจะเอามาใช้งานจริง

    • ผมใช้ Gitea สำหรับแพ็กเกจอย่างเดียว รองรับ Docker, npm, Python ฯลฯ
      แปลกใจเหมือนกันที่ไม่มีใครพูดถึงในเธรดนี้เลย
  • CNCF Distribution หรือ Docker Registry เดิม มีฟังก์ชันรองรับรีจิสทรีด้วย CloudFront signed URL ที่ดึงจาก S3 อยู่แล้ว [1]
    https://distribution.github.io/distribution/storage-drivers/...

  • สงสัยว่า https://github.com/distribution/distribution มีปัญหาอะไร

    • อันนี้ไม่เคยเห็นมาก่อน และมันก็รองรับ S3 จริงๆ แหละ แต่สงสัยว่ามันให้ไคลเอนต์ดาวน์โหลดจาก S3 โดยตรงหรือเปล่า หรือแค่ใช้ S3 เป็น storage backend ภายในของตัวเอง แล้วตอน pull ก็ทำตัวเหมือน พร็อกซี อยู่ดี
  • วิธีนี้ดูแพงมาก และน่าจะดีถ้าบทความพูดถึงเรื่อง ต้นทุน ด้วย อยากรู้ทั้ง S3 และ R2

    • S3 Standard คิดค่าจัดเก็บต่อ GB อยู่ที่ประมาณ 1 ใน 5 ของ ECR
      ค่าทราฟฟิกขาออกสู่อินเทอร์เน็ตสาธารณะเท่ากัน แต่ ECR แบบ public มีข้อยกเว้นคือทราฟฟิกที่ออกไปสำหรับการใช้งานภายใน AWS นั้นฟรี
    • สุดท้ายแล้วต้นทุนก็คือต้นทุนของ S3 ขึ้นอยู่กับรีเจียนและ storage tier แต่สามารถดูค่าจัดเก็บต่อ GB, ค่า GET/PUT และค่าแบนด์วิดท์ได้จากเว็บไซต์ AWS: https://aws.amazon.com/s3/pricing/
  • นอกเหนือจากเครื่องมือพัฒนาแล้ว ผมไม่ได้ใช้ Docker มากนัก แต่ไม่เคยเข้าใจว่าทำไม private container registry ถึงต้องมีอยู่
    มันดูเหมือนการแสวงหาค่าเช่าเฉยๆ เลยสงสัยว่าจริงๆ แล้วมันมีข้อดีอะไร เมื่อเทียบกับการทำไฟล์อิมเมจที่จัดการเองแล้วใช้งานตามต้องการ

    • ไม่จำเป็นต้องใช้ก็ได้ ใช้ docker save และ docker import ก็พอ
      docker save alpine:3.19 > alpine.tar
      docker load < alpine.tar
      แต่จากนั้นก็ต้องมาจัดการไฟล์ tar นั้นเอง และทุกระบบต้องรู้ว่ามันอยู่ที่ไหนและจะเข้าถึงอย่างไร หรือจะไม่ต้องประดิษฐ์ล้อใหม่แล้วใช้วิธีที่ Docker มีให้อยู่แล้วก็ได้
    • มีโอกาสสูงว่าจะมีอิมเมจที่ไม่อยากเผยแพร่สู่สาธารณะ ซึ่งปกติอิมเมจแบบนั้นต้องให้โครงสร้างพื้นฐานอย่างคลัสเตอร์ k8s หรือ CI/CD runner เข้าถึงได้
      ดังนั้นจึงต้องสร้าง registry เองหรือจ่ายเงินให้คนอื่นดูแลให้ แน่นอนว่าถ้าใช้อิมเมจเพื่อการพัฒนาอย่างเดียว เรื่องพวกนี้ก็ไม่มีความหมาย แค่เก็บอิมเมจไว้ในเครื่องพัฒนาก็พอ
    • เหตุผลเดียวกับที่เราไม่ส่งไฟล์กันทางอีเมลแทนการใช้ที่เก็บโค้ด
      เพราะต้องมีที่เก็บส่วนกลางที่มีเวอร์ชันเก่าทั้งหมดและให้ผู้ใช้งานหลายรายเข้าถึงได้ง่าย คุณคงไม่อยากคอย push แอปที่ build แล้วไปยังทุกที่ที่มันอาจถูกรัน แค่ build ครั้งเดียวแล้ว push ไปที่เก็บส่วนกลาง จากนั้นให้ทุกที่อ้างอิงที่เก็บนั้นก็พอ
      และก็ไม่จำเป็นต้องจ่ายเงินสำหรับโฮสต์ private registry เสมอไป เพราะมีเครื่องมือสำหรับโฮสต์เองอยู่มากมาย
    • private cloud registry มีประโยชน์มากสำหรับโปรเจกต์ที่มีข้อกำหนดด้าน authentication/authorization ที่จำเป็นเกี่ยวกับ Docker image
      สามารถตั้งค่าทั้งหมดแยกตาม environment ได้ด้วย Terraform, Bicep, Pulumi
    • ประเด็นคือจะจัดการมันอย่างไรด้วย ถ้าอยากใช้เครื่องมือเดียวกับที่ใช้กับ public image ก็แค่รัน container registry ขึ้นมา
  • ECR ดูเหมือนถูกออกแบบมาให้สามารถอัปโหลด image layer แบบแบ่งเป็นหลายส่วนได้จริง
    API ของ ECR ที่เกี่ยวข้องมี InitiateLayerUpload API ที่เรียกตอนเริ่มอัปโหลดแต่ละ image layer, UploadLayerPart API ที่เรียกสำหรับแต่ละ chunk ของ layer (สูงสุด 20MB) และ PutImage API ที่ push image manifest ซึ่งมีการอ้างอิงถึง image layer หลังอัปโหลด layer เสร็จแล้ว จุดแปลกคือการอัปโหลด layer chunk ต้องใช้ base64 encoding ทำให้ข้อมูลเพิ่มขึ้นประมาณ 33%

    • ผมเคยใช้ API นั้นโดยตรงแล้ว แต่น่าเสียดายที่แม้ที่นั่นก็ยังบังคับให้ อัปโหลดตามลำดับ
  • ไอเดียที่ใช้การจัดวาง file path เป็นวิธีควบคุม endpoint น่าสนใจ
    แต่อยากรู้ว่าจะจัดการ Docker-Content-Digest header อย่างไร แม้จะไม่บังคับ แต่แนะนำให้ใส่ไว้ใน response และ client จำนวนมากก็คาดหวังมันอยู่ โดยอาจปฏิเสธ layer ที่ไม่มี header นี้ได้ อีกทั้งฟีเจอร์อย่าง referrers API ในสเปก OCI 1.1 ก็อาจหายไปด้วย ดูเหมือนจะ implement ได้ค่อนข้างยาก