

ตอนแยกงานใน pipeline เรามักมีไฟล์ที่อยากให้ขั้นถัดไปหยิบใช้ต่อ ทั้ง dependency ที่เพิ่งดาวน์โหลดและผลบิ้วที่ต้องทดสอบ ถ้ามองเพียงว่าเป็นไฟล์เหมือนกัน ก็อาจเลือกที่เก็บเดียวแล้วค่อยพบว่าการรันใหม่ได้ของไม่ตรงกับรอบที่ตั้งใจ
GitLab มีทั้ง cache กับ artifact ให้ใช้ครับ แต่คำถามก่อนเลือกคือไฟล์นั้นช่วยประหยัดงานที่สร้างใหม่ได้ หรือเป็นผลลัพธ์ของ job ที่ขั้นถัดไปต้องใช้ให้ตรงตัว สองหน้าที่นี้มีผลต่อวิธีตั้ง key อายุ และการตามที่มาของไฟล์
เมื่อแยกได้ pipeline จะยังทำงานถูกในวันที่ cache ไม่มี และรู้ด้วยว่าผลทดสอบอ้างถึงชิ้นงานใดจริง ไม่ใช่หยิบไฟล์ที่บังเอิญเหลืออยู่จากรอบก่อน
ตัวอย่างที่เหมาะกับ cache คือข้อมูล dependency ที่เครื่องมือดาวน์โหลดแล้วสามารถหาใหม่ตาม lockfile และแหล่งที่กำหนด การมี cache ช่วยลดการดาวน์โหลดซ้ำ แต่ไม่ควรถูกใช้เป็นแหล่งเดียวของผลบิ้วที่ไม่มีวิธีระบุรอบ
ถ้า cache ว่าง งานควรยังติดตั้ง dependency และเดินต่อได้ตามเงื่อนไขปกติ ส่วนเวลาอาจต่างออกไป หาก pipeline ทำงานผิดทันทีเพราะไฟล์สำคัญเคยถูกฝากไว้ใน cache อย่างเดียว ก็ควรทบทวนว่ากำลังใช้มันแทนการส่งผลลัพธ์อยู่หรือไม่

Cache ยังเกี่ยวกับ runner และที่เก็บที่ตั้งไว้ด้วย การรันคนละเครื่องหรือเปลี่ยนการตั้ง distributed cache อาจทำให้ได้หรือไม่ได้สำเนา จึงไม่ควรออกแบบความถูกต้องของงานโดยสมมติว่าจะได้ cache เดิมทุกครั้งแน่นอน
ตรวจด้วยว่า path ที่ cache เป็นสิ่งที่เครื่องมือต้องการเก็บจริง เช่น โฟลเดอร์ cache ของ package manager อาจเหมาะกับวิธีติดตั้งมากกว่าเก็บ directory dependency โดยไม่คิดถึง runtime หรือ architecture ของ runner ที่เปลี่ยนได้
ถ้าขั้น build สร้างผลลัพธ์ที่ขั้นทดสอบต้องใช้ ไฟล์นั้นควรถูกเก็บและรับต่ออย่างรู้ว่ามาจาก job ใดใน pipeline ไม่หวังให้ cache key กว้างๆ คืนของรอบล่าสุดที่เขียนสำเร็จมาแทน
Artifact ใช้เก็บได้ทั้งผลบิ้วและรายงานตามการตั้งค่า เมื่อมีงานหลายชุด ควรกำหนดการรับจาก job ที่เกี่ยวข้องให้ชัด ไม่ดึงทุกอย่างจากขั้นก่อนหน้าโดยไม่รู้ว่ามีไฟล์ชื่อเดียวกันหรือของที่ไม่ต้องใช้รวมมาด้วยหรือไม่
การทำให้ขั้นทดสอบใช้ชิ้นงานเดียวกับที่จะส่งต่อยังช่วยเรื่องหลักฐาน หากทดสอบ source ใหม่อีกรอบแล้วบิ้วใหม่ตอน deploy ผลที่ทดสอบกับผลที่รันอาจต่างกัน แม้ commit ดูเป็นตัวเดียวกันก็ตาม
แต่ artifact ของ job ก็ไม่จำเป็นต้องเป็นที่เก็บ release ระยะยาวทุกประเภท หากต้องแจกจ่ายเป็นรุ่นและรักษาตามนโยบายปล่อยงาน ควรเลือก package หรือ container registry ที่เหมาะสม พร้อมบันทึกความสัมพันธ์กลับมายัง pipeline
หาก dependency เปลี่ยนแต่ใช้ key เดิม งานอาจต้องเสียเวลาแก้ cache ที่ไม่เข้ากัน หรือเสี่ยงเกิดปัญหาจากสิ่งที่เก็บไว้ต่างสภาพ ควรเลือก key ตาม lockfile กับเงื่อนไขเครื่องมือที่มีผลต่อความเข้ากัน ไม่ใช้คำว่า default เป็นคำตอบทุกโปรเจกต์

แยกขอบเขตของ branch หรือระดับความเชื่อถือด้วยตามนโยบาย runner และ GitLab เพราะการให้หลายงานเขียนที่เก็บร่วมกันมีเรื่องทั้งการทับข้อมูลและสิ่งที่นำกลับมาใช้อีกครั้ง ไม่ควรเปิดกว้างเพียงเพื่อเพิ่มอัตรา cache hit
สำหรับ job ที่ต้องอ่านอย่างเดียว อาจใช้ policy ที่ไม่ให้เขียนกลับตามรูปแบบที่รองรับ ส่วน job ที่สร้างข้อมูลใหม่ก็ต้องรู้ว่ามีใครเขียน key เดียวกันพร้อมกันหรือไม่ การตั้งสิทธิ์กับผู้รับผิดชอบ cache จึงเป็นส่วนหนึ่งของการออกแบบ pipeline
ควรดูผลเวลาทั้งดึงและบีบเก็บกลับด้วย Cache ที่ใหญ่มากอาจสร้างงานโอนเพิ่มจนไม่คุ้มกับสิ่งที่ประหยัด ต้องวัดตามไฟล์และที่เก็บจริง ไม่ถือว่าการมี cache มากขึ้นทำให้ทุก job เร็วขึ้นเสมอ
ตัวอย่างส่วนหนึ่งของ job สมมติ สำหรับโปรเจกต์ที่มี Node.js พร้อมบน runner ใช้ npm และบิ้วออก dist/:
build:
cache:
key:
files:
- package-lock.json
paths:
- .npm/
script:
- npm ci --cache .npm --prefer-offline
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week
ในตัวอย่าง .npm/ ช่วยติดตั้งซ้ำ ส่วน dist/ เป็นผลจาก build ของ job นี้ ต้องเปลี่ยน path และวิธีติดตั้งให้ตรงโปรเจกต์จริง รวมถึงกำหนด job ที่รับผลต่อให้ชัด ตัวอย่างไม่ได้หมายความว่า framework ทุกตัวออกไฟล์ชื่อ directory เดียวกัน
เวลาเก็บหนึ่งสัปดาห์ก็เป็นนโยบายตัวอย่าง ต้องเทียบกับเวลาที่ทีมต้องใช้ตรวจและส่งต่อ รวมถึงการตั้ง retention ของ instance ที่อาจมีผลด้วย อย่านำอายุไฟล์ชั่วคราวไปเป็นคำรับรองว่ามี release สำหรับ rollback อยู่ตลอดระยะเดียวกัน
ทั้ง cache กับ artifact อาจรับไฟล์ที่เผลอมี token หรือค่าตั้งรวมอยู่หากเลือก path กว้าง ควรส่งออกเฉพาะสิ่งที่มีหน้าที่ต่อขั้นถัดไป และตรวจว่าไฟล์ log หรือรายงานไม่ได้พาความลับที่อ่านระหว่าง build ติดออกมาด้วย
เมื่อ job ล้มเหลว ควรกำหนดว่าเก็บรายงานใดตามความจำเป็น ไม่เก็บ directory ทำงานทั้งก้อนเพียงเพื่อให้มีอะไรช่วย debug เพราะอาจรวมข้อมูลมากกว่าที่ผู้มีสิทธิ์อ่าน artifact ควรได้รับ
ลองรันในสภาพที่ cache ไม่มีและตรวจการรับ artifact ของ pipeline เดิม จะช่วยยืนยันสองสัญญาที่ต่างกัน คือสร้าง dependency ใหม่ได้ และใช้ผลบิ้วตรงรอบที่ต้องการ ภาพประกอบในบทนี้เป็นขอบเขตหน้าที่ ไม่มีผลเวลาของ pipeline จริง
เลือก cache สำหรับของที่ช่วยลดงานซ้ำและสร้างใหม่ได้ ส่วน artifact ใช้ส่งผลของ job ให้ขั้นถัดไปอย่างตามที่มาได้ จัด key ขอบเขต อายุ และไฟล์ที่เก็บตามหน้าที่ พร้อมตรวจทั้งรอบไม่มี cache กับการรับผลที่ตรง pipeline เมื่อสองทางนี้ชัด เราจะปรับความเร็วได้โดยยังรักษาความถูกต้องของสิ่งที่ทดสอบและนำไปใช้งานครับ