Skip to content
CodeSook
CodeSook

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

AspectDocker ActionJavaScript 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 Surge
description: Deploy to Surge
runs:
using: docker
image: Dockerfile
inputs:
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
Terminal window
node_modules
dist-action
CLAUDE.md
README.md
Dockerfile
action.yaml

Dockerfile เขียนง่ายมาก

เราจะให้ Bun รัน Typescript file ตรงๆไปเลย ไม่ compile

Dockerfile
FROM oven/bun:1-alpine AS builder
WORKDIR /app
COPY . .
RUN bun i -g surge && bun install
CMD ["bun", "/app/index.ts"]

ส่วนวิธีการเรียกใช้งาน จะเหมือนกับการเรียกใช้งาน action ทั่วไป อ้างอิงไปที่ path ให้ถูกละกัน