24. Custom Actions with Docker
เนื่องจากว่า Github actions ถ้าอยากเขียน custom action เราใช้ได้แค่ภาษา JavaScript อย่างเดียว
ถ้าจำเป็นต้องใช้ภาษาอื่นๆ เราต้องไปใช้ Docker เท่านั้น
เรามาดูข้อดี ข้อเสีย ของ Docker ในการเขียน custom action กันหน่อย
- รันในสภาพแวดล้อมที่เหมือนกันทุกครั้ง
- ไม่ขึ้นกับ runner environment
- Reproducible builds
- สามารถใช้ภาษาใดก็ได้
- ควบคุม dependencies ได้ทั้งหมด
- กำหนด system packages ได้
- Custom configuration
- แยกออกจาก host system
- ไม่กระทบกับ actions อื่น
- Security isolation
- Slow startup time: ต้อง build/pull image
- Resource intensive: ใช้ memory และ CPU มาก
- Network overhead: Download base images
- ทุกครั้งที่รันต้อง build
- Docker images มีขนาดใหญ่
- GitHub Actions มีข้อจำกัดเรื่อง storage
- Network transfer time
- ยากต่อการ debug ทำให้เราต้อง exec ต้องเข้าไปใน container เพื่อ debug
- รันได้เฉพาะ Linux runners
- ไม่รองรับ Windows/macOS runners
- Architecture dependencies
- ต้องดูแล Dockerfile
- Update base images
- Security patches
เปรียบเทียบกับ JavaScript Actions
Aspect | Docker Action | JavaScript Action |
---|---|---|
Speed | ⚠️ ช้า (build time) | ✅ เร็ว |
Flexibility | ✅ ภาษาใดก็ได้ | ⚠️ JavaScript เท่านั้น |
Size | ❌ ใหญ่ | ✅ เล็ก |
Platform | ❌ Linux เท่านั้น | ✅ ทุก platform |
Debugging | ❌ ยาก | ✅ ง่าย |
Best Practices
✅ ใช้ Docker Action เมื่อ:
- ต้องการ specific runtime environment
- ใช้ภาษาอื่นนอกจาก JavaScript
- ต้องการ system-level dependencies
- Complex processing tasks
❌ หลีกเลี่ยงเมื่อ:
- Simple tasks ที่ทำด้วย JavaScript ได้
- ต้องการ performance สูง
- รัน frequently
- ต้องการรองรับหลาย platform
ตัวอย่าง
ผมทำตัวอย่างคร่าวๆมาให้นะครับ อยากให้เห็น idea เฉยๆ ไม่ได้ทำเป็น Tutorial นะครับ
โดยตัวอย่างจะทำ custom action ที่ deploy React CSR ไปที่ Surge เหมือนเดิม แต่รอบนี้จะใช้ Bun
Bun สามารถรัน JS ได้แต่ Github actions ไม่ได้ support นะ ดังนั้นถ้าจะใช้ Bun ก็ต้องใช้ Docker ช่วย
สิ่งที่เราต้องมีแน่ๆเลยต้องทำ custom action คือ file action.yaml
action.yaml
name: Deploy to Surgedescription: Deploy to Surgeruns: using: docker image: Dockerfileinputs: token: required: true description: The token to deploy to email: required: true description: The email to deploy to domain: required: true description: The domain to deploy to dist_folder: # เปลี่ยนเป็น underscore แทน dash นะ required: false description: The folder to deploy default: "dist"outputs: website-url: description: The URL of the deployed website
จาก code ด้านบน
ในส่วน runs
จะต้องบอกว่าใช้ Docker และ image ที่ใช้จะใช้เป็น Dockerfile
เดี๋ยว github action จะเอาไป build ให้
runs: using: docker image: Dockerfile
โค้ด ts จะเป็นแบบนี้
index.ts
import { $ } from "bun";// surge dist --token d2f81d98ab5f03e8da3fb6848c6a5f15 --login um_oom@hotmail. --domain gh-action-tanstack.surge.sh
async function main() { // get inputs values const domain = Bun.env.INPUT_DOMAIN; const distFolder = Bun.env["INPUT_DIST_FOLDER"]; const token = Bun.env.INPUT_TOKEN; const email = Bun.env.INPUT_EMAIL;
// const command = `npx surge ${distFolder} --domain ${domain}` console.log({ domain, distFolder, token, email });
const exitCode = await $`surge ${distFolder} --token ${token} --login ${email} --domain ${domain}`; const websiteUrl = `https://${domain}`; console.log(`::set-output name=website-url::${websiteUrl}`);
return exitCode;}
main();
.dockerignore
node_modulesdist-actionCLAUDE.mdREADME.mdDockerfileaction.yaml
Dockerfile เขียนง่ายมาก
เราจะให้ Bun รัน Typescript file ตรงๆไปเลย ไม่ compile
Dockerfile
FROM oven/bun:1-alpine AS builderWORKDIR /app
COPY . .
RUN bun i -g surge && bun installCMD ["bun", "/app/index.ts"]
ส่วนวิธีการเรียกใช้งาน จะเหมือนกับการเรียกใช้งาน action ทั่วไป อ้างอิงไปที่ path ให้ถูกละกัน