CI/CD GitHub Angular Filebase deploy
ปกติแล้วโปรเจกต์ Angular จะแถม Git มาด้วย เมื่อใดก็ตามที่ต้องการ deploy โปรเจกต์ไปยัง Firebase ก็มักจะทำที่เครื่องตนเอง คงดีกว่านี้ถ้าได้นำโปรเจกต์ขึ้น Github แล้วใช้ Github Action ทำ automate ไปยัง Firebase แทน
บทความนี้เขียนจากมือใหม่ดังนั้นจะใช้ภาษาอธิบายที่เรียบง่ายที่สุดเพื่อเป็นฐานความคิดซึ่งจะนำไปต่อยอดความรู้ในเรื่องอื่นต่อไปครับ
เชื่อว่าตอนนี้ทุกคนรู้จัก Git แล้ว แต่สำหรับคนที่ยังไม่รู้ก็จะบอกให้รู้คร่าวๆว่า
Git คือวิธีจัดเก็บไฟล์รูปแบบหนึ่ง จะเป็นไฟล์เอกสาร รูปภาพหรือไฟล์อะไรก็ได้ เราสามารถเก็บประวัติมันได้ เช่น สร้างเมื่อไร ลบเมื่อไร แก้ไขบรรทัดไหนบ้าง แก้เปลี่ยนเป็นอะไร ใครเป็นคนทำ (ทำงานร่วมกันได้ทีละหลายคน) ซึ่งสามารถย้อนดู ณ ช่วงเวลาที่ต้องการได้ตลอด แถมหยิบ ณ ช่วงเวลานั้นออกมาใช้ได้อีกด้วย (มันดีกว่าเก็บไฟล์แยกไว้ใน folder แล้วเปลี่ยนชื่อ folder เป็นวันที่นะ)
CI/CD คืออะไร
มาถึงหัวข้อที่อยากให้รู้ CI ย่อมาจาก Continuous Integration คือจับมันมาบูรณาการหรือง่ายๆว่าทำของขึ้นมา ต้องบอกพวกเราว่าปกติแล้วกระบวนการพัฒนา software หรือโปรแกรมนั้นมันมีขั้นตอนย่อยๆมาประกอบกันครับ ยกตัวอย่างเราเขียนโค้ดเสร็จก็จะทดสอบโค้ด (เรียกว่าการเขียน test) และถ้าทำร่วมกันหลายคนก็มักจะใช้ Git มาจัดเก็บไฟล์ทั้งหมดไว้ มันจึงเป็นวิธีปฏิบัติที่แต่ละคนหรือแต่ละทีมต้องมีแบบแผนหรือข้อตกลงร่วมกันเพื่อจะส่งมอบโค้ดหรือของนั้นต่อไป
Continuous Integration ตามตัวอย่างข้างต้นจึงพูดว่าจะจัดการโค้ดอย่างไรดี? คำตอบแบบตัวอย่างก็คือ
- เราจะใช้ Git แยกงานออกเป็น branches
- เขียนโค้ดเสร็จต้องเขียน unit test
- เมื่อ push โค้ดเข้า develop branch (เราสร้างมันขึ้นมาจากข้อตกลงร่วมกัน) จะต้องรัน unit test ทั้งหมดและจะต้องผ่านทั้งหมด
- นำโค้ดทั้งหมดยกเว้น unit test มา package เป็น target หรือของที่ต้องการ เช่น ไฟล์ JavaScript ทั้งหมด package เป็นไฟล์ bundle.js
CD ย่อมาจาก Continuous Delivery หรือ Continuous Deployment ง่ายๆว่าส่งของหรือการ deploy ของ กล่าวคือหลังจาก CI ได้ของหรือ target นั้นแล้วก็จำต้องส่งมอบต่อไป
การส่งมอบแบบ Delivery คือจะยังไม่ถึงมือของลูกค้าที่จะต้องใช้ software นี้ ต่างจากแบบ Deployment ที่จะถึงมือของลูกค้าทันที ซึ่งทั้ง delivery และ deployment เป็นรูปแบบที่ดำเนินไปเองอัตโนมัติ ดูภาพประกอบ
Continuous Delivery จะไปถึงแค่ repository (ที่ที่เก็บไฟล์) เพื่อให้ทีมบริหารตัดสินใจหรือเพื่อทีมทดสอบขั้นสุดท้ายก็ได้ (และหลังจากทุกอย่างเรียบร้อยพวกเขาจะมีวิธี deploy ขึ้น production เอง) ส่วน Continuous Deployment ต่างออกไปที่เมื่อผลทดสอบผ่านทั้งหมดแล้วก็จะ deploy ขึ้น production ไปเลย
กระบวนการ CI/CD อย่างเป็นขั้นเป็นตอนนี้เรียกว่า Pipeline จะมีขั้นตอนใดบ้างมากน้อย จะต้องผ่านการอนุมัติ (approved) ก่อนหรือไม่โดยฝ่ายใดบ้างเหล่านี้แล้วแต่ตกลงกันครับ
เชื่อว่าตอนนี้ทุกคนรู้จัก CI/CD แล้ว
GitHub Actions คืออะไร
นี่เป็นหัวใจของบทความนี้เลยก็ว่าได้ พื้นฐานของ GitHub Actions ก็คือ automate หรือระบบอัตโนมัติ ถามว่าอัตโนมัติได้อย่างไร? คำตอบคือได้จากการเขียน script
GitHub คือแหล่ง repository หรือที่ที่เก็บไฟล์หรือเก็บ source code มีจุดมุ่งหมายเพื่อการพัฒนา software เป็นบริการที่ให้สมาชิกสามารถเก็บไฟล์ต่างๆตลอดจนทำ CI/CD ได้ฟรี (*หมายเหตุ มีข้อจำกัดเรื่องปริมาณการใช้งาน)
ไม่นานมานี้ GitHub ได้เพิ่มคุณลักษณะใหม่ที่เรียกว่า GitHub Actions เขาชู 2 ประเด็น ได้แก่
- Custom software development life cycle (SDLC)
- Workflows directly in your GitHub repository
Custom software development life cycle ทำความเข้าใจง่ายที่สุดคือการกำหนดวิธีหรือขั้นตอนการพัฒนาโปรแกรมได้เอง โดย source code เก็บไว้ที่ GitHub ผ่านการเขียน script
Workflows directly in your GitHub repository ก็คือการเขียน script ที่ยึดตาม Workflow syntax
Workflow syntax
คือกฏการเขียน script ที่เรียกว่า configurable automated process ซึ่งกำหนดด้วย job ต่างๆ ส่วน script นั้นสร้างจากไฟล์ YAML
รายละเอียดของการเขียนและ syntax สามารถอ่านเพิ่มเติมได้ที่ GitHub Actions Documentation บทความนี้จะเน้นที่การเขียน script ตัวอย่างเพื่อ deploy โปรเจกต์ Angular ไปยัง Firebase Hosting เพียงเท่านั้นครับ
Angular Project for Demo and GitHub Actions
เราจะสร้าง Angular ขึ้นมาหนึ่งโปรเจกต์เพื่อเป็นตัวอย่างทำ CI/CD ผ่าน GitHub Actions เมื่อใดก็ตามที่มีการเปลี่ยนแปลง (Git เรียกมันว่า changed) หรือก็คือการ push ไปยัง master branch ซึ่งอยู่บน GitHub repository ก็จะเกิด action เริ่มสร้างของ (CI) และส่งมอบของนั้น (CD) ต่อไปยัง Firebase Hosting ให้เอง ดังภาพ
- ที่ Github สร้าง repository ชื่อ tungngern-register
- ที่คอมฯเราเอง สร้างโปรเจกต์ Angular ชื่อ tungngern-register
- จากนั้นใช้ Git push source code ขึ้น Github repository
เริ่มสร้าง Actions
เลือกแท็บเขียนว่า Actions แล้วกดปุ่ม Set up this workflow
script ไฟล์ YAML นี้จะอยู่ถัดจาก root repository คือ .github/workflows/<ชื่อไฟล์>.yml
หลังจากเขียน script เสร็จแล้วมองหาปุ่ม commit ด้านขวาครับ แล้ว commit ไฟล์นี้
ผลลัพธ์
ตัวอย่าง action script
จากตัวอย่างนี้เราเลือกให้ master branch เมื่อเกิดการ changed ก็จะทำงาน action
ภายใน action กำหนดให้มีแค่ job เดียวเรียกใช้ ubuntu-latest มาทำงาน commands ของขั้นตอน Build และ Deploy
- OS ที่เลือกคือ ubuntu-latest เป็น container (ถูกดูแลและอยู่บน GitHub)
- บอกให้ OS รันคำสั่ง npm install เพื่อติดตั้ง node_modules จากนั้นสั่งให้รันคำสั่ง build ซึ่งถูกเขียนไว้ใน package.json ของโปรเจกต์ ถือว่าเสร็จสิ้นกระบวนการ CI
- บอกให้ OS รันคำสั่ง npm install -g firebase-tools เพื่อ update ไลบรารี firebase-tools ให้เป็นปัจจุบันเสมอด้วย จากนั้นสั่งให้รันคำสั่ง firebase deploy ตามด้วย token ที่ได้จากการ generated (เดี๋ยวเราพูดถึง) เพื่อ deploy หรือก็คือส่งมอบโปรเจกต์ไปยัง Firebase Hosting ถือว่าเสร็จสิ้นกระบวนการ CD (Continuous Deployment)
เป็นอันว่าเราเตรียมโปรเจกต์ Angular เสร็จแล้ว ขั้นตอนถัดไปคือ Firebase Hosting
Firebase Hosting for Demo
ตรงไปยัง Firebase
- จากนั้นให้สร้างโปรเจกต์ใหม่
Generated Token
กลับมาที่เครื่องคอมฯของเราเพื่อสร้าง Firebase token จาก account ที่เราต้องการให้เชื่อถือ (trust)
- ติดตั้ง firebase-tools หากถามสิทธิ์ให้ sudo
- ใช้ firebase-tools เรียกคำสั่ง login:ci เพื่อ generate token
sudo npm install -g firebase-tools
ตามด้วย generate token
firebase login:ci
จากตัวอย่างให้คัดลอก 1//0gVirz_XXX
ไปยัง GitHub เพื่อบอกกับ GitHub ว่าสามารถเชื่อถือ account นี้ได้
- ที่ GitHub root project เลือกแท็บ Setting
- จากนั้นเลือกเมนู Secrets และกดปุ่ม New secret
- ตั้งชื่อ secret ที่ตรงกันใน script YAML, คัดลอก token ที่ได้จากการ generated วางลงไปแล้วกดปุ่ม Add secret
ในกรณีทำงานเป็นทีมเราสามารถเพิ่ม account ที่ต้องการให้เชื่อถือได้ หรือแก้ไข token เดิมในกรณีเปลี่ยน account ก็ได้
Generated firebase.json
คำถามสำคัญก็คือ GitHub จะทราบได้อย่างไรว่าจะให้ deploy ไปยัง Firebase Hosting ไหน?
คำตอบคือ เราต้องเป็นคนบอกให้มันทราบครับ ผ่านไฟล์ firebase.json
กลับมาที่เครื่องคอมฯของเรา ตรงไปยัง root project พิมพ์
firebase init
จากหน้าจอนี้จะเลือก Firebase Hosting (ด้วยการกด spacebar ก่อนแล้ว Enter)
เลือกโปรเจกต์ที่เราได้สร้างไว้แล้วบน Firebase
เมื่อมันถามว่า What do you want to use as your public directory? ให้พิมพ์ว่า dist (หรือจะตั้งตามชอบก็ได้ แต่ส่วนมากเป็น dist และเมื่อ build เสร็จก็จะได้ target อยู่ใน folder นี้ สำคัญคือ .gitignore ที่มากับโปรเจกต์จะไม่สนใจ folder ชื่อนี้)
เมื่อมันถามว่า Configure as a single-page app (rewrite all urls to /index.html)? อันนี้ให้ตอบ Y
และเมื่อทุกอย่างแล้วเสร็จให้เราพิมพ์
git status
ปรากฏว่าเราได้ firebase.json แล้ว
และแล้วถึงคีย์สำคัญ ให้ git add, commit, pull แล้ว push ไปยัง master branch ได้เลย
Review and Fixed Bug
มาดูกันว่าความพยายามของเราประสบผลอย่างไรบ้าง และจะแก้ไขปัญหาที่พบอย่างไร
ตรงไปยัง GitHub Actions
ดูว่า commit ที่ได้กระทำส่งผลอย่างไรต่อกระบวนการใน script
- ในครั้งแรกมัน build ไม่ผ่านเพราะขาด token name
- ในครั้งที่สอง build ผ่านเพราะกำหนดแหล่ง deploy ถูกต้อง
ตรงไปยัง Firebase Hosting
ดูว่าทุกอย่างเรียบร้อยจริงไหม
จากนั้นเปิดไปดูตาม URL
ปัญหาคือหา index.html ไม่พบ
จากเหตุและผลที่ว่า ubuntu-latest จะเรียก npm รันคำสั่ง build ซึ่งถูกเขียนไว้ใน package.json ของโปรเจกต์ ฉะนั้นเราลองรัน npm run build ที่เครื่องคอมฯเราบ้าง
ปรากฏว่าได้ dist/tungngern-register ซึ่งภายในพบ index.html
ด้วยเหตุนี้จึงแก้ไขไฟล์ firebase.json ให้เป็นไปตามนั้น
เพิ่มชื่อโปรเจกต์ต่อท้าย dist ไปด้วย คั่นด้วยเครื่องหมาย /
เสร็จแล้ว git add, commit และ push อีกครั้ง
ผลลัพธ์
สรุป
GitHub Actions เป็น feature ที่ต้องการอำนวยความสะดวกแก่นักพัฒนาเมื่อ source code นั้นเก็บไว้กับ GitHub repository หนึ่งในงานของมันคือสามารถทำ CI/CD และ pipelines เพื่อส่งมอบ software ไปยังเป้าหมายโดยการจัดการขั้นตอนผ่าน script YAML
เอกสารอ้างอิง
https://www.redhat.com/en/topics/devops/what-is-ci-cd
https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow
https://dev.to/gautemeekolsen/getting-started-with-github-actions-ci-cd-firebase-deploy-5g87