နားလည်ထားရမယ့် အချက်
GitHub Actions ရဲ့ environment ဟာ server တစ်လုံး မဟုတ်ပါဘူး။ သူက repository ထဲမှာ ရှိတဲ့ နာမည်တပ်ထားတဲ့ မှတ်တမ်းတစ်ခုဖြစ်ပြီး staging, production, eu-prod စတဲ့ deploy target တစ်ခုကို ကိုယ်စားပြုတယ်။ သူနဲ့အတူ ပါလာတာ သုံးမျိုးရှိတယ် — ကိုယ်ပိုင် secret တွေ၊ ကိုယ်ပိုင် variable တွေ၊ ပြီးတော့ ကိုယ်ပိုင် protection rule တွေ။ job တစ်ခုက environment: ဆိုတဲ့ key တစ်ကြောင်းတည်းနဲ့ ဝင်လိုက်တာနဲ့ အရေးကြီးတဲ့ အပြောင်းအလဲ နှစ်ခု ဖြစ်သွားတယ်။
ပထမတစ်ခုက scoping ပါ။ production environment မှာ သတ်မှတ်ထားတဲ့ secret ဟာ environment: production လို့ ကြေညာထားတဲ့ job ထဲကိုပဲ ရောက်လာတယ်။ staging job က အဲဒါကို ဖတ်လို့ မရဘူး — ဘယ်သူက သတိထားလို့ မဟုတ်ဘဲ အဲဒီ job ရဲ့ context ထဲကို ကနဦးကတည်းက မထည့်ပေးလို့ဖြစ်တယ်။ environment တွေ တည်ရှိရတဲ့ အကြောင်းရင်းက ဒါပါပဲ။ environment မသုံးဘူးဆိုရင် credential အားလုံးက repository scope မှာ ရှိနေမယ်၊ ဆိုလိုတာက staging deploy job ရော၊ သူ့အထဲက step တိုင်း၊ သူ့အထဲမှာ run နေတဲ့ third-party action တိုင်းရော production key ကို ကိုင်ထားနိုင်တယ်။ environment က "staging job ဟာ prod ကို မထိရဘူး" ဆိုတဲ့ မူဝါဒကို copy-paste မှားတာမျိုးတောင် ခံနိုင်တဲ့ စက်ပိုင်းအာမခံချက် ဖြစ်အောင် ပြောင်းပေးတယ်။
ဒုတိယက gating ပါ။ required reviewer, wait timer, deployment branch allowlist စတဲ့ protection rule တွေကို job မစခင်မှာ စစ်တယ်။ approval စောင့်နေတဲ့ job ဟာ step တစ်ခုမှ မ run ရသေးဘူး၊ ဒါကြောင့် ဘာမှ ထက်ဝက်တင် deploy ဖြစ်မနေဘူး၊ စောင့်နေတဲ့ အချိန်ပိုင်းအတွင်း secret ကိုလည်း decrypt မလုပ်ရသေးဘူး။ သတ်မှတ်ထားတဲ့ reviewer တစ်ယောက်ယောက် approve လုပ်ရင် queue လုပ်ခဲ့တဲ့ commit အတိုင်းပဲ ဆက် run တယ်။
လူအများ လွတ်သွားတတ်တဲ့ အချက်က gate ဟာ workflow အပေါ်မှာ မဟုတ်ဘဲ job အပေါ်မှာ ရှိတယ် ဆိုတာပါ။ deploy နဲ့ smoke test ကို job တစ်ခုတည်းထဲ ထည့်ထားရင် approval က နှစ်ခုလုံးကို ပိတ်ထားတယ်၊ စက်ကိုယ်တိုင် လုပ်နိုင်တဲ့ အလုပ်အတွက် reviewer ကို အိပ်ရာက နှိုးရသလို ဖြစ်သွားတယ်။ needs: နဲ့ ခွဲပြီး လူ့ဆုံးဖြတ်ချက်ကို ပြန်လုပ်လို့မရတဲ့ အဆင့်အတွက်ပဲ သိမ်းထားပါ။
APPROVAL GATE IN A DEPLOY PIPELINE
----------------------------------
push to main
|
v
+----------+ +-------------------+ +--------------------+
| build | --> | deploy-staging | --> | deploy-production |
| (no env) | | env: staging | | env: production |
+----------+ | secrets: staging | | secrets: prod only |
+-------------------+ +--------------------+
automatic ^
|
+------------------------+
| PROTECTION RULES |
| - required reviewers |
| - wait timer |
| - branch: main only |
+------------------------+
while waiting: job is QUEUED, not started
no step has run, no production secret has been decryptedလက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Settings > Environments မှာ staging နဲ့ production ကို ဆောက်ပါ။ production မှာ required reviewers ကို ဖွင့်ပြီး လူနှစ်ယောက်လောက် ထည့်ပါ၊ deployment branch ကို main တစ်ခုတည်း ကန့်သတ်ပါ။ ပြီးရင် DEPLOY_TOKEN ဆိုတဲ့ secret ကို environment တစ်ခုချင်းစီအောက်မှာ တန်ဖိုးမတူအောင် သီးသန့် ထည့်ပါ — repository scope မှာ တစ်ခုတည်း မထားပါနဲ့။ workflow ထဲမှာ deploy-staging နဲ့ deploy-production ဆိုပြီး job နှစ်ခု ခွဲထားတယ်၊ နှစ်ခုလုံးက ${{ secrets.DEPLOY_TOKEN }} ဆိုတဲ့ စာသားအတူတူကို ရေးထားပေမယ့် တကယ်ရလာတဲ့ တန်ဖိုးက သူတို့ ကြေညာထားတဲ့ environment ပေါ်မူတည်ပြီး ကွဲပါတယ်။ ဒါက အရေးအကြီးဆုံး အချက်ပါ — expression က တူပေမယ့် ရောက်လာတဲ့ credential က မတူဘူး။
build ကို job သီးသန့်ထားပြီး artifact ကို upload လုပ်ထားတာကိုလည်း သတိပြုပါ။ production job က source ကနေ ပြန်မဆောက်ဘဲ staging မှာ စမ်းပြီးသား artifact အတိအကျကိုပဲ ယူသုံးတယ်၊ ဒါမှ "staging မှာ အဆင်ပြေပေမယ့် prod မှာ မရဘူး" ဆိုတဲ့ ပြဿနာမျိုး လျော့သွားမယ်။
PR တစ်ခု merge လုပ်ကြည့်ပါ။ build နဲ့ staging က အလိုအလျောက် ပြီးသွားမယ်၊ production job ကတော့ Waiting အနေအထားနဲ့ ရပ်နေမယ်။ ကိုယ်တိုင် reviewer ဖြစ်ရင် run page ကနေ approve နှိပ်ကြည့်ပြီး၊ တစ်ခါ reject လုပ်ကြည့်ပါ — reject လုပ်ရင် production job ရဲ့ step တစ်ခုမှ မ run ဘဲ ရပ်သွားတာကို တွေ့ရမယ်။
အတူတူ စမ်းရေးကြည့်မယ်
name: Deploy
on:
push:
branches:
- main
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Deploy the built artifact to staging
run: ./scripts/deploy.sh staging
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
smoke-staging:
needs: deploy-staging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Smoke test staging
run: ./scripts/smoke.sh https://staging.example.com
deploy-production:
needs: smoke-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Deploy the same artifact to production
run: ./scripts/deploy.sh production
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
push to main ဖြစ်တာနဲ့ build job က run ပြီး dist ကို artifact အဖြစ် တင်တယ်။ ပြီးရင် deploy-staging က staging environment ရဲ့ DEPLOY_TOKEN နဲ့ အလိုအလျောက် deploy လုပ်ပြီး smoke test ဆက် run တယ်။ deploy-production job ကတော့ ချက်ချင်း မစဘဲ approval စောင့်နေတဲ့ အနေအထားနဲ့ ရပ်နေမယ် — သတ်မှတ်ထားတဲ့ reviewer တစ်ယောက် approve လုပ်မှသာ စမယ်။ reviewer က reject လုပ်ရင် ဒါမှမဟုတ် timeout ဖြစ်ရင် အဲဒီ job က step တစ်ခုမှ မ run ဘဲ ရပ်သွားတယ်၊ production secret ကိုလည်း runner ဆီ လုံးဝ မပေးလိုက်ရဘူး။ staging job ဘက်မှာ ဘယ်လိုအမှားမျိုး ဖြစ်ဖြစ် production environment ရဲ့ secret ကို မမြင်နိုင်ပါဘူး။၅ မိနစ် စမ်းကြည့်
လက်ရှိ workflow ရဲ့ deploy-production job ထဲကို smoke test step ထပ်ထည့်ပြီး run ကြည့်ပါ — approval က smoke test ကိုပါ ပိတ်ထားတာကို သတိပြုပါ။ ပြီးရင် အဲဒါကို job သီးသန့် ခွဲထုတ်ပြီး needs: နဲ့ ချိတ်ပါ။ နောက်တစ်ဆင့်အနေနဲ့ production environment မှာ wait timer ၅ မိနစ် ထည့်ကြည့်ပြီး approve လုပ်ပြီးတဲ့နောက် ဘယ်အချိန်မှာ တကယ်စတယ်ဆိုတာ မှတ်တမ်းတင်ပါ။
သတိလေးတစ်ချက်
secret ကို repository scope မှာ ထားပြီး environment နာမည်ကိုပဲ ပြောင်းလိုက်တာ — အဲဒါဆို job တိုင်းက အဲဒီ secret ကို ဆက်ဖတ်လို့ရနေတုန်းပဲ၊ ဘာမှ ကာကွယ်ပေးမထားဘူး
deploy step နဲ့ အလိုအလျောက် လုပ်လို့ရတဲ့ step (build, test, smoke) တွေကို job တစ်ခုတည်းထဲ ရောထည့်လိုက်လို့ approval က မလိုအပ်ဘဲ အားလုံးကို ပိတ်ထားမိတာ
GitHub Docs: Using environments for deployment — CI/CD with GitHub Actions