ผลต่างระหว่างรุ่นของ "01204223/deployment"
Jittat (คุย | มีส่วนร่วม) |
Jittat (คุย | มีส่วนร่วม) (→ทดสอบ) |
||
| (ไม่แสดง 48 รุ่นระหว่างกลางโดยผู้ใช้คนเดียวกัน) | |||
| แถว 7: | แถว 7: | ||
เนื่องจากแอพของเรามีสองส่วน backend (ที่จะต้องทำงานบนเซิร์ฟเวอร์) และ frontend (ที่เมื่อ react build เสร็จแล้ว จะเป็นไฟล์ static ที่ส่งให้บราวเซอร์ได้เลย) จึงมีสองแนวทางในการ deploy คือการ deploy สองส่วนแยกกัน หรือจะรวมสองส่วนเข้าด้วยกันเพื่อ deploy ไปด้วยกัน เพื่อความง่ายเราจะใช้แบบที่สอง | เนื่องจากแอพของเรามีสองส่วน backend (ที่จะต้องทำงานบนเซิร์ฟเวอร์) และ frontend (ที่เมื่อ react build เสร็จแล้ว จะเป็นไฟล์ static ที่ส่งให้บราวเซอร์ได้เลย) จึงมีสองแนวทางในการ deploy คือการ deploy สองส่วนแยกกัน หรือจะรวมสองส่วนเข้าด้วยกันเพื่อ deploy ไปด้วยกัน เพื่อความง่ายเราจะใช้แบบที่สอง | ||
| − | + | เราจะทดลองใช้บริการ Google Cloud Run หรือถ้าใครอยากจะใช้ Microsoft Azure App Services ก็ได้ จะมีหลักการไม่ต่างจากกันนัก | |
| + | |||
| + | กล่าวคือ โค้ดที่เราเขียน จะถูกนำไปทำงานใน Container การที่โค้ดทำงานใน container instance ทำให้การเปิด instance เพิ่ม การปิด หรือการสร้างใหม่ทำได้สะดวกมาก แนวทางนี้มีข้อจำกัดคือเมื่อเรา deploy ระบบใหม่ container นี้จะถูกสร้างขึ้นมาใหม่ทำให้ข้อมูลจะหายหมด การจะเก็บข้อมูลเหล่านี้จะต้องใช้บริการภายนอก ยกตัวอย่างเช่น ในกรณีของเราคือเราใช้ Mysql database จากเครื่อง p1.secondtrain.org เป็นต้น | ||
| + | |||
| + | ด้านล่างเป็นภาพจาก [https://docs.cloud.google.com/run/docs/overview/what-is-cloud-run] | ||
| + | |||
| + | [[Image:223-cloud-run.png|400px]] | ||
| − | == | + | == ปรับโค้ดเพื่อ deploy == |
เราต้องปรับโค้ดของเราให้พร้อมที่จะนำไป deploy บน Google cloud run เสียก่อน โดยเครื่องมือที่เราใช้จะ copy โค้ดทั้งหมดของเราไปที่ระบบของ google และสร้าง container image โดยติดตั้ง package ตาม requirements.txt และเรียกให้ไฟล์ main.py ทำงาน ดังนี้เราต้องจัดการดังนี้ | เราต้องปรับโค้ดของเราให้พร้อมที่จะนำไป deploy บน Google cloud run เสียก่อน โดยเครื่องมือที่เราใช้จะ copy โค้ดทั้งหมดของเราไปที่ระบบของ google และสร้าง container image โดยติดตั้ง package ตาม requirements.txt และเรียกให้ไฟล์ main.py ทำงาน ดังนี้เราต้องจัดการดังนี้ | ||
| แถว 31: | แถว 37: | ||
เราจะทำไปทีละขั้น | เราจะทำไปทีละขั้น | ||
| − | + | === จัดการ mysqlclient === | |
| + | |||
| + | ใน backend | ||
| + | |||
| + | pip uninstall mysqlclient | ||
| + | |||
| + | pip install PyMySQL | ||
| + | |||
| + | pip freeze > requirements.txt | ||
| + | |||
| + | แก้ URI เปลี่ยนจาก mysql://xxxxxx เป็น mysql+pymysql://xxxxxx | ||
| + | |||
| + | === ปรับ main.py ให้ทำงานได้ และโหลด config จากไฟล์ === | ||
| + | |||
| + | Google cloud run จะเริ่มทำงานโดยเรียก main.py เลย (ไม่ได้เรียก Flask) เราเลยจะต้องทำให้ main.py ทำงานได้ และต่อกับ PORT ที่ระบุทาง environment variable | ||
| + | |||
| + | ให้เพิ่มบรรทัดด้านล่างลงที่ท้ายไฟล์ main.py | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
| แถว 38: | แถว 60: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | นอกจากนี้ เราจะต้องทำให้ main.py อ่าน config จากไฟล์ด้วย | ||
| + | |||
| + | ที่ผ่านมา Flask จะอ่านจาก .env โดยอัตโนมัติ แต่เราจะไม่ส่งไฟล์ .env ไปให้กับ google cloud run เราจะสร้างอีกไฟล์แทน (และจะต้องกำหนดให้ไฟล์ถูกส่งไปให้ cloud run ด้วย) | ||
| + | |||
| + | ให้เพิ่มไฟล์ <tt>local_config.py</tt> ลงไป โดยใส่ความลับลงไปดังต้วอย่างด้านล่าง (อย่าลืมเปลี่ยนบัญชีและรหัสผ่าน) | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
CONFIG_DB_URI = "mysql+pymysql://USERNAME:PASSWORD@p1.secondtrain.org/DBNAME" | CONFIG_DB_URI = "mysql+pymysql://USERNAME:PASSWORD@p1.secondtrain.org/DBNAME" | ||
| แถว 43: | แถว 70: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | จากนั้นใน main.py เราจะแก้ให้โหลดไฟล์ local_config.py ด้วย และนำค่าที่ได้ไปรวมกับค่าจาก environment | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
try: | try: | ||
| แถว 54: | แถว 82: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | + | เช่นเดียวกับไฟล์ .env เราจะต้องป้องกันไม่ให้ไฟล์ local_config.py ถูกส่งไปใน git repository แต่ต้องไม่ห้าม google cloud นำไฟล์ไปใช้ เราจะตั้งค่านี้ในตอนท้าย | |
| + | |||
| + | === แก้ react API URL และตั้งค่าการ build === | ||
| + | |||
| + | เราจะแก้ API endpoint แทนที่จะเป็น localhost ให้เป็นที่ url ที่ app ของเราจะไปทำงาน โดยปรับในไฟล์ App.js ดังนี้ | ||
| + | |||
| + | <syntaxhighlight lang="js"> | ||
| + | function App() { | ||
| + | const TODOLIST_API_URL = '/api/todos/'; | ||
| + | const TODOLIST_LOGIN_URL = '/api/login/'; | ||
| + | //... | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | เมื่อแก้ url ดังกล่าวแล้ว เราจะไม่สามารถรันเทสโปรแกรมได้ในเครื่องเรา เพราะว่า api จากในเว็บจะกลายเป็น localhost:5173/api ซึ่งไม่วิ่งไปที่ flask server ที่อยู่ที่ localhost:5000 | ||
| + | |||
| + | อย่างไรก็ตามใน server ของ vite มีความสามารถที่จะทำ proxy แปลงให้ request วิ่งไปที่ url ที่เราต้องการได้ โดยใส่ใน config | ||
| + | |||
| + | เราจะปรับ config ของ vite ที่อยู่ในไฟล์ frontend/vite.config.js สองประเด็นคือ | ||
| + | |||
| + | * จัดการ proxy ตอนรันคำสั่ง dev server | ||
| + | * ตั้งค่า build outDir ที่จะให้ vite build file สำหรับ frontend โดยเราจะให้ไปเก็บไฟล์ผลลัพธ์ที่ backend/frontend-static | ||
| + | |||
| + | ให้เพิ่มข้อมูลดังกล่าวลงใน frontend/vite.config.js ตามโค้ดด้านล่าง | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
| แถว 74: | แถว 125: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | < | + | จากนั้นให้ทดลองรัน |
| − | + | ||
| − | + | npm run build | |
| − | + | ||
| − | + | ใน frontend เพื่อให้ vite build แอพ react หน้าบ้านของเรา ลงในไดเร็กทอรี backend/frontend-stati จะได้ผลลัพธ์ประมาณนี้ | |
| − | + | ||
| − | </ | + | <pre> |
| + | > first-react-app@0.0.0 build | ||
| + | > vite build | ||
| + | |||
| + | vite v7.3.1 building client environment for production... | ||
| + | ✓ 47 modules transformed. | ||
| + | ../backend/frontend-static/index.html 0.46 kB │ gzip: 0.30 kB | ||
| + | ../backend/frontend-static/assets/index-RufhkGDN.css 1.40 kB │ gzip: 0.71 kB | ||
| + | ../backend/frontend-static/assets/index-rC5IratV.js 233.24 kB │ gzip: 74.45 kB | ||
| + | ✓ built in 1.39s | ||
| + | </pre> | ||
| + | |||
| + | สังเกตว่าจะมีการสร้างไฟล์ 3 ไฟล์คือ index.html ไฟล์ css และไฟล์ js | ||
| + | |||
| + | === ปรับให้ flask แจกจ่ายไฟล์ของ react === | ||
| + | |||
| + | เมื่อเรา build ไฟล์ของ react frontend แล้ว เราจะต้องหาวิธีทำให้ไฟล์เหล่านั้นไปถึง browser ของผู้ใช้ | ||
| + | |||
| + | เนื่องจาก app ของเราเป็น Flask เราจึงจะไปปรับให้ Flask เป็นผู้ส่งไฟล์ให้เรา โดยไปเพิ่ม view function ดังด้านล่าง | ||
| − | '' | + | ให้เพิ่มโค้ดไว้ที่ท้ายไฟล์ (หลัง view function อื่นทั้งหมด) แต่ก่อนบรรทัด <tt>if __name__ == '__main__':</tt> |
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
| แถว 99: | แถว 168: | ||
return send_from_directory('frontend-static', 'index.html') | return send_from_directory('frontend-static', 'index.html') | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
| + | ฟังก์ชันนี้จะดู path ทั้งหมดที่หลุดเงื่อนไขฟังก์ชันอื่น ๆ ทั้งหมด ตรวจสอบว่าเป็นไฟล์ใน frontend-static หรือไม่ ถ้าใช่ก็ส่งไฟล์ดังกล่าวไป ไม่เช่นนั้นก็จะส่งแต่ไฟล์ index.html ไปแทน | ||
| + | |||
| + | === แก้ .gitignore และเพิ่ม .gcloudignore === | ||
| + | |||
| + | เรามีไฟล์และไดเร็กทอรีที่ไม่ต้องการให้ปรากฏใน git repository เพิ่มเติม ให้'''เพิ่ม'''สองบรรทัดด้านล่างลงในไฟล์ .gitignore | ||
| + | |||
| + | /frontend-static | ||
| + | /local_config.py | ||
| + | |||
| + | อย่างไรก็ตาม เมื่อเรา deploy ด้วย google cloud run สคริปต์ในการ deploy จะไม่นำไฟล์ที่อยู่รายการ .gitignore ไปด้วย ทำให้ไฟล์ local_config.py และโค้ด react ของเราก็จะไม่ถูกนำไปด้วยเช่นเดียวกัน | ||
| + | |||
| + | เราสามารถระบุเพิ่มเติมเองว่าไฟล์ใดบ้างที่จะไม่ให้นำไปที่ google cloud โดยสร้างไฟล์ .gcloudignore แล้วระบุดังนี้ | ||
| + | |||
| + | .env | ||
| + | |||
| + | /venv | ||
| + | /instance | ||
| + | __pycache__ | ||
| + | |||
| + | สังเกตว่าเราจะไม่ระบุ local_config และ frontend-static ลงไป เพื่อให้ไฟล์ดังกล่าวถูกนำไป deploy ด้วย | ||
| + | |||
| + | === ทดสอบ === | ||
| + | |||
| + | ถ้าทุกอย่างเรียบร้อย เราจะสามารถใช้ application ของเราโดยรันแค่ main.py ได้เลย (ไม่ต้องรันทั้ง flask run และ npm run dev) โดยที่ไม่ต้องใช้ไฟล์ .env ด้วย | ||
| + | |||
| + | ให้ลองเปลี่ยนชื่อไฟล์ .env เป็นไฟล์ชื่ออื่นก่อน เช่น .env-temp แล้วรัน | ||
| + | |||
| + | python main.py | ||
| + | |||
| + | เว็บของเราจะอยู่ที่พอร์ด 8080 ซึ่งจะเข้าได้โดย http://localhost:8080/ | ||
| + | |||
| + | == Deploy ไปยัง Google cloud run == | ||
| + | |||
| + | {{กล่องเทา| | ||
| + | ในส่วนนี้ สามารถใช้บัญชี service account กลางที่แจ้งใน discord ได้ แต่ถ้าต้องการสร้างบัญชีเองให้ทำตามขั้นตอนต่อไป}} | ||
| + | |||
| + | ต้องไปสร้างบัญชีที่ [https://console.cloud.google.com/ https://console.cloud.google.com/] จากที่ทดลอง สำหรับ Google Cloud Run ถ้าต้องการเปิด web ให้เป็น public จะไม่สามารถใช้บัญชี @ku.th ได้ ให้ใช้บัญชีอื่น | ||
| + | |||
| + | [[Image:223-gcloud-register.png|400px]] | ||
| + | |||
| + | เลือก start free จากนั้นกรอกข้อมูล '''ต้องกรอกข้อมูลบัตรเครดิตด้วย''' และจะมีการชาร์จไปที่บัตรประมาณ 40 บาทให้เรายืนยันเลขในรายการ (คาดว่าจะได้รับ Refund ต่อไป) | ||
| + | |||
| + | [[Image:233-gg-card-verification.png|300px]] | ||
| + | |||
| + | เราจะใช้แนวทางจากเอกสารนี้ [https://docs.cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service] แต่อาจจะไม่ได้ทำตามทุกขั้น | ||
=== ตั้งค่าพื้นฐาน Google Cloud Run === | === ตั้งค่าพื้นฐาน Google Cloud Run === | ||
| + | |||
| + | {{กล่องเทา| | ||
| + | ถ้าใช้บัญชี service account กลางที่แจ้งใน discord ไม่ต้องสร้าง ให้ใช้ project ชื่อ practicum68 ได้เลย ให้ข้ามขั้นตอนนี้ได้}} | ||
| + | |||
| + | เราต้องไปสร้าง Project ที่จะทำงานก่อน ให้ไปกดตรง project picker (มุมซ้ายบน) ที่ตอนนี้น่าจะแสดงว่า My First Project | ||
| + | |||
| + | [[Image:223-myfirstproject.png|300px]] | ||
| + | |||
| + | จะแสดงรายการต่าง ๆ ให้เลือก New Project ที่มุมขวา จะพบหน้าจอให้กรอกข้อมูลดังด้านล่าง เลือกชื่อโปรเจ็คสักชื่อที่ชอบใจ | ||
| + | |||
| + | [[Image:223-gg-new-project.png|400px]] | ||
| + | |||
| + | เมื่อสร้าง project เสร็จ ให้เลือก project ดังกล่าว (กดที่มุมซ้ายบน) ในหน้าจอนั้นจะแสดง project ID ด้วย ให้ copy เก็บเอาไว้ (จะชื่อเหมือนที่เราตั้งแต่จะมี - ตามด้วยตัวเลขเพิ่มเติม) | ||
| + | |||
| + | [[Image:223-project-id.png|500px]] | ||
| + | |||
| + | จากนั้นให้ไปเชื่อม Billing account โดยเลือกเมนู Google Cloud (เมนูหลักมุมซ้าย) -> Billing จะเห็นหน้าจอบอกว่า project นี้ยังไม่มี billing account | ||
| + | |||
| + | [[Image:223-gg-no-billing.png|300px]] | ||
| + | |||
| + | ให้เลือก Link a billing account แล้วเลือกเป็น ''My Billing Account'' | ||
| + | |||
| + | ในการจะใช้งาน Google cloud run ได้จะต้อง enable service สองอันคือ Cloud Run Admin API และ Cloud Build API โดยสามารถทำได้จากทั้งในหน้าเว็บ และทาง cli | ||
| + | |||
| + | ถ้าทำทางหน้าเว็บให้เลือกเมนู Google Cloud -> API & Services -> Library จากนั้นให้ search "Cloud Run Admin API" และ "Cloud Build API" และเลือก Enable แต่เราสามารถตั้งค่าผ่านทาง cli ได้ | ||
| + | |||
| + | === ติดตั้งและตั้งค่าผ่านทาง Google Cloud CLI: gcloud === | ||
| + | {{กล่องเทา| | ||
| + | ถ้าใช้บัญชี service account กลางที่แจ้งใน discord ให้ทำตามขั้นตอนที่จะระบุในกล่องเทาถัดจากขั้นตอนหลัก }} | ||
| + | |||
| + | ให้ติดตั้ง cli gcloud ก่อน โดยทำตาม[https://docs.cloud.google.com/sdk/docs/install-sdk https://docs.cloud.google.com/sdk/docs/install-sdk] | ||
| + | |||
| + | จากนั้นให้ login โดยสั่ง | ||
| + | |||
| + | gcloud auth login | ||
| + | |||
| + | จะมีหน้าจอบราวเซอร์เปิดให้เรา login เมื่อเรียบร้อยจะมีหนาจอให้อนุมัติสิทธิ์ | ||
| + | |||
| + | [[Image:223-ggcloud-allow.png|400px]] | ||
| + | |||
| + | จากนั้นให้เลือก project โดยสั่ง | ||
| + | |||
| + | gcloud config set project PROJECT_ID | ||
| + | |||
| + | โดยที่ PROJECT_ID จะเป็นชื่อ project เราที่มีหมายเลขยาว ๆ ต่อ (ถ้าไม่ใส่อาจจะไปผิด project ได้) | ||
| + | |||
| + | จากนั้นให้เปิดการใช้งาน service cloud run และ cloud build | ||
| + | |||
| + | gcloud services enable run.googleapis.com cloudbuild.googleapis.com | ||
| + | |||
| + | เมื่อเปิดเรียบร้อยก็พร้อมสั่ง deploy | ||
| + | |||
| + | {{กล่องเทา| | ||
| + | '''การใช้บัญชี service account กลางในการ deploy''' ให้ดาวน์โหลด key file (ไฟล์จะชื่อ practicum68-xxxxxxxxxxx.json) จากใน discord (ห้ามทำหลุด) แล้วทำตามขั้นตอนใน discord | ||
| + | }} | ||
=== Deploy === | === Deploy === | ||
| + | |||
| + | ให้สั่ง | ||
gcloud run deploy --source . | gcloud run deploy --source . | ||
| − | Service name (backend): | + | โดยการสั่งดังกล่าวบอกว่าให้ deploy โดยให้ระบบ cloud run ไปดูเอาเองว่าโค้ดต้นทางเป็นอะไรและพยายาม deploy ตามนั้น ซึ่งของเราเป็น Flask app ระบบก็จะจัดการไปตามมาตรฐาน |
| + | |||
| + | สคริปต์จะถามชื่อ service จะใส่เป็นอะไรก็ได้ '''ถ้าใช้บัญชีกลาง ให้ใส่ชื่อไม่ให้ซ้ำกับคนอื่น อาจจะใส่เป็น todo-xxxxx โดยที่ xxxxx เป็นรหัสนิสิต 5 ตัวท้ายก็ได้ หรือจะเป็นข้อความสุ่มอื่น ๆ ก็ได้ ถ้า deploy หลายครั้งให้ใช้ชื่อเดิม จะได้ไม่เพิ่ม server มากเกินไป''' (ด้านล่างใส่ว่า todo) | ||
| + | |||
| + | Service name (backend): todo | ||
| + | |||
| + | ถ้า deploy ครั้งแรก จะมีการถามว่าจะให้สร้าง Artifact Registry Docker repository ไว้หรือไม่ ส่วนนี้ถ้า deploy บ่อยอาจจะเสียเงินได้ แต่ให้ตอบว่าให้สร้างไว้ก่อน ไม่เช่นนั้นจะ deploy ไม่ได้ | ||
| + | |||
| + | Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named | ||
| + | [cloud-run-source-deploy] in region [asia-southeast3] will be created. | ||
| + | |||
| + | Do you want to continue (Y/n)? y | ||
| + | |||
| + | และอาจมีคำถามอื่น ๆ อีก | ||
| + | |||
| + | Allow unauthenticated invocations to [todo] (y/N)? y | ||
| + | |||
| + | จากนั้นจะให้เลือก region ที่จะทำงาน ถ้าเลือก asia-southeast3 จะเป็นอยู่ในกรุงเทพ | ||
| + | |||
Please specify a region: | Please specify a region: | ||
... | ... | ||
| แถว 118: | แถว 308: | ||
Please enter numeric choice or text value (must exactly match list item): 11 | Please enter numeric choice or text value (must exactly match list item): 11 | ||
| − | Building using Buildpacks and deploying container to Cloud Run service [ | + | จากนั้นจะมีการสร้าง container และ deploy อาจจะใช้เวลาสักหน่อย |
| − | ✓ Building and deploying... Done. | + | |
| − | ✓ Validating configuration... | + | Building using Buildpacks and deploying container to Cloud Run service [todo] in project [practicum68-xxxxxxxxxxxx] region [asia-southeast3] |
| − | ✓ Uploading sources... | + | ✓ Building and deploying... Done. |
| − | ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds;region=asia- | + | ✓ Validating configuration... |
| − | + | ✓ Uploading sources... | |
| − | ✓ Creating Revision... | + | ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds;region=asia-southeast1/63e0c81f-fd33- |
| − | ✓ Routing traffic... | + | 4584-b74c-b7ef9b6b586b?project=xxxxxxxxxxxx]. |
| − | Done. | + | ✓ Creating Revision... |
| − | Service [ | + | ✓ Routing traffic... |
| − | Service URL: https:// | + | Done. |
| + | Service [todo] revision [todo-00004-xf9] has been deployed and is serving 100 percent of traffic. | ||
| + | Service URL: https://todo-xxxxxxxxxxxx.asia-southeast3.run.app | ||
| + | |||
| + | '''หมายเหตุ''' ตอนนี้ Cloud Run ถ้าเราใช้ไม่มากพอ เราจะอยู่ใน free tier แต่ถ้าเรา deploy บ่อยมาก ๆ อาจจะเสียเงินค่า Artifact Registry Docker repository ได้ ถ้า deploy หลายครั้ง ควรไปลบ | ||
| + | |||
| + | [[Image:223-artifact-registry.png|500px]] | ||
| + | |||
| + | วิธีไปหน้าดังกล่าว ไปที่ช่อง search แล้วพิมพ์ Artifact Registry | ||
| + | |||
| + | {{กล่องเทา| | ||
| + | '''การตั้งให้มีการลบ artifacts อัตโนมัติ''' ให้เลือกไปที่ Repostory (น่าจะชื่อว่า cloud-run-source-deploy) แล้วเลือก Edit repository จากนั้นในส่วน Cleanup policies ให้เลือก Delete artifacts แล้วกดเลือก ''Add a cleanup policy'' แล้วเพิ่มเงื่อนไข Keep most recent versions แล้วใส่ไปสัก 2 version ก็เพียงพอ ดังรูปด้านล่าง | ||
| + | |||
| + | [[Image:223-artifacts-policies.png|300px]] | ||
| + | }} | ||
| + | |||
| + | === การ debug === | ||
| + | |||
| + | == Deploy ไปยัง Microsoft Azure == | ||
| + | |||
| + | === สมัคร Azure === | ||
| + | {{กล่องเทา| | ||
| + | ในส่วนนี้ไม่มีบัญชีให้ใช้ทดสอบ เพราะว่าบัญชีที่เคยใช้ถูก lock เมื่อสร้างใหม่ ms ก็ไม่ยอมให้เปิดบัญชี ถ้าอยากทดลองให้ลองพยายามสร้างบัญชีเอง}} | ||
| + | |||
| + | ก่อนอื่นไปสมัครสมาชิก Microsoft azure ก่อน ที่ [https://azure.microsoft.com/en-us/products/app-service/web https://azure.microsoft.com/en-us/products/app-service/web] '''จากที่ทดลอง ไม่สามารถใช้บัญชี @live.ku.th ได้''' | ||
| + | |||
| + | ระบบจะให้สมัครสมาชิก ให้เลือก free trial | ||
| + | |||
| + | [[Image:223-azure-sub.png|300px]] | ||
| + | |||
| + | ต้องกรอกข้อมูลให้เรียบร้อย ให้เลือก Free trial (อย่าเลือก Pay-as-you-go) ต้องใส่ข้อมูลบัตรเครดิตไว้ก่อนด้วย ถ้าทำเสร็จเรียบร้อยจะได้หน้าจอประมาณนี้ | ||
| + | |||
| + | [[Image:223-azure-account-success.png|500px]] | ||
| + | |||
| + | === ติดตั้งเครื่องมือ CLI: az === | ||
| + | |||
| + | จากนั้นในการ deploy เราสามารถใช้ web interface ก็ได้ แต่เราจะใช้ cli แทน โดยให้ติดตั้ง Azure CLI โดยไปที่ [https://learn.microsoft.com/en-us/cli/azure/?view=azure-cli-latest https://learn.microsoft.com/en-us/cli/azure/?view=azure-cli-latest] แล้วดำเนินการตามส่วน Installation | ||
| + | |||
| + | [[Image:223-azure-cli-installation.png|500px]] | ||
| + | |||
| + | ถ้าติดตั้งเรียบร้อยจะสามารถเรียก cli ชื่อ <tt>az</tt> ได้ | ||
| + | |||
| + | az | ||
| + | |||
| + | === Deploy === | ||
| + | |||
| + | ถ้าเราปรับโค้ดตามข้างต้นเรียบร้อย เราแทบจะเสร็จสิ้นการเตรียมการ อย่างไรก็ตาม Azure ต้องการให้โปรแกรมหลักของเราชื่อ <tt>app.py</tt> แทนที่จะเป็น <tt>main.py</tt> | ||
| + | |||
| + | ให้เปลี่ยนชื่อ main.py เป็น app.py ก่อน โดยอาจจะสั่ง | ||
| + | |||
| + | mv main.py app.py | ||
| + | |||
| + | และให้ทดลองเรียก Flask ให้ทำงาน (อย่าลืมตั้งค่า FLASK_APP ด้วย) ถ้าจะ commit ลง git อย่าลืม add app.py | ||
| + | |||
| + | เราสามารถ deploy อัตโนมัติได้สะดวกมาก โดยเข้าไปใน backend แล้วสั่ง | ||
| + | |||
| + | az login | ||
| + | |||
| + | จากนั้นจะมี web browser ปรากฏขึ้น ใน login ให้เรียบร้อย | ||
| + | |||
| + | จากนั้นสั่ง | ||
| + | |||
| + | az webapp up --runtime PYTHON:3.14 --sku F1 --logs | ||
| + | |||
| + | ตรงส่วน sku ให้ดูดี ๆ ให้ใส่ F1 จะเป็น free tier | ||
| + | |||
| + | จากนั้นรอพักใหญ่ สคริปต์จะทำงานให้ผลลัพธ์ประมาณนี้ '''และจะรันค้างอยู่ เพราะว่าเราสั่งให้มีการแสดง logs ค้างไว้''' เมื่อแอพ deploy เรียบร้อยให้กด Ctrl-C ออกมาได้เลย | ||
| + | |||
| + | <pre> | ||
| + | The webapp 'jolly-rock-xxxyyyzzzxxxyyyzzz' doesn't exist | ||
| + | Creating Resource group 'jittat_rg_1414' ... | ||
| + | Resource group creation complete | ||
| + | Creating AppServicePlan 'jittat_asp_2900' or Updating if already exists | ||
| + | Resource provider 'Microsoft.Web' used by this operation is not registered. We are registering for you. | ||
| + | Registration succeeded. | ||
| + | Creating webapp 'jolly-rock-xxxyyyzzzxxxyyyzzz' ... | ||
| + | vnet_route_all_enabled is not a known attribute of class <class 'azure.mgmt.web.v2024_11_01.models._models_py3.Site'> and will be ignored | ||
| + | Configuring default logging for the app, if not already enabled | ||
| + | Creating zip with contents of dir /home/jittat/prog/test/flask-react-todo-start/backend ... | ||
| + | Getting scm site credentials for zip deployment | ||
| + | Starting zip deployment. This operation can take a while to complete ... | ||
| + | Warming up Kudu before deployment. | ||
| + | Deployment endpoint responded with status code 202 | ||
| + | Polling the status of async deployment. Start Time: 2026-03-03 03:40:15.411645+00:00 UTC | ||
| + | Status: Building the app... Time: 1(s) | ||
| + | Status: Building the app... Time: 18(s) | ||
| + | Status: Build successful. Time: 34(s) | ||
| + | Status: Starting the site... Time: 51(s) | ||
| + | Status: Starting the site... Time: 67(s) | ||
| + | Status: Starting the site... Time: 83(s) | ||
| + | Status: Starting the site... Time: 99(s) | ||
| + | Status: Site started successfully. Time: 115(s) | ||
| + | You can launch the app at http://jolly-rock-xxxyyyzzzxxxyyyzzz.azurewebsites.net | ||
| + | Configuring default logging for the app, if not already enabled | ||
| + | 2026-03-03T03:52:16 Welcome, you are now connected to log-streaming service. | ||
| + | Starting Log Tail -n 10 of existing logs ---- | ||
| + | /home/LogFiles/kudu/trace/7398fc64b7fd-4e462719-2827-4576-8e9f-a6874c374779.txt (https://xxxxxxxxxxxxxxxxxxxxxxxx) | ||
| + | 2026-03-03T03:50:12 Startup Request, url: /api/zipdeploy?isAsync=true, method: POST, type: request, pid: 852,1,14, ScmType: None, SCM_DO_BUILD_DURING_DEPLOYMENT: True | ||
| + | /home/LogFiles/2026_03_03_10-30-0-139_default_docker.log (https://xxxxxxxxxxxxxxxxxxxxxxxx/api/vfs/LogFiles/2026_03_03_10-30-0-139_default_docker.log) | ||
| + | </pre> | ||
| + | |||
| + | app ที่เรา deploy แล้วจะปรากฏในรายการ App Services ของ Azure portal ทุกครั้งที่เราสั่ง deploy ตามด้านบน เราไม่ได้กำหนดชื่อ จะทำให้ได้ app ใหม่เกิดขึ้นเรื่อย ๆ | ||
| + | |||
| + | [[Image:223-azure-deployed.png|700px]] | ||
| + | |||
| + | ถ้าต้องการให้ deploy ทับของเดิมให้เพิ่ม option <tt>-n APPNAME</tt> และนอกจากนี้ถ้าเราไม่สั่งอะไร จะได้ app ไปทำงานที่ Canada ซึ่งจะช้ามาก เราสามารถเลือกที่อื่นได้ เช่นที่ญี่ปุ่น ให้เพิ่ม option <tt>-l japanwest</tt> เป็นต้น ดังนั้นคำสั่งอาจจะเป็น | ||
| + | az webapp up --runtime PYTHON:3.14 --sku F1 --logs -n practicum68-todo -l japanwest | ||
| − | + | ถ้าพบ error ระหว่างสั่ง ให้ลองอ่าน อาจจะต้องไปลบ resource ที่ใช้ที่ canada ทิ้งก่อน | |
รุ่นแก้ไขปัจจุบันเมื่อ 08:52, 6 มีนาคม 2569
- หน้านี้เป็นส่วนหนึ่งของ 01204223
เราจะฝึกการนำแอพที่เราสร้างไปติดตั้งในระบบเพื่อใช้งานจริง ถ้าเราไม่ได้มีเซิร์ฟเวอร์เอง การใช้บริการ cloud deployment ก็เป็นอีกทางเลือกที่มีประโยชน์ หลายครั้งยังทำให้ระบบที่เราทำขึ้นรองรับโหลดได้หลากหลาย โดยแทบไม่ต้องปรับแก้
วิธีการที่มาตรฐานที่สุดคือการใช้ container แต่ในวิชานี้เราไม่มีเวลาศึกษาเรื่องดังกล่าว เราจึงจะใช้การติดตั้งแบบอัตโนมัติที่มีการสร้าง container ถ้าเราใช้โครงสร้าง project ตามรูปแบบมาตรฐาน
เนื่องจากแอพของเรามีสองส่วน backend (ที่จะต้องทำงานบนเซิร์ฟเวอร์) และ frontend (ที่เมื่อ react build เสร็จแล้ว จะเป็นไฟล์ static ที่ส่งให้บราวเซอร์ได้เลย) จึงมีสองแนวทางในการ deploy คือการ deploy สองส่วนแยกกัน หรือจะรวมสองส่วนเข้าด้วยกันเพื่อ deploy ไปด้วยกัน เพื่อความง่ายเราจะใช้แบบที่สอง
เราจะทดลองใช้บริการ Google Cloud Run หรือถ้าใครอยากจะใช้ Microsoft Azure App Services ก็ได้ จะมีหลักการไม่ต่างจากกันนัก
กล่าวคือ โค้ดที่เราเขียน จะถูกนำไปทำงานใน Container การที่โค้ดทำงานใน container instance ทำให้การเปิด instance เพิ่ม การปิด หรือการสร้างใหม่ทำได้สะดวกมาก แนวทางนี้มีข้อจำกัดคือเมื่อเรา deploy ระบบใหม่ container นี้จะถูกสร้างขึ้นมาใหม่ทำให้ข้อมูลจะหายหมด การจะเก็บข้อมูลเหล่านี้จะต้องใช้บริการภายนอก ยกตัวอย่างเช่น ในกรณีของเราคือเราใช้ Mysql database จากเครื่อง p1.secondtrain.org เป็นต้น
ด้านล่างเป็นภาพจาก [1]
ปรับโค้ดเพื่อ deploy
เราต้องปรับโค้ดของเราให้พร้อมที่จะนำไป deploy บน Google cloud run เสียก่อน โดยเครื่องมือที่เราใช้จะ copy โค้ดทั้งหมดของเราไปที่ระบบของ google และสร้าง container image โดยติดตั้ง package ตาม requirements.txt และเรียกให้ไฟล์ main.py ทำงาน ดังนี้เราต้องจัดการดังนี้
- ทำให้การติดตั้ง package ทำงานได้สมบูรณ์ (ปรับ requirements.txt)
- ทำให้ main.py ทำงานได้ (พร้อมกับ config ต่าง ๆ)
- รวมโค้ด frontend จาก react ที่ปรับ api url แล้ว, และเพิ่มโค้ดให้ flask server เป็นคนแจกจ่าย frontend code
ขั้นตอนข้างต้นมีรายละเอียดคร่าว ๆ ดังนี้
- โปรแกรมหลักที่จะถูกเรียกทำงานคือ main.py เราต้องปรับให้โปรแกรมดังกล่าวทำงานได้เลย (แทนที่เดิมเราเคยเรียก flask run)
- เดิมเราใช้ package mysqlclient ในการเชื่อมต่อกับ MySQL แต่การติดตั้ง package ดังกล่าวมีการคอมไพล์โค้ดภาษาซีซึ่งใน container ไม่ได้มีมาด้วย เราจะต้องเปลี่ยนไปใช้ package PyMySQL ที่เป็นไลบรารี python ล้วนในการเชื่อมต่อ
- เราต้องติดตั้ง PyMySQL
- แก้ requirements.txt
- ปรับ URI ของ database
- ต้องเปลี่ยนการจัดการ config ให้โหลดจากไฟล์ local_config.py
- อย่าลืมปรับ .gitignore
- เราต้อง build โค้ดส่วน frontend และนำมาใส่ไดเร็กทอรี backend
- ต้องปรับ URL endpoint ด้วย
- เพิ่มโค้ดใน Flask ให้ serve ไฟล์ frontend ด้วย
เราจะทำไปทีละขั้น
จัดการ mysqlclient
ใน backend
pip uninstall mysqlclient
pip install PyMySQL
pip freeze > requirements.txt
แก้ URI เปลี่ยนจาก mysql://xxxxxx เป็น mysql+pymysql://xxxxxx
ปรับ main.py ให้ทำงานได้ และโหลด config จากไฟล์
Google cloud run จะเริ่มทำงานโดยเรียก main.py เลย (ไม่ได้เรียก Flask) เราเลยจะต้องทำให้ main.py ทำงานได้ และต่อกับ PORT ที่ระบุทาง environment variable
ให้เพิ่มบรรทัดด้านล่างลงที่ท้ายไฟล์ main.py
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
นอกจากนี้ เราจะต้องทำให้ main.py อ่าน config จากไฟล์ด้วย
ที่ผ่านมา Flask จะอ่านจาก .env โดยอัตโนมัติ แต่เราจะไม่ส่งไฟล์ .env ไปให้กับ google cloud run เราจะสร้างอีกไฟล์แทน (และจะต้องกำหนดให้ไฟล์ถูกส่งไปให้ cloud run ด้วย)
ให้เพิ่มไฟล์ local_config.py ลงไป โดยใส่ความลับลงไปดังต้วอย่างด้านล่าง (อย่าลืมเปลี่ยนบัญชีและรหัสผ่าน)
CONFIG_DB_URI = "mysql+pymysql://USERNAME:PASSWORD@p1.secondtrain.org/DBNAME"
CONFIG_JWT_SECRET = 'fdslkfjsdlkufewhjroiewurewrew'
จากนั้นใน main.py เราจะแก้ให้โหลดไฟล์ local_config.py ด้วย และนำค่าที่ได้ไปรวมกับค่าจาก environment
try:
from local_config import CONFIG_DB_URI, CONFIG_JWT_SECRET
except:
CONFIG_DB_URI = 'sqlite:///todos.db'
CONFIG_JWT_SECRET = 'fdslkfjsdlkufewhjroiewurewrew'
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('SQLALCHEMY_DATABASE_URI', CONFIG_DB_URI)
app.config['JWT_SECRET_KEY'] = os.getenv('JWT_SECRET_KEY', CONFIG_JWT_SECRET)
เช่นเดียวกับไฟล์ .env เราจะต้องป้องกันไม่ให้ไฟล์ local_config.py ถูกส่งไปใน git repository แต่ต้องไม่ห้าม google cloud นำไฟล์ไปใช้ เราจะตั้งค่านี้ในตอนท้าย
แก้ react API URL และตั้งค่าการ build
เราจะแก้ API endpoint แทนที่จะเป็น localhost ให้เป็นที่ url ที่ app ของเราจะไปทำงาน โดยปรับในไฟล์ App.js ดังนี้
function App() {
const TODOLIST_API_URL = '/api/todos/';
const TODOLIST_LOGIN_URL = '/api/login/';
//...
}
เมื่อแก้ url ดังกล่าวแล้ว เราจะไม่สามารถรันเทสโปรแกรมได้ในเครื่องเรา เพราะว่า api จากในเว็บจะกลายเป็น localhost:5173/api ซึ่งไม่วิ่งไปที่ flask server ที่อยู่ที่ localhost:5000
อย่างไรก็ตามใน server ของ vite มีความสามารถที่จะทำ proxy แปลงให้ request วิ่งไปที่ url ที่เราต้องการได้ โดยใส่ใน config
เราจะปรับ config ของ vite ที่อยู่ในไฟล์ frontend/vite.config.js สองประเด็นคือ
- จัดการ proxy ตอนรันคำสั่ง dev server
- ตั้งค่า build outDir ที่จะให้ vite build file สำหรับ frontend โดยเราจะให้ไปเก็บไฟล์ผลลัพธ์ที่ backend/frontend-static
ให้เพิ่มข้อมูลดังกล่าวลงใน frontend/vite.config.js ตามโค้ดด้านล่าง
export default defineConfig({
// ...
server: {
proxy: {
'/api': {
target: 'http://localhost:5000/',
changeOrigin: true,
},
},
},
build: {
outDir: '../backend/frontend-static',
emptyOutDir: true,
},
})
จากนั้นให้ทดลองรัน
npm run build
ใน frontend เพื่อให้ vite build แอพ react หน้าบ้านของเรา ลงในไดเร็กทอรี backend/frontend-stati จะได้ผลลัพธ์ประมาณนี้
> first-react-app@0.0.0 build > vite build vite v7.3.1 building client environment for production... ✓ 47 modules transformed. ../backend/frontend-static/index.html 0.46 kB │ gzip: 0.30 kB ../backend/frontend-static/assets/index-RufhkGDN.css 1.40 kB │ gzip: 0.71 kB ../backend/frontend-static/assets/index-rC5IratV.js 233.24 kB │ gzip: 74.45 kB ✓ built in 1.39s
สังเกตว่าจะมีการสร้างไฟล์ 3 ไฟล์คือ index.html ไฟล์ css และไฟล์ js
ปรับให้ flask แจกจ่ายไฟล์ของ react
เมื่อเรา build ไฟล์ของ react frontend แล้ว เราจะต้องหาวิธีทำให้ไฟล์เหล่านั้นไปถึง browser ของผู้ใช้
เนื่องจาก app ของเราเป็น Flask เราจึงจะไปปรับให้ Flask เป็นผู้ส่งไฟล์ให้เรา โดยไปเพิ่ม view function ดังด้านล่าง
ให้เพิ่มโค้ดไว้ที่ท้ายไฟล์ (หลัง view function อื่นทั้งหมด) แต่ก่อนบรรทัด if __name__ == '__main__':
from flask import send_from_directory
# Catch-all route: if the requested file exists in frontend-static, serve it;
# otherwise fall back to serving the React app's index.html.
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve_frontend(path):
static_dir = os.path.join(app.root_path, 'frontend-static')
# If a specific file is requested and exists, serve it
if path and os.path.isfile(os.path.join(static_dir, path)):
return send_from_directory('frontend-static', path)
# Otherwise serve the app entrypoint
return send_from_directory('frontend-static', 'index.html')
ฟังก์ชันนี้จะดู path ทั้งหมดที่หลุดเงื่อนไขฟังก์ชันอื่น ๆ ทั้งหมด ตรวจสอบว่าเป็นไฟล์ใน frontend-static หรือไม่ ถ้าใช่ก็ส่งไฟล์ดังกล่าวไป ไม่เช่นนั้นก็จะส่งแต่ไฟล์ index.html ไปแทน
แก้ .gitignore และเพิ่ม .gcloudignore
เรามีไฟล์และไดเร็กทอรีที่ไม่ต้องการให้ปรากฏใน git repository เพิ่มเติม ให้เพิ่มสองบรรทัดด้านล่างลงในไฟล์ .gitignore
/frontend-static /local_config.py
อย่างไรก็ตาม เมื่อเรา deploy ด้วย google cloud run สคริปต์ในการ deploy จะไม่นำไฟล์ที่อยู่รายการ .gitignore ไปด้วย ทำให้ไฟล์ local_config.py และโค้ด react ของเราก็จะไม่ถูกนำไปด้วยเช่นเดียวกัน
เราสามารถระบุเพิ่มเติมเองว่าไฟล์ใดบ้างที่จะไม่ให้นำไปที่ google cloud โดยสร้างไฟล์ .gcloudignore แล้วระบุดังนี้
.env /venv /instance __pycache__
สังเกตว่าเราจะไม่ระบุ local_config และ frontend-static ลงไป เพื่อให้ไฟล์ดังกล่าวถูกนำไป deploy ด้วย
ทดสอบ
ถ้าทุกอย่างเรียบร้อย เราจะสามารถใช้ application ของเราโดยรันแค่ main.py ได้เลย (ไม่ต้องรันทั้ง flask run และ npm run dev) โดยที่ไม่ต้องใช้ไฟล์ .env ด้วย
ให้ลองเปลี่ยนชื่อไฟล์ .env เป็นไฟล์ชื่ออื่นก่อน เช่น .env-temp แล้วรัน
python main.py
เว็บของเราจะอยู่ที่พอร์ด 8080 ซึ่งจะเข้าได้โดย http://localhost:8080/
Deploy ไปยัง Google cloud run
ในส่วนนี้ สามารถใช้บัญชี service account กลางที่แจ้งใน discord ได้ แต่ถ้าต้องการสร้างบัญชีเองให้ทำตามขั้นตอนต่อไป
ต้องไปสร้างบัญชีที่ https://console.cloud.google.com/ จากที่ทดลอง สำหรับ Google Cloud Run ถ้าต้องการเปิด web ให้เป็น public จะไม่สามารถใช้บัญชี @ku.th ได้ ให้ใช้บัญชีอื่น
เลือก start free จากนั้นกรอกข้อมูล ต้องกรอกข้อมูลบัตรเครดิตด้วย และจะมีการชาร์จไปที่บัตรประมาณ 40 บาทให้เรายืนยันเลขในรายการ (คาดว่าจะได้รับ Refund ต่อไป)
เราจะใช้แนวทางจากเอกสารนี้ [2] แต่อาจจะไม่ได้ทำตามทุกขั้น
ตั้งค่าพื้นฐาน Google Cloud Run
ถ้าใช้บัญชี service account กลางที่แจ้งใน discord ไม่ต้องสร้าง ให้ใช้ project ชื่อ practicum68 ได้เลย ให้ข้ามขั้นตอนนี้ได้
เราต้องไปสร้าง Project ที่จะทำงานก่อน ให้ไปกดตรง project picker (มุมซ้ายบน) ที่ตอนนี้น่าจะแสดงว่า My First Project
จะแสดงรายการต่าง ๆ ให้เลือก New Project ที่มุมขวา จะพบหน้าจอให้กรอกข้อมูลดังด้านล่าง เลือกชื่อโปรเจ็คสักชื่อที่ชอบใจ
เมื่อสร้าง project เสร็จ ให้เลือก project ดังกล่าว (กดที่มุมซ้ายบน) ในหน้าจอนั้นจะแสดง project ID ด้วย ให้ copy เก็บเอาไว้ (จะชื่อเหมือนที่เราตั้งแต่จะมี - ตามด้วยตัวเลขเพิ่มเติม)
จากนั้นให้ไปเชื่อม Billing account โดยเลือกเมนู Google Cloud (เมนูหลักมุมซ้าย) -> Billing จะเห็นหน้าจอบอกว่า project นี้ยังไม่มี billing account
ให้เลือก Link a billing account แล้วเลือกเป็น My Billing Account
ในการจะใช้งาน Google cloud run ได้จะต้อง enable service สองอันคือ Cloud Run Admin API และ Cloud Build API โดยสามารถทำได้จากทั้งในหน้าเว็บ และทาง cli
ถ้าทำทางหน้าเว็บให้เลือกเมนู Google Cloud -> API & Services -> Library จากนั้นให้ search "Cloud Run Admin API" และ "Cloud Build API" และเลือก Enable แต่เราสามารถตั้งค่าผ่านทาง cli ได้
ติดตั้งและตั้งค่าผ่านทาง Google Cloud CLI: gcloud
ถ้าใช้บัญชี service account กลางที่แจ้งใน discord ให้ทำตามขั้นตอนที่จะระบุในกล่องเทาถัดจากขั้นตอนหลัก
ให้ติดตั้ง cli gcloud ก่อน โดยทำตามhttps://docs.cloud.google.com/sdk/docs/install-sdk
จากนั้นให้ login โดยสั่ง
gcloud auth login
จะมีหน้าจอบราวเซอร์เปิดให้เรา login เมื่อเรียบร้อยจะมีหนาจอให้อนุมัติสิทธิ์
จากนั้นให้เลือก project โดยสั่ง
gcloud config set project PROJECT_ID
โดยที่ PROJECT_ID จะเป็นชื่อ project เราที่มีหมายเลขยาว ๆ ต่อ (ถ้าไม่ใส่อาจจะไปผิด project ได้)
จากนั้นให้เปิดการใช้งาน service cloud run และ cloud build
gcloud services enable run.googleapis.com cloudbuild.googleapis.com
เมื่อเปิดเรียบร้อยก็พร้อมสั่ง deploy
การใช้บัญชี service account กลางในการ deploy ให้ดาวน์โหลด key file (ไฟล์จะชื่อ practicum68-xxxxxxxxxxx.json) จากใน discord (ห้ามทำหลุด) แล้วทำตามขั้นตอนใน discord
Deploy
ให้สั่ง
gcloud run deploy --source .
โดยการสั่งดังกล่าวบอกว่าให้ deploy โดยให้ระบบ cloud run ไปดูเอาเองว่าโค้ดต้นทางเป็นอะไรและพยายาม deploy ตามนั้น ซึ่งของเราเป็น Flask app ระบบก็จะจัดการไปตามมาตรฐาน
สคริปต์จะถามชื่อ service จะใส่เป็นอะไรก็ได้ ถ้าใช้บัญชีกลาง ให้ใส่ชื่อไม่ให้ซ้ำกับคนอื่น อาจจะใส่เป็น todo-xxxxx โดยที่ xxxxx เป็นรหัสนิสิต 5 ตัวท้ายก็ได้ หรือจะเป็นข้อความสุ่มอื่น ๆ ก็ได้ ถ้า deploy หลายครั้งให้ใช้ชื่อเดิม จะได้ไม่เพิ่ม server มากเกินไป (ด้านล่างใส่ว่า todo)
Service name (backend): todo
ถ้า deploy ครั้งแรก จะมีการถามว่าจะให้สร้าง Artifact Registry Docker repository ไว้หรือไม่ ส่วนนี้ถ้า deploy บ่อยอาจจะเสียเงินได้ แต่ให้ตอบว่าให้สร้างไว้ก่อน ไม่เช่นนั้นจะ deploy ไม่ได้
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [asia-southeast3] will be created. Do you want to continue (Y/n)? y
และอาจมีคำถามอื่น ๆ อีก
Allow unauthenticated invocations to [todo] (y/N)? y
จากนั้นจะให้เลือก region ที่จะทำงาน ถ้าเลือก asia-southeast3 จะเป็นอยู่ในกรุงเทพ
Please specify a region: ... [8] asia-south2 [9] asia-southeast1 [10] asia-southeast2 [11] asia-southeast3 [12] australia-southeast1 [13] australia-southeast2 ... Please enter numeric choice or text value (must exactly match list item): 11
จากนั้นจะมีการสร้าง container และ deploy อาจจะใช้เวลาสักหน่อย
Building using Buildpacks and deploying container to Cloud Run service [todo] in project [practicum68-xxxxxxxxxxxx] region [asia-southeast3] ✓ Building and deploying... Done. ✓ Validating configuration... ✓ Uploading sources... ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds;region=asia-southeast1/63e0c81f-fd33- 4584-b74c-b7ef9b6b586b?project=xxxxxxxxxxxx]. ✓ Creating Revision... ✓ Routing traffic... Done. Service [todo] revision [todo-00004-xf9] has been deployed and is serving 100 percent of traffic. Service URL: https://todo-xxxxxxxxxxxx.asia-southeast3.run.app
หมายเหตุ ตอนนี้ Cloud Run ถ้าเราใช้ไม่มากพอ เราจะอยู่ใน free tier แต่ถ้าเรา deploy บ่อยมาก ๆ อาจจะเสียเงินค่า Artifact Registry Docker repository ได้ ถ้า deploy หลายครั้ง ควรไปลบ
วิธีไปหน้าดังกล่าว ไปที่ช่อง search แล้วพิมพ์ Artifact Registry
การตั้งให้มีการลบ artifacts อัตโนมัติ ให้เลือกไปที่ Repostory (น่าจะชื่อว่า cloud-run-source-deploy) แล้วเลือก Edit repository จากนั้นในส่วน Cleanup policies ให้เลือก Delete artifacts แล้วกดเลือก Add a cleanup policy แล้วเพิ่มเงื่อนไข Keep most recent versions แล้วใส่ไปสัก 2 version ก็เพียงพอ ดังรูปด้านล่าง
การ debug
Deploy ไปยัง Microsoft Azure
สมัคร Azure
ในส่วนนี้ไม่มีบัญชีให้ใช้ทดสอบ เพราะว่าบัญชีที่เคยใช้ถูก lock เมื่อสร้างใหม่ ms ก็ไม่ยอมให้เปิดบัญชี ถ้าอยากทดลองให้ลองพยายามสร้างบัญชีเอง
ก่อนอื่นไปสมัครสมาชิก Microsoft azure ก่อน ที่ https://azure.microsoft.com/en-us/products/app-service/web จากที่ทดลอง ไม่สามารถใช้บัญชี @live.ku.th ได้
ระบบจะให้สมัครสมาชิก ให้เลือก free trial
ต้องกรอกข้อมูลให้เรียบร้อย ให้เลือก Free trial (อย่าเลือก Pay-as-you-go) ต้องใส่ข้อมูลบัตรเครดิตไว้ก่อนด้วย ถ้าทำเสร็จเรียบร้อยจะได้หน้าจอประมาณนี้
ติดตั้งเครื่องมือ CLI: az
จากนั้นในการ deploy เราสามารถใช้ web interface ก็ได้ แต่เราจะใช้ cli แทน โดยให้ติดตั้ง Azure CLI โดยไปที่ https://learn.microsoft.com/en-us/cli/azure/?view=azure-cli-latest แล้วดำเนินการตามส่วน Installation
ถ้าติดตั้งเรียบร้อยจะสามารถเรียก cli ชื่อ az ได้
az
Deploy
ถ้าเราปรับโค้ดตามข้างต้นเรียบร้อย เราแทบจะเสร็จสิ้นการเตรียมการ อย่างไรก็ตาม Azure ต้องการให้โปรแกรมหลักของเราชื่อ app.py แทนที่จะเป็น main.py
ให้เปลี่ยนชื่อ main.py เป็น app.py ก่อน โดยอาจจะสั่ง
mv main.py app.py
และให้ทดลองเรียก Flask ให้ทำงาน (อย่าลืมตั้งค่า FLASK_APP ด้วย) ถ้าจะ commit ลง git อย่าลืม add app.py
เราสามารถ deploy อัตโนมัติได้สะดวกมาก โดยเข้าไปใน backend แล้วสั่ง
az login
จากนั้นจะมี web browser ปรากฏขึ้น ใน login ให้เรียบร้อย
จากนั้นสั่ง
az webapp up --runtime PYTHON:3.14 --sku F1 --logs
ตรงส่วน sku ให้ดูดี ๆ ให้ใส่ F1 จะเป็น free tier
จากนั้นรอพักใหญ่ สคริปต์จะทำงานให้ผลลัพธ์ประมาณนี้ และจะรันค้างอยู่ เพราะว่าเราสั่งให้มีการแสดง logs ค้างไว้ เมื่อแอพ deploy เรียบร้อยให้กด Ctrl-C ออกมาได้เลย
The webapp 'jolly-rock-xxxyyyzzzxxxyyyzzz' doesn't exist Creating Resource group 'jittat_rg_1414' ... Resource group creation complete Creating AppServicePlan 'jittat_asp_2900' or Updating if already exists Resource provider 'Microsoft.Web' used by this operation is not registered. We are registering for you. Registration succeeded. Creating webapp 'jolly-rock-xxxyyyzzzxxxyyyzzz' ... vnet_route_all_enabled is not a known attribute of class <class 'azure.mgmt.web.v2024_11_01.models._models_py3.Site'> and will be ignored Configuring default logging for the app, if not already enabled Creating zip with contents of dir /home/jittat/prog/test/flask-react-todo-start/backend ... Getting scm site credentials for zip deployment Starting zip deployment. This operation can take a while to complete ... Warming up Kudu before deployment. Deployment endpoint responded with status code 202 Polling the status of async deployment. Start Time: 2026-03-03 03:40:15.411645+00:00 UTC Status: Building the app... Time: 1(s) Status: Building the app... Time: 18(s) Status: Build successful. Time: 34(s) Status: Starting the site... Time: 51(s) Status: Starting the site... Time: 67(s) Status: Starting the site... Time: 83(s) Status: Starting the site... Time: 99(s) Status: Site started successfully. Time: 115(s) You can launch the app at http://jolly-rock-xxxyyyzzzxxxyyyzzz.azurewebsites.net Configuring default logging for the app, if not already enabled 2026-03-03T03:52:16 Welcome, you are now connected to log-streaming service. Starting Log Tail -n 10 of existing logs ---- /home/LogFiles/kudu/trace/7398fc64b7fd-4e462719-2827-4576-8e9f-a6874c374779.txt (https://xxxxxxxxxxxxxxxxxxxxxxxx) 2026-03-03T03:50:12 Startup Request, url: /api/zipdeploy?isAsync=true, method: POST, type: request, pid: 852,1,14, ScmType: None, SCM_DO_BUILD_DURING_DEPLOYMENT: True /home/LogFiles/2026_03_03_10-30-0-139_default_docker.log (https://xxxxxxxxxxxxxxxxxxxxxxxx/api/vfs/LogFiles/2026_03_03_10-30-0-139_default_docker.log)
app ที่เรา deploy แล้วจะปรากฏในรายการ App Services ของ Azure portal ทุกครั้งที่เราสั่ง deploy ตามด้านบน เราไม่ได้กำหนดชื่อ จะทำให้ได้ app ใหม่เกิดขึ้นเรื่อย ๆ
ถ้าต้องการให้ deploy ทับของเดิมให้เพิ่ม option -n APPNAME และนอกจากนี้ถ้าเราไม่สั่งอะไร จะได้ app ไปทำงานที่ Canada ซึ่งจะช้ามาก เราสามารถเลือกที่อื่นได้ เช่นที่ญี่ปุ่น ให้เพิ่ม option -l japanwest เป็นต้น ดังนั้นคำสั่งอาจจะเป็น
az webapp up --runtime PYTHON:3.14 --sku F1 --logs -n practicum68-todo -l japanwest
ถ้าพบ error ระหว่างสั่ง ให้ลองอ่าน อาจจะต้องไปลบ resource ที่ใช้ที่ canada ทิ้งก่อน













