Thuta Learning
CI/CD with GitHub Actions
ExercisesDevOps & Toolsbeginner

Exercise: Release Pipeline တစ်ခု တည်ဆောက်ခြင်း

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Exercise: Release Pipeline တစ်ခု တည်ဆောက်ခြင်း concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • Diagram ကို ဖတ်ပြီး pipeline ထဲမှာ job တွေ ဘယ်လိုစီးဆင်းပြီး ဘာက gate လုပ်သလဲ ခြေရာခံနိုင်ရန်
  • Workflow file ကို ဖတ်ပြီး ဘယ် job တွေ ဘယ်အစဉ်လိုက် run မလဲ ကြိုတင်ပြောနိုင်ရန်

နားလည်ထားရမယ့် အချက်

Release pipeline တစ်ခုဟာ CI pipeline နဲ့ အဓိကကွာတဲ့ အချက်တစ်ခု ရှိတယ် — CI က တစ်နေ့ကို အကြိမ်ကြိမ် run ပြီး သူ့အမှားတွေက စျေးပေါတယ်။ Release ကတော့ ရံဖန်ရံခါမှ run တယ်၊ လူတွေ မြင်နေတဲ့ရှေ့မှာ run တယ်၊ ပြီးတော့ သူ့အမှားတွေက customer တွေ တိုက်ရိုက်မြင်ရတယ်။ ဒါကြောင့် design goal တွေက ပြောင်းသွားတယ်။ သင် test လုပ်ခဲ့တဲ့ အရာအတိအကျကိုပဲ ship လုပ်ချင်တယ်၊ branch ပေါ်မှာ ဘာရှိနေရှိနေ မဟုတ်ဘဲ tag တစ်ခုကနေ ပြန်ထုတ်လို့ရတဲ့ release ကို လိုချင်တယ်၊ ပြီးတော့ production ကို ဘာမှ မထိခင် လူတစ်ယောက် ကြားထဲမှာ ရှိစေချင်တယ်။

အဲဒီအလေးချိန်အများစုကို သဘောတရားသုံးခုက ထမ်းထားတယ်။ ပထမက tag trigger ပါ — on: push: tags: ['v*'] ဆိုတာက pipeline ကို မပြောင်းလဲနိုင်တဲ့ နာမည်တစ်ခုက စတင်စေတယ်၊ ဒါကြောင့် v1.2.3 ဟာ commit တစ်ခုတည်းကိုပဲ အမြဲညွှန်းပြီး workflow ကို ပြန် run ရင်လည်း တူညီတဲ့ tree ကိုပဲ build မယ်။ ဒုတိယက တစ်ခါတည်း build ပြီး နောက်မှာ ပြန်သုံးဖို့ပါ။ build job မှာ တစ်ခါ compile လုပ်၊ deploy job မှာ ထပ် compile လုပ်တဲ့ pipeline ဟာ ဘယ်သူမှ မစမ်းသပ်ရသေးတဲ့ artifact တစ်ခုကို ship လုပ်လိုက်တာပါ။ actions/upload-artifact@v4 နဲ့ တင်ပြီး actions/download-artifact@v4 နဲ့ ပြန်ဆွဲချတာက test လုပ်ခဲ့တဲ့ bytes တွေကိုပဲ ship လုပ်တဲ့ bytes ဖြစ်စေတယ်။ တတိယက environment gate ပါ။ job တစ်ခုပေါ်က environment: block ဟာ အလှဆင်ချက် မဟုတ်ဘူး — အဲဒီ environment မှာ repository settings ကနေ required reviewers သတ်မှတ်ထားရင် job က ရပ်စောင့်ပြီး သတ်မှတ်ထားတဲ့ လူတစ်ယောက်ရဲ့ approval ကို စောင့်တယ်၊ ပြီးတော့ အဲဒီ environment အောက်မှာ scope လုပ်ထားတဲ့ secret တွေဟာ gate မဖြတ်ရသေးတဲ့ ဘယ် job အတွက်မှ မရရှိနိုင်ဘူး။

အောက်က scaffold က ပထမသဘောတရားကို အပြည့်အစုံ အကောင်အထည်ဖော်ထားပြီး ကျန်နှစ်ခုကို သင့်အတွက် ချန်ထားတယ်။

text
RELEASE PIPELINE: DONE VS TODO
------------------------------
-------------------------------

     git push origin v1.2.3
               |
               v
     [ build ]  -- DONE, leave this alone
     checkout -> npm ci -> npm run build -> tar -> upload
               |
               |  artifact: release-bundle
               v
     [ publish ]  -- TODO (stub only echoes)
     download artifact -> create GitHub Release, attach tarball
     needs: permissions: contents: write
               |
               v
     [ deploy-production ]  -- TODO (stub only echoes)
     environment: production -> WAITS FOR HUMAN APPROVAL
               |
               v
        production is live

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

ကျန်နေတဲ့ job တွေကို မရေးခင် သူတို့မှီခိုနေတဲ့ setup ကို အရင်လုပ်ပါ — မလုပ်ရင် နှစ်ခုလုံး ရှင်းလင်းမှုမရှိတဲ့ ပုံစံနဲ့ fail ဖြစ်ပါလိမ့်မယ်။ သင့် repository မှာ Settings ကနေ Environments ကို သွားပြီး production ဆိုတဲ့ environment တစ်ခု ဆောက်ပါ။ 'Required reviewers' ကို အမှန်ခြစ်ပြီး ကိုယ့်ကိုယ်ကို ထည့်ပါ။ ဒါဆိုရင် နောက်ပိုင်း environment: production လို့ ကြေညာတဲ့ ဘယ် job မဆို ရပ်ပြီး click တစ်ချက်ကို စောင့်တော့မယ်။

နောက်တစ်ခုက permissions ပါ။ Release တစ်ခု ဆောက်တာဟာ repository ကို ရေးတာဖြစ်ပြီး၊ workflow ထဲက default GITHUB_TOKEN ဟာ repository အများစုမှာ read-only ဖြစ်တယ်။ ဒါကြောင့် publish job မှာ contents: write ပေးတဲ့ permissions: block ကိုယ်ပိုင် လိုတယ် — workflow level မဟုတ်ဘဲ job level မှာ ထားပါ၊ ဒါမှ build job က ပိုသေးတဲ့ permission set ကို ဆက်ထိန်းထားနိုင်မယ်။ ဒီအတွက် personal access token မလိုပါဘူး၊ permission ပေးလိုက်ရင် secrets.GITHUB_TOKEN နဲ့ လုံလောက်တယ်။

ပြီးရင် တကယ်သုံးမယ့်ပုံစံအတိုင်း စမ်းပါ။ commit တစ်ခုကို git tag v0.0.1-test နဲ့ tag လုပ်ပြီး git push origin v0.0.1-test နဲ့ တင်ပါ။ build job က artifact ထုတ်တာကို ကြည့်၊ ပြီးရင် publish job က ထပ် build မလုပ်ဘဲ အဲဒီ artifact ကိုပဲ download လုပ်တာကို အတည်ပြုပါ။ ထပ်စမ်းချင်ရင် tag ကို local နဲ့ remote နှစ်ဖက်လုံးက ဖျက်ပြီး ပြန် push ပါ — နာမည်တူ release တစ်ခုနဲ့ တိုက်မိမှာမို့ ထုတ်ထားပြီးသား draft Release ကိုပါ ဖျက်ဖို့ မမေ့ပါနဲ့။

အတူတူ စမ်းရေးကြည့်မယ်

yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Check out the tagged commit
        uses: actions/checkout@v4
      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: npm
      - name: Install dependencies
        run: npm ci
      - name: Build the release bundle
        run: npm run build
      - name: Package the bundle
        run: tar -czf app-${{ github.ref_name }}.tar.gz dist
      - name: Upload the release artifact
        uses: actions/upload-artifact@v4
        with:
          name: release-bundle
          path: app-${{ github.ref_name }}.tar.gz
          retention-days: 30

  # TODO(you) - replace this stub with a real publish job. It should grant
  # itself contents write permission, download the release-bundle artifact
  # with actions/download-artifact@v4, and create a GitHub Release for the
  # tag in github.ref_name with the tarball attached as an asset.
  publish:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Not implemented yet
        run: echo 'TODO - download release-bundle and publish a GitHub Release'

  # TODO(you) - this job must not run until a human approves it. Add an
  # environment block naming a protected environment (for example the
  # production environment you configured with required reviewers), then
  # replace the echo with the real deployment command.
  deploy-production:
    runs-on: ubuntu-latest
    needs: publish
    steps:
      - name: Not implemented yet
        run: echo 'TODO - deploy the published release to production'
You should see
ဒီအတိုင်းဆိုရင် scaffold ဟာ အလုပ်လုပ်ပေမယ့် မပြည့်စုံသေးတဲ့ pipeline တစ်ခုပါ။ v* နဲ့ ကိုက်တဲ့ tag တစ်ခု push လိုက်ရင် သူ စတယ်။ build job ကတော့ အစစ်အမှန်ဖြစ်ပြီး ပြည့်စုံတယ် — tag လုပ်ထားတဲ့ commit ကို checkout လုပ်တယ်၊ npm ci နဲ့ dependency သွင်းတယ်၊ production build ကို run တယ်၊ dist ကို tag နာမည်နဲ့ tarball တစ်ခုအဖြစ် package လုပ်တယ်၊ ပြီးရင် release-bundle ဆိုတဲ့ artifact အဖြစ် retention 30 ရက်နဲ့ upload လုပ်တယ်။ အဲဒီအပိုင်းက တကယ် အလုပ်လုပ်တယ်။

ကျန်တဲ့ job နှစ်ခုကတော့ stub တွေပါ။ publish က build ကို စောင့်ပြီး TODO message တစ်ကြောင်း echo လုပ်ရုံပဲ — release-bundle ကို ဘယ်တော့မှ download မလုပ်ဘူး၊ GitHub Release ကို မဆောက်ဘူး၊ contents write permission လည်း မရှိဘူး၊ ဒါကြောင့် repository ရဲ့ Releases page မှာ ဘာမှ ပေါ်လာမှာ မဟုတ်ဘူး။ deploy-production က publish ကို စောင့်ပြီး ဒုတိယ TODO တစ်ကြောင်း echo လုပ်တယ် — environment block မရှိတဲ့အတွက် ဘာမှ approval အတွက် မရပ်ဘူး၊ environment secret တွေလည်း မရဘူး။ stub job နှစ်ခုစလုံးက success လို့ ပြတဲ့အတွက် run တစ်ခုလုံးက အစိမ်းရောင်နဲ့ ပြီးသွားပေမယ့် တကယ်တော့ ဘာမှ ship မလုပ်ဖြစ်ဘူး။ အဲဒီအစိမ်းရောင်ကပဲ ထောင်ချောက်ပါ — echo step တွေကို မလဲမချင်း run အောင်မြင်တာဟာ build compile ဖြစ်တယ်ဆိုတာလောက်ကိုပဲ သက်သေပြတယ်။

၅ မိနစ် စမ်းကြည့်

Pipeline ကို အပြီးသတ်ပါ။ tag တစ်ခုတည်း push လိုက်ရုံနဲ့ — git tag v1.2.3 ပြီးတော့ git push origin v1.2.3 — workflow run တစ်ခုတည်းအတွင်းမှာ အောက်ပါသုံးချက်ကို အဲဒီအစီအစဉ်အတိုင်း လုပ်ပေးနိုင်ရင် သင် ပြီးပြီ။

တစ် — project ကို တစ်ခါတည်းသာ build လုပ်ရမယ်။ နောက်က job တွေထဲမှာ ဒုတိယ npm run build တစ်ခုမှ မရှိရဘူး၊ နောက်ပိုင်း job တိုင်းက build job ထုတ်ပေးလိုက်တဲ့ release-bundle artifact ကနေပဲ အလုပ်လုပ်ရမယ်။

နှစ် — repository ရဲ့ Releases page မှာ tag နာမည်နဲ့ Release တစ်ခု ပေါ်လာရမယ်၊ tarball ကိုလည်း download လုပ်လို့ရတဲ့ asset အဖြစ် တွဲပါလာရမယ်။ stub publish job ကို ဖယ်ပြီး ကိုယ့်ကိုယ်ကို contents: write ပေးတဲ့၊ actions/download-artifact@v4 နဲ့ release-bundle ကို ဆွဲချတဲ့၊ ပြီးရင် release ဆောက်တဲ့ job တစ်ခုနဲ့ အစားထိုးပါ — step ရဲ့ env: မှာ GH_TOKEN: secrets.GITHUB_TOKEN ထားပြီး gh release create "$GITHUB_REF_NAME" ./app-*.tar.gz --generate-notes ဆိုတာက အသေးဆုံး အလုပ်ဖြစ်တဲ့ နည်းလမ်းပါ။

သုံး — လူတစ်ယောက် approve မလုပ်မချင်း production deploy က မ run ရဘူး။ deploy-production ကို သင် ပြင်ဆင်ထားတဲ့ protected environment ကို ညွှန်းတဲ့ environment: တစ်ခု ပေးပြီး၊ run က တကယ် 'Waiting for review' အခြေအနေမှာ ရပ်နေတာကို အတည်ပြုပါ — ဖြတ်ကျော်မသွားစေရဘူး။

အဲဒါပြီးရင် ထပ်တိုးလေ့ကျင့်ခန်း — tag မှာ hyphen ပါရင် (v1.2.3-rc1) release ကို draft အဖြစ်၊ မပါရင် release အပြည့်အဝအဖြစ် ထုတ်အောင် လုပ်ပါ။ ဒါဆိုရင် pre-release tag တွေက watcher တွေဆီ notification မပို့တော့ဘူး။

သတိလေးတစ်ချက်

artifact ကို download မလုပ်ဘဲ deploy job ထဲမှာ ပြန် build လုပ်ခြင်း — အဲဒီအခါ run ထဲက ဘယ် job မှ မစမ်းသပ်ရသေးတဲ့ bytes တွေကို ship လုပ်လိုက်တာ ဖြစ်သွားတယ်။

publish job မှာ permissions: contents: write ထည့်ဖို့ မေ့ခြင်း — default GITHUB_TOKEN က read-only ဖြစ်လို့ ကျန် step တွေ အားလုံးမှန်နေရဲ့သားနဲ့ Release ဆောက်တဲ့အဆင့်မှာ 403 နဲ့ fail ဖြစ်သွားတယ်။

GitHub Docs: Managing environments for deploymentCI/CD with GitHub Actions

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • artifact ကို download မလုပ်ဘဲ deploy job ထဲမှာ ပြန် build လုပ်ခြင်း — အဲဒီအခါ run ထဲက ဘယ် job မှ မစမ်းသပ်ရသေးတဲ့ bytes တွေကို ship လုပ်လိုက်တာ ဖြစ်သွားတယ်။
  • publish job မှာ permissions: contents: write ထည့်ဖို့ မေ့ခြင်း — default GITHUB_TOKEN က read-only ဖြစ်လို့ ကျန် step တွေ အားလုံးမှန်နေရဲ့သားနဲ့ Release ဆောက်တဲ့အဆင့်မှာ 403 နဲ့ fail ဖြစ်သွားတယ်။
  • Workflow ကို production branch ပေါ် တိုက်ရိုက်မစမ်းဘဲ branch (သို့) test repository တွင် အရင်အတည်ပြုပါ။

လေ့ကျင့်ခန်း

Pipeline ကို အပြီးသတ်ပါ။ tag တစ်ခုတည်း push လိုက်ရုံနဲ့ — git tag v1.2.3 ပြီးတော့ git push origin v1.2.3 — workflow run တစ်ခုတည်းအတွင်းမှာ အောက်ပါသုံးချက်ကို အဲဒီအစီအစဉ်အတိုင်း လုပ်ပေးနိုင်ရင် သင် ပြီးပြီ။

တစ် — project ကို တစ်ခါတည်းသာ build လုပ်ရမယ်။ နောက်က job တွေထဲမှာ ဒုတိယ npm run build တစ်ခုမှ မရှိရဘူး၊ နောက်ပိုင်း job တိုင်းက build job ထုတ်ပေးလိုက်တဲ့ release-bundle artifact ကနေပဲ အလုပ်လုပ်ရမယ်။

နှစ် — repository ရဲ့ Releases page မှာ tag နာမည်နဲ့ Release တစ်ခု ပေါ်လာရမယ်၊ tarball ကိုလည်း download လုပ်လို့ရတဲ့ asset အဖြစ် တွဲပါလာရမယ်။ stub publish job ကို ဖယ်ပြီး ကိုယ့်ကိုယ်ကို contents: write ပေးတဲ့၊ actions/download-artifact@v4 နဲ့ release-bundle ကို ဆွဲချတဲ့၊ ပြီးရင် release ဆောက်တဲ့ job တစ်ခုနဲ့ အစားထိုးပါ — step ရဲ့ env: မှာ GH_TOKEN: secrets.GITHUB_TOKEN ထားပြီး gh release create "$GITHUB_REF_NAME" ./app-*.tar.gz --generate-notes ဆိုတာက အသေးဆုံး အလုပ်ဖြစ်တဲ့ နည်းလမ်းပါ။

သုံး — လူတစ်ယောက် approve မလုပ်မချင်း production deploy က မ run ရဘူး။ deploy-production ကို သင် ပြင်ဆင်ထားတဲ့ protected environment ကို ညွှန်းတဲ့ environment: တစ်ခု ပေးပြီး၊ run က တကယ် 'Waiting for review' အခြေအနေမှာ ရပ်နေတာကို အတည်ပြုပါ — ဖြတ်ကျော်မသွားစေရဘူး။

အဲဒါပြီးရင် ထပ်တိုးလေ့ကျင့်ခန်း — tag မှာ hyphen ပါရင် (v1.2.3-rc1) release ကို draft အဖြစ်၊ မပါရင် release အပြည့်အဝအဖြစ် ထုတ်အောင် လုပ်ပါ။ ဒါဆိုရင် pre-release tag တွေက watcher တွေဆီ notification မပို့တော့ဘူး။

You'll know it worked when: ဒီအတိုင်းဆိုရင် scaffold ဟာ အလုပ်လုပ်ပေမယ့် မပြည့်စုံသေးတဲ့ pipeline တစ်ခုပါ။ v* နဲ့ ကိုက်တဲ့ tag တစ်ခု push လိုက်ရင် သူ စတယ်။ build job ကတော့ အစစ်အမှန်ဖြစ်ပြီး ပြည့်စုံတယ် — tag လုပ်ထားတဲ့ commit ကို checkout လုပ်တယ်၊ npm ci နဲ့ dependency သွင်းတယ်၊ production build ကို run တယ်၊ dist ကို tag နာမည်နဲ့ tarball တစ်ခုအဖြစ် package လုပ်တယ်၊ ပြီးရင် release-bundle ဆိုတဲ့ artifact အဖြစ် retention 30 ရက်နဲ့ upload လုပ်တယ်။ အဲဒီအပိုင်းက တကယ် အလုပ်လုပ်တယ်။ ကျန်တဲ့ job နှစ်ခုကတော့ stub တွေပါ။ publish က build ကို စောင့်ပြီး TODO message တစ်ကြောင်း echo လုပ်ရုံပဲ — release-bundle ကို ဘယ်တော့မှ download မလုပ်ဘူး၊ GitHub Release ကို မဆောက်ဘူး၊ contents write permission လည်း မရှိဘူး၊ ဒါကြောင့် repository ရဲ့ Releases page မှာ ဘာမှ ပေါ်လာမှာ မဟုတ်ဘူး။ deploy-production က publish ကို စောင့်ပြီး ဒုတိယ TODO တစ်ကြောင်း echo လုပ်တယ် — environment block မရှိတဲ့အတွက် ဘာမှ approval အတွက် မရပ်ဘူး၊ environment secret တွေလည်း မရဘူး။ stub job နှစ်ခုစလုံးက success လို့ ပြတဲ့အတွက် run တစ်ခုလုံးက အစိမ်းရောင်နဲ့ ပြီးသွားပေမယ့် တကယ်တော့ ဘာမှ ship မလုပ်ဖြစ်ဘူး။ အဲဒီအစိမ်းရောင်ကပဲ ထောင်ချောက်ပါ — echo step တွေကို မလဲမချင်း run အောင်မြင်တာဟာ build compile ဖြစ်တယ်ဆိုတာလောက်ကိုပဲ သက်သေပြတယ်။

Exercise: Release Pipeline တစ်ခု တည်ဆောက်ခြင်း | Thuta Learning