ข้ามไปยังเนื้อหาหลัก

รัน pipeline ในเครื่องของคุณ

loha run --local รัน job ใน .loha.yml ของคุณใน container บนเครื่องของคุณเอง เพื่อให้เห็นว่าขั้นตอนใดล้มเหลว (หรือผ่าน) ก่อนที่คุณจะ push คำสั่งนี้รัน plan เดียวกัน กับที่ loha plan แสดง ได้แก่ อิมเมจ สคริปต์ user id capability ไดเรกทอรีทำงาน และขีดจำกัด CPU กับหน่วยความจำชุดเดียวกัน ซึ่งเซิร์ฟเวอร์ของ Loha เป็นผู้สร้าง มีเพียงส่วนที่เครื่องส่วนตัวไม่มีเท่านั้นที่ถูกแทนที่ และสรุปท้ายการรันจะบอกให้ทราบว่าส่วนใด

การรันในเครื่องเป็นเรื่องของเครื่องคุณเท่านั้น ไม่สร้างบิลด์บนแพลตฟอร์ม ไม่รายงานอะไรกลับไป และไม่ส่งคำขอใดนอกจากคำขอ plan

การรันในเครื่องเปิดให้ทุกเวิร์กสเปซ

loha run --local เป็นส่วนหนึ่งของฟีเจอร์ local run ซึ่งเปิดเป็นค่าเริ่มต้น หากผู้ดูแลแพลตฟอร์มของ Loha ปิดไว้สำหรับเวิร์กสเปซของคุณ คำสั่งจะหยุดพร้อมข้อความ Local runs are not enabled for this workspace. Ask a workspace admin to turn on local_run. และออกด้วยโค้ด 2

ก่อนเริ่มใช้​

ต้องมี container engine และ checkout ของรีโพสิทอรีที่ onboard กับ Loha แล้ว เช่นเดียวกับ loha plan

  • Docker Desktop และ Docker Engine เป็น engine ที่ผ่านการทดสอบ ค่าเริ่มต้นคือ docker
  • Podman ใช้ได้แบบ best-effort เลือกด้วย --engine podman หรือ LOHA_CONTAINER_ENGINE=podman (แฟล็กมีผลเหนือกว่า)
  • หากไม่มี engine คำสั่งจะออกด้วยโค้ด 3 พร้อมข้อความ No container engine found. Install Docker Desktop or Docker Engine, or pass --engine podman. ก่อนติดต่อเซิร์ฟเวอร์ หากติดตั้ง engine แล้วแต่ยังไม่ทำงาน ข้อความของ engine เองจะถูกพิมพ์ก่อน
  • อิมเมจถูก pull จากรีจิสทรีของมัน (ดูว่า pull เมื่อใดใน หมายเหตุเกี่ยวกับ engine) อิมเมจจากรีจิสทรีของเวิร์กสเปซต้องใช้ docker login ของคุณเอง Loha ไม่ส่งข้อมูลยืนยันตัวตนของรีจิสทรีให้ CLI

วิธีใช้​

รันจากภายใน checkout:

loha run --local
Run local-3f9c2ab1, logs in /home/you/app/.loha/local-runs/local-3f9c2ab1/logs
Job test
✓ test/wait-for-services (3.4s)
✓ test/checkout (0.9s)
[test/migrate] applying 12 migrations
✓ test/migrate (5.1s)
[test/unit] 148 passed
✓ test/unit (41s)

JOB STEP MODE RESULT TIME
test checkout emulated passed 0.9s
test migrate run passed 5.1s
test unit run passed 41s

≠ Source: staged working tree, not a clone of the pushed commit
≠ Network: this machine's network, not build-pod egress rules
≠ Services: containers sharing one network namespace, not pod sidecars

ค่าข้างต้นเป็นตัวอย่าง เอาต์พุตของ container แสดงเป็น [job/step] line โดยใช้ชื่อ job และขั้นตอนเดียวกับหน้าบิลด์ โดยค่าเริ่มต้น job รันทีละตัวตามลำดับ needs ส่วน matrix รันทีละชุดต่อกัน และ --parallel N ให้รัน job ที่พร้อมแล้วพร้อมกันได้สูงสุด N ตัว (ดู Parallel job) job และขั้นตอนที่ปิดอยู่จะแสดงพร้อมเหตุผล ซึ่งเป็นข้อความเดียวกับที่ loha plan พิมพ์

เมื่อเซิร์ฟเวอร์ส่งผลของ trigger มา การรันจะพิมพ์ก่อนว่าบล็อก on: ของ pipeline ทำอะไรกับ event ที่คุณ plan: ! On: would fire (<reason>) หรือ ! On: would not fire (<reason>) แล้วรันต่อไปไม่ว่ากรณีใด เพราะการรันในเครื่องเป็นของคุณที่จะเริ่มเมื่อไรก็ได้ loha plan พิมพ์คำตอบเดียวกันเป็นบรรทัด On:

แฟล็ก​

แฟล็กของ plan เป็นชุดเดียวกับ loha plan และมีความหมายเหมือนกัน คือกำหนดว่าจะรัน plan ใด

แฟล็กใช้ทำอะไร
--localจำเป็นต้องระบุ loha run ที่ไม่มีแฟล็กนี้จะแสดงคำแนะนำให้ใช้ loha deploy และออกด้วยโค้ด 2
--file, --branch, --event, --sha, --repo, --trigger, --var KEY=VALUEแฟล็กของ plan เหมือน loha plan
--base <branch>, --tag <tag>จำลอง branch ปลายทางของ pull request (--event pull_request) หรือ tag ที่ถูก push (--event tag) เหมือน loha plan ใช้กับ event อื่นเป็นข้อผิดพลาดการใช้คำสั่ง
--engine docker|podmancontainer engine (ค่าเริ่มต้น: LOHA_CONTAINER_ENGINE ถ้าไม่มีใช้ docker)
--job <id>รันเฉพาะ job นี้และ job ที่ต้องใช้ ระบุซ้ำได้
--parallel Nรัน job ที่พร้อมแล้วพร้อมกันได้สูงสุด N ตัว ตั้งแต่ 1 ถึง 16 (ค่าเริ่มต้น 1) ใช้ร่วมกับ --mount-source ไม่ได้ (ดู Parallel job)
--matrix KEY=VALUEรันเฉพาะ instance ของ matrix ที่มีค่านี้ ระบุซ้ำได้ ต้องตรงทุกค่า (ดู Matrix)
--step <job>/<step>รันเฉพาะขั้นตอนนี้ ต้องใช้ --reuse (ดู รันขั้นตอนซ้ำและเปิด shell)
--from <job>/<step>รันขั้นตอนนี้และทุกขั้นตอนหลังจากนั้น ต้องใช้ --reuse ใช้ร่วมกับ --step ไม่ได้
--reuse <volume>ใช้ volume ของซอร์สที่การรัน --keep ครั้งก่อนทิ้งไว้เป็นพื้นที่ทำงานตามสภาพที่เป็นอยู่
--shell <job>/<step>รันทุกอย่างก่อนขั้นตอนนั้น แล้วเปิด /bin/sh ใน container ของมันแทนการรันขั้นตอน ต้องมีเทอร์มินัล ใช้ร่วมกับ --json, --step, --from หรือ --parallel ไม่ได้
--approveอนุมัติทุก approval gate โดยไม่ถาม (ดู Approval)
--secret NAMEให้ขั้นตอนต่าง ๆ ได้ secret ชื่อ NAME โดยอ่านค่าจากตัวแปรสภาพแวดล้อมชื่อเดียวกันของคุณ ระบุซ้ำได้
--env-file <path>ไฟล์บรรทัด KEY=VALUE ที่ให้ค่า secret และตัวแปรทั่วไปที่ plan ไม่แสดงค่า (ดู Secret และตัวแปร)
--mount-sourcemount working tree ของคุณโดยตรงแทนการคัดลอก เร็วกว่า แต่ผลลัพธ์จากการ build จะถูกเขียนลงใน working tree และผลอาจต่างจากคลัสเตอร์
--committed-onlyใช้ไฟล์ pipeline และซอร์สจาก HEAD โดยไม่สนใจการแก้ไขในเครื่อง ใช้ร่วมกับ --mount-source ไม่ได้
--no-limitsไม่ใช้ขีดจำกัด CPU และหน่วยความจำของ plan
--platform linux/amd64รัน container สำหรับ platform นี้ (จำลองเมื่อต่างจากเครื่องของคุณ)
--keepเก็บ volume ของซอร์สไว้หลังรันและพิมพ์ชื่อ
--jsonพิมพ์ event แบบ JSON หนึ่งรายการต่อบรรทัดบน stdout แทนข้อความ (ดู เอาต์พุตสำหรับเครื่องอ่าน)

คำสั่งที่ใช้ร่วมกันไม่ได้จะถูกปฏิเสธด้วยโค้ด 2 ก่อนเริ่ม engine และก่อนส่งคำขอใด ๆ ได้แก่ --parallel นอกช่วง 1 ถึง 16, --step หรือ --from โดยไม่มี --reuse, --step พร้อม --from, --shell พร้อม --json, --step, --from หรือ --parallel, --shell เมื่อ stdin และ stdout ไม่ใช่เทอร์มินัลทั้งคู่ (--shell needs an interactive terminal.), --reuse หรือ --parallel พร้อม --mount-source, รายการ --matrix ที่ไม่ใช่ KEY=VALUE หรือซ้ำคีย์, --tag กับ event อื่นที่ไม่ใช่ tag และ --base กับ event อื่นที่ไม่ใช่ pull_request สิ่งที่มีแต่ plan ที่ตรวจได้ เช่น job หรือขั้นตอนที่ไม่มีอยู่ หรือตัวเลือก --matrix ที่ไม่ตรงกับอะไรเลย (รวมถึงค่าว่าง --matrix KEY=) ก็ออกด้วยโค้ด 2 เช่นกัน ทันทีที่ทราบ plan เช่นเดียวกับ volume ของ --reuse ที่ไม่มีอยู่ หรือไม่ใช่ volume ของการรัน loha ที่ถูกเก็บไว้ของรีโพสิทอรีนี้

โค้ดทางออก​

โค้ดความหมาย
0ทุกขั้นตอนที่เปิดอยู่ผ่าน
1ขั้นตอนล้มเหลวหรือหมดเวลา ยกเลิกด้วย Ctrl-C หรือเตรียมการรันไม่สำเร็จ (เช่น engine ล้มเหลวขณะสร้าง workspace)
2plan ถูกปฏิเสธ (พิมพ์ข้อผิดพลาดของเซิร์ฟเวอร์เหมือน loha plan) หรือใช้คำสั่งผิด: ไม่มี --local แฟล็กหรือชุดแฟล็กไม่ถูกต้อง เป้าหมาย --job, --step, --from, --shell หรือ --matrix ที่ไม่มีอยู่ volume ของ --reuse ที่ถูกปฏิเสธ ไม่มีตัวแปรสภาพแวดล้อมของ --secret ยังไม่เปิดการรันในเครื่อง หรือข้อผิดพลาดของเซิร์ฟเวอร์หรือการยืนยันตัวตน
3ไม่มี container engine หรือ engine ไม่ทำงาน

ขั้นตอนที่ออกด้วยโค้ด 137 จะแสดงเป็น killed: likely out of memory at the <class> limit (<memory>) ซึ่งระบุคลาสทรัพยากรของ job และขีดจำกัดหน่วยความจำ เพื่อให้แยกได้ว่าเป็นการถูกฆ่าจากหน่วยความจำไม่พอ ไม่ใช่เทสต์ล้มเหลว เมื่อใช้ --no-limits หรือเมื่อ plan ไม่ได้กำหนดขีดจำกัดหน่วยความจำ จะแสดงเป็น killed (exit 137), possibly out of memory

ขั้นตอนแบบสคริปต์ที่ออกด้วยโค้ด 126, 127 หรือ 255 จะแสดงเป็น exited with code <n>; the image may have no /bin/sh (the step's script needs one) เพราะสคริปต์ถูกรันด้วย /bin/sh อิมเมจที่ไม่มี shell (เช่นอิมเมจ scratch หรือ distroless) จึงรันสคริปต์ run: ไม่ได้ ให้ใช้อิมเมจที่มี shell หรือใช้ขั้นตอนที่ระบุ command

เมื่อ job ล้มเหลวก่อนที่ขั้นตอนใดจะเริ่ม เช่น service เริ่มไม่ขึ้น เอาต์พุตแบบข้อความจะพิมพ์ ✗ <job>: <reason> เพื่อให้เห็นสาเหตุบนหน้าจอ ไม่ใช่เฉพาะในไฟล์ log

อะไรถูกรันบ้าง​

แต่ละขั้นตอนมี badge ใน loha plan และการรันในเครื่องทำตาม badge นั้น

  • ขั้นตอน run รันตามที่เขียน ใช้อิมเมจและสคริปต์เดียวกัน ใน container ที่เริ่มด้วย user ของ plan, --cap-drop ALL พร้อม capability ที่ plan ขอ, --security-opt no-new-privileges และขีดจำกัด CPU กับหน่วยความจำของ job ขีดจำกัดหน่วยความจำถูกส่งเป็น --memory-swap ด้วย container จึงใช้ swap เกินขีดจำกัดไม่ได้ เพราะ node ของคลัสเตอร์ไม่มี swap ขั้นตอนที่หน่วยความจำไม่พอบนคลัสเตอร์จึงหน่วยความจำไม่พอในเครื่องด้วย container ไม่เคยรันแบบ privileged
  • ขั้นตอน emu ถูกแทนด้วยของที่เทียบเท่าในเครื่อง การ checkout ถูกแทนด้วยการ stage ซอร์สของคุณ (ดู ซอร์ส) task cache cache@v2, upload-artifact และ job output ที่ artifacts-save กับ artifacts-restore ส่งต่อ รันสคริปต์จริงกับเซิร์ฟเวอร์เล็ก ๆ บนเครื่องของคุณ (ดู Cache และ Job output และ artifact) การ build อิมเมจ (buildah-build, docker-build) ถูก build ด้วย container engine ของคุณ (ดู การ build อิมเมจ) และ approval gate จะถามคุณในเทอร์มินัล (ดู Approval)
  • ขั้นตอน skip ไม่รันบนเครื่องของคุณ ได้แก่ สิ่งที่ push, deploy, แจ้งเตือน หรือเซ็นชื่อ และ security gate ที่ Loha จัดการ git-clone ของรีโพสิทอรีนี้ถูกจดจำจาก path group/project ดังนั้น SSH host alias หรือ URL ของ mirror ก็ยังนับว่าเป็นรีโพสิทอรีนี้ การ clone รีโพสิทอรีอื่นจะถูกข้ามพร้อมข้อความ Clones another repository; not available locally. และมีหมายเหตุระบุ URL ทั้งสอง (ไม่รวมข้อมูลรับรอง) หากไม่มีอะไร stage ซอร์สของคุณไว้ จะมีอีกหมายเหตุว่า Nothing was staged for <job>; later steps see an empty workspace.

ความล้มเหลวครั้งแรกหยุดการรัน เมื่อขั้นตอนใดล้มเหลว ขั้นตอนที่เหลือของ job นั้นจะแสดง not run job ที่ต้องใช้ job ที่ล้มเหลวจะแสดง skipped: needs <job>, which failed และ job อื่นที่ยังไม่เริ่มจะแสดง not run: the run failed คลัสเตอร์ทำงานแบบเดียวกัน คือหยุดจัดตารางงานเมื่อมี task ล้มเหลว

job ต่าง ๆ ใช้ volume เดียว ตลอดการรัน ไฟล์ที่ job ก่อนหน้าเขียนไว้จึงอยู่ให้ job ถัดไป ยกเว้น matrix: แต่ละ instance ได้ workspace ว่างของตัวเอง เหมือนบนคลัสเตอร์ และรับ output ของ job ก่อนหน้าผ่าน artifacts-restore (ดู Job output และ artifact)

timeout ของขั้นตอนกับ retries จาก plan ถูกบังคับใช้ และ timeout ของ pipeline ใช้กับการรันทั้งหมด ไม่มี timeout ของ job แยกต่างหาก

Matrix​

matrix มาถึงในรูปที่ขยายแล้ว หนึ่ง job ต่อหนึ่งชุด และแต่ละ instance ได้ workspace ของตัวเอง จึงไม่มีสอง instance ที่เขียนไฟล์เดียวกัน โดยค่าเริ่มต้น instance รันทีละตัวต่อกัน

--matrix KEY=VALUE รันเฉพาะ instance ที่ matrix มีค่านั้น เช่น --matrix node=22 เพื่อลองเพียงชุดเดียว ระบุซ้ำได้และทุกรายการต้องตรงกัน (--matrix node=22 --matrix os=linux) ตัวเลือกมีผลเฉพาะ job ที่มีแกนนั้น: job ที่ไม่มี matrix และ job ที่ matrix ไม่มีแกนนั้นรันตามปกติ ตัวเลือกที่ไม่ตรงกับ instance ใดเลย หรือระบุแกนที่ไม่มี job ใดมี จะหยุดการรันด้วยโค้ด 2 และแสดงรายการแกนที่มี ค่าว่าง (--matrix node=) ไม่ตรงกับ instance ใด จึงหยุดการรันในแบบเดียวกัน

Parallel job​

--parallel N (1 ถึง 16 ค่าเริ่มต้น 1) ให้รันได้สูงสุด N job พร้อมกัน คือ job ใดก็ตามที่ needs ผ่านแล้ว ไม่ใช่เฉพาะ instance ของ matrix เหมือนที่คลัสเตอร์รัน job ที่เป็นอิสระต่อกันพร้อมกัน บรรทัดเอาต์พุตยังมี prefix [job/step] ดังนั้น log ที่สลับกันก็ยังอ่านได้ ความล้มเหลวครั้งแรกยังหยุดไม่ให้ job ใหม่เริ่ม job ที่กำลังรันอยู่จะรันจนจบ

--parallel ใช้ร่วมกับ --mount-source ไม่ได้ เพราะ job จะเขียน working tree ของคุณพร้อมกัน การตรวจทรัพยากร ดูแต่ละ job แยกกัน ไม่ได้ดู N job รวมกัน ดังนั้นเมื่อ N สูง engine อาจถูกขอมากกว่าที่มี ลด N หรือเพิ่มทรัพยากรให้ engine VM หาก job ถูกฆ่า

Cache​

ขั้นตอนที่ใช้ cache@v2 รันสคริปต์จริงของมัน เซิร์ฟเวอร์ในเครื่องของคุณตอบคำขอของสคริปต์ ดังนั้นการรันครั้งที่สองจะกู้คืนสิ่งที่ครั้งแรกบันทึกไว้

  • cache เป็น ต่อเครื่องและต่อรีโพสิทอรี เก็บไว้ใต้ loha/local-cache/ ในไดเรกทอรี cache ของผู้ใช้ (~/Library/Caches บน macOS, ~/.cache บน Linux, %LocalAppData% บน Windows) และไม่เคยถูกอัปโหลด
  • การกู้คืนต้องใช้ key ที่ตรงทุกตัวอักษร ไม่มีการถอยไปใช้ cache ของ default branch ไม่มีงบขนาดและไม่มีการจำกัดอัตราแบบบนคลัสเตอร์ key ที่ไม่ถูกต้องจะถูกปฏิเสธเหมือนบนคลัสเตอร์
  • ไม่มีการลบอัตโนมัติ หากต้องการล้าง ให้ลบโฟลเดอร์ rm -rf <user cache dir>/loha/local-cache (หรือโฟลเดอร์ของรีโพสิทอรีเดียวภายในนั้น)

Job output และ artifact​

upload-artifact, artifacts-save และ artifacts-restore รันสคริปต์จริงกับเซิร์ฟเวอร์ในเครื่อง instance ของ matrix จึงได้รับไฟล์ที่ job ก่อนหน้าบันทึกไว้ และไฟล์ของ upload-artifact จะอยู่ใน .loha/local-runs/<run id>/artifacts/ (ดู ไฟล์ผลลัพธ์) เมื่อสองขั้นตอน เช่น instance ของ matrix สองตัว อัปโหลดไฟล์ชื่อเดียวกันภายใต้ชื่อ artifact เดียวกัน ไฟล์ที่สองจะเก็บเป็น artifacts/<name>/<step>/<file> จึงไม่มีไฟล์ใดเขียนทับอีกไฟล์

เซิร์ฟเวอร์ในเครื่อง (cache, artifact, collector รายงานการสแกน) ฟังเฉพาะที่อยู่ loopback หรือ container bridge ของเครื่องคุณ ไม่เคยฟังทุก interface ทุก route มี secret แบบสุ่มต่อการรันอยู่ใน path และ container เข้าถึงเซิร์ฟเวอร์ที่ host.docker.internal token ของ cache และ artifact สุ่มใหม่ทุกการรัน เนื่องจากการอัปโหลดและดาวน์โหลดข้อมูลจริงเป็น URL ธรรมดา token ของ blob จึงเดินทางใน query ของ URL ผ่าน host gateway และใช้ได้เฉพาะการรันนั้น

การ build อิมเมจ​

ขั้นตอน buildah-build และ docker-build build ด้วย container engine ของคุณ จาก volume ของ workspace (ไฟล์เดียวกัน รวมถึงสิ่งที่ขั้นตอนก่อนหน้าสร้างไว้) ด้วย Dockerfile, build argument และ target ของ plan

  • อิมเมจถูกติดแท็ก loha-local/<name>:<run id> โดย <name> คือส่วนท้ายของ image ของขั้นตอน ไม่รวมแท็ก แปลงเป็นตัวพิมพ์เล็กและล้างให้เหลือ a-z 0-9 . _ -
  • ไม่เคยถูก push ไม่ว่าพารามิเตอร์อื่นของขั้นตอนจะระบุอย่างไร อิมเมจมี label io.loha.local-run=<run id> แต่ต่างจาก container ตรงที่ ไม่ถูกลบเมื่อการรันจบ คุณจึง docker run ได้ภายหลัง และลบด้วย docker rmi เมื่อใช้เสร็จ
  • .dockerignore ของ context มีผล เหมือนที่ Kaniko และ Buildah บนคลัสเตอร์ใช้: CLI กรอง context ด้วยกฎของ Docker ก่อนที่ engine จะเห็น ไฟล์ที่ถูกยกเว้น (.env, .git, node_modules …) จึงไม่ถูกส่งไปเลย .dockerignore และ Dockerfile ถูกส่งเสมอ บรรทัดที่ CLI ใช้ได้ไม่ตรงทุกประการ (เช่น ** ภายในชื่อ) จะถูกแจ้งเป็น Could not apply .dockerignore line <n> locally; the cluster builder may exclude more.
  • เมื่อใช้ buildx builder ที่ driver ไม่ใช่ docker (เช่น docker-container) การ build จะเพิ่ม --load เพื่อให้อิมเมจอยู่ในรายการอิมเมจของ engine คุณ
  • ค่าของ build argument ถึง engine ผ่าน environment ไม่ใช่ command line build argument ที่ชื่อตรงกับตัวแปรที่ engine client อ่านเอง (DOCKER_*, BUILDX_*, BUILDKIT_HOST, BUILDKIT_PROGRESS, HTTP_PROXY, HTTPS_PROXY, NO_PROXY และแบบตัวพิมพ์เล็ก) ทำให้ขั้นตอนล้มเหลว
  • ขีดจำกัดของ build container ใน plan (CPU, หน่วยความจำ) ไม่ใช้กับการ build ในเครื่อง
  • ขั้นตอนถูกทำเครื่องหมาย emulated builder ของ engine คุณไม่ใช่ builder ของคลัสเตอร์: engine ที่ไม่มี BuildKit อาจปฏิเสธ Dockerfile ที่ใช้ RUN --mount หรือ heredoc

Approval​

approval gate จะหยุดการรันและถามในเทอร์มินัล:

Approve deploy? Deploy to staging [y/N]

y หรือ yes (ตัวพิมพ์ใดก็ได้) คืออนุมัติ อย่างอื่น รวมถึงบรรทัดว่าง คือปฏิเสธ และเมื่อเกิน timeoutSeconds ของ gate ก็เช่นกัน gate ที่ถูกปฏิเสธหรือหมดเวลาจะ ล้มเหลว พร้อม approval declined หรือ approval timed out และหยุดการรันเหมือนขั้นตอนที่ล้มเหลว เหมือนที่ gate ที่ถูกปฏิเสธทำให้ task ล้มเหลวบนคลัสเตอร์ คำตอบไม่ถูกเขียนลง log

หากไม่มีเทอร์มินัล (pipe, งาน CI, --json) ก็ไม่มีใครให้ถาม: gate จะล้มเหลวทันทีพร้อม Approval required for <job>; run in a terminal or pass --approve. ใช้ --approve เพื่ออนุมัติทุก gate โดยจะมีประกาศ Approvals are accepted automatically (--approve).

รันขั้นตอนซ้ำและเปิด shell​

เพื่อปรับปรุงขั้นตอนที่ล้มเหลวทีละขั้นโดยไม่ต้องรันทุกอย่างก่อนหน้าใหม่ ให้เก็บ workspace ไว้:

loha run --local --keep                              # prints the kept volume's name
loha run --local --reuse <volume> --from build/test # that step and everything after it
loha run --local --reuse <volume> --step build/test # only that step
loha run --local --shell build/test # a shell where that step would run
  • --step และ --from ต้องใช้ --reuse <volume> ซึ่งเป็น volume ที่ การรัน --keep ครั้งก่อนของรีโพสิทอรีเดียวกัน ทิ้งไว้ หากไม่มี การรันจะเริ่มจาก workspace ว่างโดยไม่บอก volume ถูกใช้ตามสภาพที่เป็นอยู่: ไม่มีการ stage ลงไปหรือลบอะไรออก volume ที่ CLI รุ่นเก่าเก็บไว้ไม่มี label io.loha.repo-key จึงนำกลับมาใช้ไม่ได้ ให้รันด้วย --keep อีกครั้งเพื่อได้ volume ที่ใช้ได้
  • job และขั้นตอนก่อนหน้าจะรายงานเป็น skipped: before --from รวมถึง approval gate ใน job เดียวกัน: ถูกข้ามพร้อมขั้นตอนก่อนเป้าหมาย และไม่ถูกถามอีก
  • ไม่สามารถระบุ instance ของ matrix เป็นเป้าหมายได้ เพราะ workspace ของมันไม่ถูกเก็บโดย --keep ให้ระบุ job ที่ไม่มี matrix
  • --shell <job>/<step> รันทุกอย่างก่อนขั้นตอนนั้นตามปกติ แล้วเปิด /bin/sh ใน container ของขั้นตอน ด้วยอิมเมจ user environment mount และไดเรกทอรีทำงานของมัน แทน การรันสคริปต์ ขั้นตอนถูกรายงานเป็น skipped: shell และการรันจบเมื่อคุณออกจาก shell shell ไม่ถูกจำกัดด้วย timeout ของ pipeline Ctrl-C ถูกส่งไปยัง shell ภายใน container เหมือนเทอร์มินัลทั่วไป: ออกด้วย exit หรือ Ctrl-D SIGINT ที่ส่งถึง loha จากที่อื่น (kill -INT) ยังคงจบ shell และล้างทรัพยากร หาก shell ที่ถูกฆ่าทิ้งเทอร์มินัลไว้ในโหมด raw ให้พิมพ์ reset ขั้นตอนที่ไม่รันใน container ในเครื่อง (ขั้นตอน emu) ไม่มี shell ให้เปิด
  • session ของ shell เป็นแบบ raw: สิ่งที่คุณพิมพ์และสิ่งที่มันแสดง ไม่ถูก mask และไม่ถูกบันทึก log ดังนั้น env จะแสดงค่า secret ตรง ๆ
  • --shell ต้องมีเทอร์มินัลทั้งที่ stdin และ stdout และใช้ร่วมกับ --json, --step, --from หรือ --parallel ไม่ได้

ซอร์ส​

คลัสเตอร์ build จาก clone สะอาดของ commit ที่ push เสมอ ในเครื่อง CLI จะ stage ซอร์สของคุณลงใน volume ใหม่ เมื่อขั้นตอน git-clone แรกของรีโพสิทอรีของคุณทำงาน และลงในไดเรกทอรีที่ขั้นตอนนั้นระบุ

  • ค่าเริ่มต้น: ไฟล์ที่ git add -A จะ commit (ทั้งที่ track และ untracked ที่ไม่ถูก ignore) พร้อม .git แบบ shallow ที่ HEAD ตรงกับ HEAD ของคุณ ทำให้ git rev-parse HEAD ใช้ได้ และการแก้ไขที่ยังไม่ commit ปรากฏเป็น modification การคัดลอกแทนการ mount ป้องกันไม่ให้ node_modules เก่าหรือผลลัพธ์ build ในเครื่องบังความล้มเหลวที่คลัสเตอร์จะเห็น
  • --committed-only: ใช้ HEAD เท่านั้น เหมือนที่คลัสเตอร์จะเห็นหลังจากคุณ push commit ปัจจุบัน ไฟล์ pipeline ก็อ่านจาก HEAD ด้วย
  • --mount-source: mount working tree ของคุณโดยตรง CLI จะพิมพ์ Build outputs will be written into your working tree, and results may differ from the cluster.

git-clone ครั้งที่สองลงไดเรกทอรีเดียวกันจะพิมพ์ already staged และไม่ทำอะไร จึงไม่ลบผลลัพธ์ที่ถูกกู้คืนมาก่อนหน้า pipeline ที่ไม่มีขั้นตอน git-clone จะเริ่มด้วย volume ว่าง

Service​

service ของ job (ฐานข้อมูล แคช) ทำงานตลอดช่วงของ job ใน network namespace เดียวกับขั้นตอนของ job เหมือน sidecar ใน pod บนคลัสเตอร์ จึงตอบที่ localhost:<port> และ ตามชื่อและ alias ของมัน connection string ที่เขียนไว้สำหรับคลัสเตอร์และการตรวจความพร้อมของ plan เองที่เช็ก 127.0.0.1 จึงใช้ได้โดยไม่ต้องแก้ การตรวจความพร้อมรันก่อนขั้นตอนของ job เหมือนบนคลัสเตอร์ และ service จะถูกลบเมื่อ job จบ

เฉพาะขั้นตอนที่ plan ระบุว่าใช้เครือข่าย service (ขั้นตอน run: ของคุณ) เท่านั้นที่เข้าร่วม ขั้นตอนที่ใช้ official task (uses:) ไม่เข้าร่วม เพราะบนคลัสเตอร์มันรันใน pod ของตัวเองและเข้าถึง sidecar ไม่ได้เช่นกัน

Secret และตัวแปร​

Loha ไม่เคยส่งค่า secret มายังเครื่องของคุณ ขั้นตอนที่ได้สิทธิ์ใช้ secret จึงไม่มีค่าจนกว่าคุณจะให้

  • --secret NAME อ่านค่าจากตัวแปรสภาพแวดล้อม NAME ใน shell ของคุณ หากไม่ได้ตั้งไว้ คำสั่งจะหยุดพร้อมข้อความ --secret NAME: environment variable NAME is not set
  • --env-file <path> อ่านบรรทัด KEY=VALUE ใช้ให้ค่า secret และ เมื่อ token ของคุณไม่มี variables:values:read ให้ค่าตัวแปรทั่วไปที่ plan แสดงเพียงชื่อ ทั้งของขั้นตอนและ service

secret ที่ได้สิทธิ์แต่ไม่มีค่าในเครื่องจะพิมพ์คำเตือนเดียวกับที่คลัสเตอร์พิมพ์สำหรับ secret ที่หายไป และขั้นตอนรันโดยไม่มี secret นั้น

รูปแบบของ --env-file:

  • หนึ่ง KEY=VALUE ต่อบรรทัด บรรทัดว่างและบรรทัดที่ขึ้นต้นด้วย # ถูกข้าม
  • ชื่อประกอบด้วยตัวอักษร ตัวเลข และ _ และต้องไม่ขึ้นต้นด้วยตัวเลข
  • ค่าในเครื่องหมายคำพูดคู่รองรับ \n, \" และ \\ แบ็กสแลชอื่นคงตามที่เขียน ใช้กับค่าหลายบรรทัด เช่น private key
  • ค่าในเครื่องหมายคำพูดเดี่ยวถูกอ่านตามตัวอักษร
  • ค่าที่ไม่มีเครื่องหมายคำพูดถูกอ่านตามที่เขียน รวมถึงช่องว่างหลัง = และตัดเฉพาะช่องว่างท้ายค่า
  • ค่าที่อยู่ในเครื่องหมายคำพูดตามด้วย # comment ได้ คีย์ที่ซ้ำใช้ค่าสุดท้าย

ไฟล์ที่รูปแบบผิดจะหยุดคำสั่งด้วยโค้ด 2 และบอกหมายเลขบรรทัด ไม่แสดงค่า

ค่าไม่เคยอยู่บน command line แต่ส่งให้ container engine ผ่าน environment ของ process ของ engine เอง จึงไม่ปรากฏใน ps หรือประวัติ shell ค่าต่อไปนี้จะถูกแทนด้วย *** ในเอาต์พุตบนเทอร์มินัล event แบบ JSON และไฟล์ log

  • ค่า --secret ทุกตัว
  • ตัวแปรทั่วไปทุกตัวที่ plan ทำเครื่องหมาย masked ทั้งในขั้นตอนและ service
  • ค่าใน --env-file ที่ชื่อถูกขั้นตอนใช้เป็น secret หรือที่ plan ทำเครื่องหมาย masked ที่ใดก็ตาม หรือที่ไม่มีขั้นตอนหรือ service ใดใช้เป็นตัวแปรทั่วไป

ค่าใน --env-file ของตัวแปรทั่วไปที่ไม่ได้ทำเครื่องหมาย masked (เช่น NODE_ENV=test หรือ PGPORT=5432) จะไม่ถูก mask log ของคุณจึงอ่านได้เหมือนบนคลัสเตอร์ ค่าที่สั้นกว่าสี่ตัวอักษรไม่ถูก mask เลย การ mask ทำงานกับข้อความที่ตรงกันทุกตัวอักษร ดังนั้น secret ที่ขั้นตอนเข้ารหัสใหม่ (base64, URL escaping) จะไม่ถูกจดจำ อย่าพิมพ์ secret

LOHA_TOKEN ไม่เคยถูกตั้ง LOHA_RUN_ID คือ local- ตามด้วยเลขฐานสิบหกแปดหลัก และ LOHA_API_URL คือที่อยู่ API ของ context ที่ใช้งานอยู่ ตัวแปรของแพลตฟอร์มอื่นจะไม่ถูกตั้ง เว้นแต่ CLI ให้บริการในเครื่อง

ไฟล์ผลลัพธ์​

ทุกอย่างที่การรันเขียนให้คุณอยู่ใน .loha/local-runs/<run id>/ ที่รากของรีโพสิทอรี

พาธเก็บอะไร
logs/log ที่ mask แล้วหนึ่งไฟล์ต่อขั้นตอน logs/<job>/<step>.log
artifacts/archive ที่ขั้นตอน upload-artifact และ artifacts-save บันทึก ตั้งชื่อตามชื่อ artifact
security/รายงานการสแกนจาก trivy-scan@v2 เก็บที่นี่และไม่ถูกส่งไปยังเซิร์ฟเวอร์
scripts/สคริปต์ของขั้นตอนที่สร้างขึ้นตามที่ใช้รันจริง

ทุกครั้งที่รันจะพิมพ์ Add .loha/local-runs/ to .gitignore; local run logs are written there. จนกว่า git จะ ignore ไดเรกทอรีนี้

trivy-scan@v2 อัปโหลดรายงานไปยัง collector การรันในเครื่องจะเริ่ม collector เล็ก ๆ บนเครื่องของคุณที่เก็บรายงานเท่านั้น และสคริปต์ทางการรันโดยไม่ถูกแก้ บน Docker Desktop และ engine แบบ VM อื่น ๆ ใช้ได้ทันที บน engine Linux แบบ native collector ฟังที่ bridge gateway ของ engine ดังนั้น engine แบบ rootless ที่ไม่มี bridge gateway ไม่รองรับขั้นตอนนี้

หมายเหตุเกี่ยวกับ engine​

ทรัพยากรของ engine VM​

บน Docker Desktop, Colima, Rancher Desktop, OrbStack และ Podman machine container ทำงานใน virtual machine ที่มี CPU และหน่วยความจำของตัวเอง ก่อนสร้างอะไร การรันจะเทียบสิ่งที่แต่ละ job ขอกับสิ่งที่ engine รายงาน โดย job ต้องการ container ของขั้นตอนที่ใหญ่ที่สุด (ขั้นตอนรันทีละอัน) บวกกับ service ทั้งหมดของ job (รันควบคู่ไปกับขั้นตอน) หากเกินกว่าที่ engine มี การรันจะหยุดพร้อมข้อความ

Job integration asks 8.25 CPUs / 9.25 GiB, but the engine has 4 CPUs / 7.76 GiB. Give the engine VM more resources or pass --no-limits.

เพิ่ม CPU และหน่วยความจำให้ VM ในการตั้งค่าของมัน (สำหรับ Colima ใช้ colima stop && colima start --cpu 8 --memory 12) หรือใช้ --no-limits เพื่อรันโดยไม่ใช้ขีดจำกัดของ plan การตรวจนี้จะถูกข้ามเมื่อใช้ --no-limits และเมื่อ engine ไม่รายงานขนาดของตัวเอง

โฟลเดอร์ที่แชร์​

engine VM มองเห็นเพียงบางโฟลเดอร์ของเครื่องคุณ โดย Colima และ Lima แชร์เฉพาะโฟลเดอร์ home เป็นค่าเริ่มต้น สคริปต์ของขั้นตอนไม่ต้องการโฟลเดอร์ที่แชร์อีกต่อไป เพราะถูกส่งเข้า container ผ่าน volume รีโพสิทอรีนอกโฟลเดอร์ home จึงรันได้ตามปกติ ส่วน --mount-source ทำการ bind-mount working tree ของคุณ จึงต้องแชร์โฟลเดอร์นั้น หากไม่ได้แชร์ การรันจะหยุดก่อนขั้นตอนใด ๆ พร้อมข้อความ The engine cannot see <path>. Move the repository under your home folder or share the folder with the engine VM, or run without --mount-source.

นโยบายการ pull​

อิมเมจเป็นไปตามนโยบาย pull เริ่มต้นของคลัสเตอร์ อิมเมจที่อ้างอิงด้วย digest หรือด้วยแท็กอื่นที่ไม่ใช่ latest จะถูกใช้ตามที่มีอยู่ เมื่ออยู่ในเครื่องคุณแล้ว ดังนั้นอิมเมจที่คุณ build หรือ retag เองจะรันได้โดยไม่ต้อง pull ส่วนอิมเมจที่ไม่มีแท็กหรือมีแท็ก latest จะถูก pull ทุกครั้งที่รัน หาก pull ไม่สำเร็จ (ออฟไลน์ หรือรีจิสทรีล่ม) และมีสำเนาในเครื่อง การรันจะดำเนินต่อด้วยสำเนานั้นและพิมพ์ Could not pull <image>; using the local copy.

Volume และ Podman​

volume ของการรันถูก mount โดยไม่มี copy-up ไฟล์ของอิมเมจที่จุด mount จึงไม่รั่วเข้าไปใน volume ของการรันจนเปลี่ยนสิ่งที่ขั้นตอนของคุณเห็น ได้ตรวจสอบแล้วเฉพาะบน Docker ส่วนพฤติกรรมบน Podman ยังไม่ได้ตรวจสอบ

การล้างและ Ctrl-C​

ทุก container และ volume ที่การรันสร้างจะมี label io.loha.local-run=<run id> และชื่อขึ้นต้นด้วย loha-<run id>- และถูกลบเมื่อการรันจบ รวมถึงหลัง Ctrl-C ไม่มีอย่างอื่นในเครื่องของคุณถูกแตะต้อง หากการลบล้มเหลว CLI จะพิมพ์คำสั่งที่ทำต่อให้เสร็จ เมื่อใช้ --keep container และ volume อื่นทั้งหมดจะถูกลบ เหลือเพียง volume ของซอร์สให้คุณตรวจดูหรือนำกลับมาใช้ CLI จะพิมพ์ชื่อและคำสั่ง volume rm

สิ่งที่การรันทิ้งไว้​

เอาต์พุตสำหรับเครื่องอ่าน​

เมื่อใช้ --json stdout มีเฉพาะ event หนึ่งอ็อบเจกต์ JSON ต่อบรรทัด ได้แก่ run_started, job_started, step_started, log, step_finished, job_finished, notice และ run_finished สุดท้ายที่มีสถานะและโค้ดทางออก บรรทัด log ถูก mask หมายเหตุต่าง ๆ เช่น คำแนะนำเรื่อง .gitignore ไปที่ stderr และไม่พิมพ์ตารางสรุป โค้ดทางออกเหมือนโหมดข้อความ

อะไรเหมือนและอะไรต่าง​

ด้านการรันในเครื่องเทียบกับคลัสเตอร์
การ parse, เงื่อนไข, matrix, ลำดับความสำคัญของ env, การสร้าง task, นโยบายอิมเมจ, ชื่อ env ที่ห้ามเหมือนกัน เพราะเซิร์ฟเวอร์สร้าง plan
อิมเมจ สคริปต์ user id capability และไดเรกทอรีทำงานของขั้นตอนเหมือนกัน
ขีดจำกัด CPU และหน่วยความจำค่าเดียวกัน บังคับโดย engine ของคุณ โดยไม่มี swap การจัดตารางและความพอดีของ node ไม่ถูกจำลอง
ซอร์สจำลอง: working tree ที่ stage แทน clone ของ commit ที่ push
Serviceจำลอง: container ที่ใช้ network namespace เดียวกันแทน sidecar ของ pod
เครือข่ายต่างกัน: เครือข่ายของเครื่องคุณแทนกฎ egress ของ build pod, host alias และ mirror
สถาปัตยกรรมต่างกัน เว้นแต่ตั้ง --platform CLI จะแจ้งเมื่อเครื่องของคุณต่างจากคลัสเตอร์
Secret และตัวแปรที่เก็บไว้แหล่งที่มาต่างกัน: secret มาจากคุณ ตัวแปรทั่วไปเป็นไปตาม scope ของ token
Cache (cache@v2)จำลอง: cache ต่อเครื่อง ใช้ key ที่ตรงทุกตัวอักษรเท่านั้น ไม่มีงบ การจำกัดอัตรา หรือ fallback
Job output และ upload-artifactจำลอง: สคริปต์จริงกับเซิร์ฟเวอร์ในเครื่อง archive อยู่ในไดเรกทอรีการรันของคุณ
การ build อิมเมจจำลอง: builder ของ engine คุณ (มี BuildKit หรือไม่ก็ได้) ไม่ push ไม่ใช้ขีดจำกัด build ของ plan
Approval gateจำลอง: คุณตอบในเทอร์มินัล หรือใช้ --approve
push, deploy, แจ้งเตือน, การเซ็นชื่อ, security gate, บันทึกบิลด์ไม่เกิดในเครื่องเด็ดขาด

ตารางสรุปจะพิมพ์แถว "ต่างกัน" ที่เกี่ยวกับการรันที่เพิ่งทำ แต่ละแถวขึ้นต้นด้วย ≠

ดูเพิ่มเติม​

  • loha plan: ดู plan ล่วงหน้าก่อนรัน
  • CLI: การติดตั้ง การเข้าสู่ระบบ และคำสั่งอื่น
  • Service และ secret