Skip to content
CodeSook
CodeSook

19. Jobs and Docker


Job in container

ปกติแล้วเราใช้ runs-on: ubuntu-latest เป็น OS หลักในการรัน workflow ของเราใช่มะ ถ้าเราใช้ Bun สร้าง app เราก็จะต้องติดตั้ง Bun ลงไปบน Ubuntu ก่อน แล้วค่อยสั่ง lint, test หรือ build ด้วย bun ใช่มะ
เราสามารถใช้ Docker image ที่มี Bun ติดตั้งไว้แล้ว แทนการติดตั้ง Bun ลงไปบน Ubuntu ตรงๆ ได้เช่นกัน

อีกตัวอย่างหนึ่งคือ ถ้าเราต้องการ test React ด้วย Playwright เราก็ต้องติดตั้ง Playwright ลงไปบน Ubuntu ก่อน แล้วเราจึงจะ test ได้ ซึ่งมันก็ไม่สะดวกนัก
เราก็สามารถแก้ปัญหาได้ด้วยการที่เอา Docker image ที่มี Playwright ติดตั้งไว้แล้ว มาใช้ใน Job ที่ต้องใช้ Playwright ในการ Test

Docker image ที่จะใช้ได้ก็ทุกตัวใน Dockerhub หรือที่ registry อื่นๆก็จะใช้ได้หมดแหละ

เราจะระบุว่า Job ไหนที่จะทำงานใน Container ก็จะเขียนแบบนี้

workflows/deploy-docker.yaml
deploy-docker.yaml
name: Deploy Project
on:
push:
jobs:
build:
runs-on: ubuntu-latest
container:
image: oven/bun:1
env:
NODE_ENV: production
steps:
- name: Get Code
uses: actions/checkout@v4
# - name: Install Bun
# uses: oven-sh/setup-bun@v2
# with:
# bun-version: 1.2.18
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
- name: Install Dependencies
run: bun i
- name: Build
run: bun run build
- name: upload dist folder
uses: actions/upload-artifact@v4
with:
name: dist
path: |
dist
public
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: download dist folder
uses: actions/download-artifact@v4
with:
name: dist
- name: List all files
run: ls -R
- name: Deploy
run: |
echo "Deploying version ${{ needs.build.outputs.package-version }}..."
echo "Commit: ${{ needs.build.outputs.build-hash }}"

ลอง push code ดู

Job build ก็ยังทำงานได้เหมือนเดิม

พอ job build เริ่มทำงาน มันก็จะไปโหลด docker image มารัน
แล้วทุกๆ steps ใน job ก็จะทำงานภายใน Container ที่อยู่ภายใน Ubuntu อีกที

Service Containers

ใน Github actions เราสามารถสร้าง Services ทิ้งไว้ แล้วให้ Jobs มาเรียกใช้งาน Services ได้ด้วย เช่น
เราสร้าง Database ไว้ แล้วให้ Job ทดลองเชื่อมต่อแล้ว Test ต่อไปได้ โดย Github actions ก็จะ run services ผ่าน Docker นี่แหละ จริงๆมันก็ใช้ Concept เดียวกันกับตอนที่เรา Dev บน local เลย การเชื่อมต่อเพื่อเข้าถึง Services ก็เหมือนกันกับตอนที่เราใช้ Docker เลย

เราจะเขียน Workflow แบบนี้

ตัวอย่าง workflow

name: Services example
on:
workflow_dispatch:
jobs:
context:
runs-on: ubuntu-latest
services:
redis:
image: redis
env:
THIS_ENV: example_env
ports:
- 6379:6379
# surrealdb:
# image: surrealdb/surrealdb
env:
PORT: 3000
REDIST_HOST: localhost
REDIST_PORT: 6379
steps:
- name: Get Code
uses: actions/checkout@v4
- name: test
run: bun run test

จากตัวอย่างด้านบนเราให้ Github actions สร้าง Service Redis ขึ้นมา ซึ่ง Github actions ก็จะไปสร้าง Redis ด้วย Docker แล้ว expose ออกมา ผ่าน Port 6379 แล้ว expose ออกมา ผ่าน Port 6379 และ expose ออกมา ผ่าน Port 6379
แล้วเราก็ set env REDIS_HOST: localhost ที่ใช้ localhost เพราะว่า steps ของเราทำงานบน Ubuntu ตรงๆ จะเห็นว่าเราไม่ได้ใช้ container:

ถ้าเราใช้ Container ก็จะเขียนแบบนี้

name: Services example
on:
workflow_dispatch:
jobs:
context:
runs-on: ubuntu-latest
container:
image: oven/bun:1
services:
redis:
image: redis
env:
THIS_ENV: example_env
ports:
- 6379:6379
# surrealdb:
# image: surrealdb/surrealdb
env:
PORT: 3000
REDIST_HOST: redis
# REDIST_HOST: localhost
REDIST_PORT: 6379
steps:
- name: Get Code
uses: actions/checkout@v4
- name: test
run: bun run test

เมื่อเราเพิ่ม container: เข้าไป จะทำให้ Steps ของเราทำงานใน Container ละ
พอเราอยากเข้าถึง Redis เราก็จะต้องใช้ชื่อ Service redis แทนที่จะเป็น localhost