คู่มือการทดลองและติดตั้งระบบในรูปแบบ Multi-Student
คู่มือ Step-by-Step สำหรับผู้เรียนในการติดตั้งและจัดการโปรเจกต์ Parich ERP แยกคอนเทนเนอร์เป็นของตัวเองขนานกันบนเซิร์ฟเวอร์หลัก 1 เครื่อง โดยเข้าผ่านชื่อโดเมนหลักและแยกพอร์ตส่วนตัว
1. Ubuntu Basic Commands (คำสั่ง Ubuntu ที่จำเป็นสำหรับการทำ Workshop)
ก่อนเริ่มต้นกิจกรรม นักเรียนจำเป็นต้องมีความคุ้นเคยกับคำสั่งจัดการเซิร์ฟเวอร์พื้นฐานในระบบ Linux/Ubuntu ดังต่อไปนี้:
1.1 การจัดการไฟล์ โฟลเดอร์ และสิทธิ์ (File System & Permissions)
| คำสั่ง (Command) | คำอธิบาย (Description) | ตัวอย่างการใช้งาน (Example) |
|---|---|---|
cd |
ย้ายตำแหน่งโฟลเดอร์ปัจจุบัน (Change Directory) | cd /home/pui/workshop/s1 |
cd .. |
ย้อนกลับออกไปนอกโฟลเดอร์ปัจจุบัน 1 ชั้น (จุดสองจุด .. หมายถึงโฟลเดอร์แม่ชั้นบน) |
cd .. |
ls -la |
แสดงรายชื่อไฟล์ทั้งหมด (รวมถึงไฟล์ซ่อน เช่น .env, .git) |
ls -la |
cp |
คัดลอกไฟล์หรือโฟลเดอร์ (ใช้ -r สำหรับโฟลเดอร์) |
cp .env.dist .env |
mv |
ย้ายไฟล์ หรือเปลี่ยนชื่อไฟล์ | mv old_name.txt new_name.txt |
chmod |
เปลี่ยนสิทธิ์การเข้าถึงไฟล์/โฟลเดอร์ | chmod 755 script.sh (อนุญาตให้รันได้) |
chown |
เปลี่ยนเจ้าของไฟล์/โฟลเดอร์ | chown pui:pui server_setup_guide.html |
1.2 การวิเคราะห์ระบบและดูทรัพยากร (System Analysis & Resources)
| คำสั่ง (Command) | คำอธิบาย (Description) | ตัวอย่างการใช้งาน (Example) |
|---|---|---|
df -h |
ตรวจสอบพื้นที่ว่างบนหน่วยจัดเก็บข้อมูล (Disk Space) | df -h |
free -m |
ตรวจสอบการใช้งาน RAM (หน่วยเป็น MB) | free -m |
ps aux | grep |
ตรวจสอบสถานะโปรเซสว่าโปรแกรมกำลังรันอยู่หรือไม่ | ps aux | grep nginx |
tail -f |
ดู Log หรือเนื้อหาท้ายไฟล์แบบ Real-time ตามจริง | tail -f /var/log/nginx/error.log |
systemctl |
ตรวจสอบ ควบคุม หรือรีสตาร์ท Service บนระบบ Host | sudo systemctl reload nginx |
1.3 คำสั่ง Docker Compose ควรรู้
| คำสั่ง (Command) | คำอธิบาย (Description) | ตัวอย่างการใช้งาน (Example) |
|---|---|---|
docker compose build |
สั่งบิลด์อิมเมจจาก Dockerfile ล่าสุดในโครงการ | docker compose build |
docker compose up -d |
เริ่มรัน Container ในพื้นหลัง (Background) | docker compose up -d |
docker compose ps |
ตรวจสอบสถานะคอนเทนเนอร์ปัจจุบันในโฟลเดอร์โครงการ | docker compose ps |
docker compose logs -f |
ดูประวัติการบันทึก (Logs) ของคอนเทนเนอร์แบบ Real-time | docker compose logs -f backend |
docker compose down |
สั่งลบและปิดบริการ Container ทั้งหมดในโครงการ | docker compose down |
2. Workshop & Port Matrix (การกำหนดสิทธิ์และพื้นที่ส่วนตัว)
เพื่อให้นักเรียนทุกคนสามารถรันโปรเจกต์ของตัวเองควบคู่กันได้บนระบบปฏิบัติการ Ubuntu เดียวกันโดยไม่ชนกัน เราจะใช้ระบบระบุตัวตน Student ID (เช่น s1, s2, ...) เพื่อแยกพอร์ต คอนเทนเนอร์ และฐานข้อมูล ดังนี้:
Single Domain: demo-parichportal.loolootest.com
การเข้าหน้าเว็บของนักเรียน (s1):
- หน้าบ้าน (Frontend):
https://demo-parichportal.loolootest.com:3001 - หลังบ้าน (Backend API):
https://demo-parichportal.loolootest.com:8001
| Student ID (N) | URL หน้าบ้าน (Frontend) | URL หลังบ้าน (Backend) | Database Name | Redis DB Index |
|---|---|---|---|---|
| s1 | https://demo-parichportal.loolootest.com:3001 | https://demo-parichportal.loolootest.com:8001 | parich_db_s1 | 1 |
| s2 | https://demo-parichportal.loolootest.com:3002 | https://demo-parichportal.loolootest.com:8002 | parich_db_s2 | 2 |
| s3 | https://demo-parichportal.loolootest.com:3003 | https://demo-parichportal.loolootest.com:8003 | parich_db_s3 | 3 |
| sN | https://demo-parichportal.loolootest.com:3000+N | https://demo-parichportal.loolootest.com:8000+N | parich_db_sN | N |
ห้ามใช้พอร์ตหรือชื่อฐานข้อมูลซ้ำกับเพื่อนร่วมชั้นเรียน และระวังอย่าพิมพ์ทับซ้อนข้อมูลคอนเทนเนอร์กันเด็ดขาด
3. Hybrid Architecture (สถาปัตยกรรมระบบไฮบริด)
ระบบของ Parich ERP ทำงานในรูปแบบ Hybrid Architecture เพื่อผลลัพธ์ที่ดีที่สุด:
Docker Container ของผู้เรียน
Nuxt Frontend (พอร์ต 3000+N)
Django Backend (พอร์ต 8000+N)
Host OS (Ubuntu 24.04)
Nginx (Reverse Proxy ประจำพอร์ต)
PostgreSQL 16 & Redis (ร่วมกัน)
จุดประสงค์ของการทำ Hybrid:
- Django ใน Docker: ช่วยควบคุมสภาพแวดล้อมระบบและ Python runtime 3.14 ให้อยู่แยกเป็นกล่องๆ ของน้องแต่ละคนอย่างปลอดภัย
- PostgreSQL 16 & Redis บน Host OS: เพื่อลดปริมาณการเขียนอ่านไฟล์ในคอนเทนเนอร์ ประสิทธิภาพดีกว่าการรันในตู้ และสะดวกต่อผู้สอนในการจัดการ/ตรวจดู DB
4. OS & Core Setup (การติดตั้งระบบพื้นฐาน)
ขั้นตอนนี้ปกติแล้วผู้สอนจะติดตั้งเตรียมไว้ให้เรียบร้อยแล้ว แต่น้องๆ ควรรู้คำสั่งเหล่านี้สำหรับการตั้งค่าเซิร์ฟเวอร์ Linux ใหม่:
# 1. ติดตั้ง PostgreSQL, Redis, Nginx และ Docker บน Host OS
sudo apt update && sudo apt install -y curl git build-essential libmagic1 postgresql-16 redis-server nginx docker-ce
sudo systemctl enable postgresql redis-server nginx docker
sudo systemctl start postgresql redis-server nginx docker
น้องๆ ทุกคนจะได้รับสิทธิ์เข้ากลุ่ม docker เพื่อไม่ต้องใช้ sudo ทุกครั้งในการสั่งรันคอนเทนเนอร์:
sudo usermod -aG docker $USER && newgrp docker
5. Database Isolation (การจองและแยกแยะฐานข้อมูล)
ให้นักเรียนสร้าง Database และกำหนดสิทธิ์การเข้าใช้งานเป็นของตัวเองบน PostgreSQL ของระบบเซิร์ฟเวอร์ร่วม:
# 1. ล็อกอินเข้าใช้งาน PostgreSQL shell
sudo -u postgres psql
# 2. สร้างฐานข้อมูลของตนเอง (เปลี่ยน sN เป็นรหัสของนักเรียน เช่น s1, s2, s3)
CREATE DATABASE parich_db_sN;
# 3. ให้สิทธิ์การเข้าถึงทั้งหมดแก่ผู้ใช้ django_ci (ซึ่งกำหนดไว้ใน .env)
GRANT ALL PRIVILEGES ON DATABASE parich_db_sN TO django_ci;
\q
5.2 การ Restore ข้อมูลทดสอบ (Database Restore)
เพื่อให้น้องๆ มีข้อมูลจำลองสำหรับทดสอบใช้งานและพัฒนาต่อได้ทันที ให้ทำการกู้คืน (Restore) ฐานข้อมูลจากไฟล์ dump ต้นแบบที่จัดเตรียมไว้ให้บนเซิร์ฟเวอร์:
# รันคำสั่ง pg_restore ผ่านสิทธิ์ผู้ดูแลฐานข้อมูล postgres เพื่อย้ายข้อมูลเข้า parich_db_sN ของตนเอง
# (เปลี่ยน sN ให้เป็นชื่อ DB ที่ตั้งไว้ในขั้นตอนแรก เช่น parich_db_s1)
sudo -u postgres pg_restore --no-owner --no-privileges -d parich_db_sN /tmp/puidb_test_backup.dump
6. Workspace & Git Workflow (การเตรียมโค้ด)
เนื่องจากทั้ง **Backend** และ **Frontend** อยู่ใน **Repository เดียวกันแต่คนละ Branch** ให้นักเรียนทำการโคลนโปรเจกต์เต็มรูปแบบลงมา 2 โฟลเดอร์แยกกัน แล้วใช้คำสั่ง checkout สลับไปแต่ละ Branch เพื่อเรียนรู้คำสั่ง Git:
เราจะแยกโฟลเดอร์สำหรับทำงานหลังบ้าน (backend-project) สลับไปที่สาขา backend/base และหน้าบ้าน (frontend-project) สลับไปที่สาขา nuxt-frontend/base
# ตัวอย่างสำหรับนักเรียน s1 (เปลี่ยนโฟลเดอร์ตาม Student ID ของตัวเอง)
mkdir -p /home/pui/workshop/s1
cd /home/pui/workshop/s1
# 1. โคลน Repository เพื่อพัฒนา Backend
# เมื่อโคลนเสร็จแล้ว ให้ย้ายเข้าโฟลเดอร์เพื่อ checkout สาขา backend/base
# และใช้คำสั่ง cd .. เพื่อย้อนกลับมาที่โฟลเดอร์ระดับบนก่อนเริ่มขั้นถัดไป
git clone ssh://git@code.loolootech.com/loolootech/fertilizer-erp.git backend-project
cd backend-project
git checkout backend/base
cd ..
# 2. โคลน Repository เพื่อพัฒนา Frontend (Nuxt)
# เมื่อโคลนเสร็จแล้ว ให้ย้ายเข้าโฟลเดอร์เพื่อ checkout สาขา nuxt-frontend/base
git clone ssh://git@code.loolootech.com/loolootech/fertilizer-erp.git frontend-project
cd frontend-project
git checkout nuxt-frontend/base
cd ..
7. .env Configuration (การตั้งค่า Config ส่วนบุคคล)
เพื่อไม่ให้เกิดการชนกันของระบบ คอนฟิกูเรชันใน `.env` ของแต่ละคนจะต้องแตกต่างกันอย่างสิ้นเชิง ให้นักเรียนสร้างและตั้งค่าคอนฟิกดังนี้:
7.1 การตั้งค่าฝั่ง Backend (Django)
cd /home/pui/workshop/s1/backend-project/backend
cp .env.dist .env
nano .env
ตัวอย่างการเปลี่ยนค่าตัวแปรใน .env ของ Backend นักเรียน s1:
# แยกชื่อโครงการในระบบ Docker Compose
COMPOSE_PROJECT_NAME=parich-s1
# ผูกพอร์ต Backend ของตัวเองตามตารางข้อ 2 (s1 ใช้ 8001)
HOST_BACKEND_PORT=8001
# ชี้ฐานข้อมูลไปยังตัวที่เราสร้างไว้ในข้อ 5
DB_NAME=parich_db_s1
DB_USER=django_ci
DB_PASSWORD=django_ci_password
DB_HOST=host.docker.internal # เข้าถึงฐานข้อมูลบน Host OS ผ่านเครือข่าย Docker
# แยกฐานข้อมูล Redis Index ของระบบ Cache
REDIS_HOST=host.docker.internal
REDIS_PORT=6379
REDIS_URL=redis://host.docker.internal:6379/1
7.2 การตั้งค่าฝั่ง Frontend (Nuxt)
cd /home/pui/workshop/s1/frontend-project/nuxt_frontend
cp .env.dist .env
nano .env
ตัวอย่างการเปลี่ยนค่าตัวแปร in .env ของ Frontend นักเรียน s1:
# แยกชื่อโครงการฝั่งหน้าบ้าน
COMPOSE_PROJECT_NAME=parich-s1-fe
# ผูกพอร์ต Frontend ของตัวเองตามตารางข้อ 2 (s1 ใช้ 3001)
HOST_FRONTEND_PORT=3001
# ชี้ API Base URL ไปยัง Backend พอร์ต 8001 ของตัวเอง (ต้องผ่านโดเมนและพอร์ตตรงๆ เพื่อความปลอดภัย)
API_BASE_URL=https://demo-parichportal.loolootest.com:8001/api
8. Build & Deploy (การรันคำสั่ง Docker Compose เพื่อเรียนรู้ระบบ)
เพื่อให้นักเรียนเข้าใจกระบวนการทำงานเบื้องหลังของตู้คอนเทนเนอร์ เราจะสั่งงานโปรเจกต์ตรงด้วยคำสั่ง **Docker Compose** ทีละขั้นตอน:
8.1 การรันระบบและจัดการฐานข้อมูลฝั่ง Backend (Django)
ย้ายเข้าโฟลเดอร์ Backend จากนั้นทำตามขั้นตอนต่อไปนี้:
cd /home/pui/workshop/s1/backend-project/backend
# 1. สั่งสร้าง (Build) Image จาก Dockerfile.prod ของระบบหลังบ้าน
docker compose build
# 2. สั่งรันบริการ Backend ขึ้นมาในพื้นหลัง (Background Mode)
docker compose up -d
# 3. ตรวจสอบสถานะการรันคอนเทนเนอร์ของตนเอง
docker compose ps
# 4. สั่ง Migrate ฐานข้อมูลเข้าไปในฐานข้อมูล PostgreSQL บน Host OS ของตนเอง
docker compose exec -T backend python manage.py migrate
# 5. สั่งรวบรวมไฟล์ Static Assets ทั้งหมด เพื่อไปเตรียมเสิร์ฟที่ Host OS
docker compose exec -T backend python manage.py collectstatic --no-input
8.2 การรันระบบฝั่ง Frontend (Nuxt)
ย้ายเข้าโฟลเดอร์ Frontend Nuxt จากนั้นทำตามขั้นตอนต่อไปนี้:
cd /home/pui/workshop/s1/frontend-project/nuxt_frontend
# 1. สั่งสร้าง (Build) Image ซึ่งจะทำการคอมไพล์โค้ด Nuxt ลงในคอนเทนเนอร์
docker compose build
# 2. สั่งรันบริการ Frontend ขึ้นมา
docker compose up -d
# 3. ตรวจสอบดูว่า Frontend รันพอร์ต 3001 ของเราเรียบร้อยดีหรือไม่
docker compose ps
9. Nginx Proxy & SSL (การตั้งค่าจัดเส้นทางพอร์ตนักเรียน)
เพื่อให้สามารถเข้าผ่านชื่อโดเมนหลักทาง HTTPS ได้อย่างปลอดภัย (แก้ปัญหา Not Secure) ผู้สอนหรือนักเรียนจะทำการตั้งค่าเพิ่มบล็อก Nginx บน Host OS เพื่อรับสัญญาณ HTTPS พอร์ตของตัวเองส่งเข้าหา Container ภายในของตนเอง:
ชี้จากโดเมนรวมเข้าหาพอร์ตภายในของน้องแต่ละคนด้วย Config นี้:
# ไฟล์คอนฟิกตัวอย่างสำหรับนักเรียน s1 (/etc/nginx/sites-available/parich-s1)
# --------------------------------------------------
# FRONTEND CONFIG (ชี้พอร์ต 3001 เข้า Nuxt Container)
# --------------------------------------------------
server {
listen 3001 ssl;
server_name demo-parichportal.loolootest.com;
# ใช้ใบรับรอง SSL ร่วมกันของโดเมนหลัก
ssl_certificate /etc/letsencrypt/live/demo-parichportal.loolootest.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demo-parichportal.loolootest.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3001; # ส่งต่อไปที่พอร์ตภายในของ Frontend Container
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# --------------------------------------------------
# BACKEND CONFIG (ชี้พอร์ต 8001 เข้า Django Container)
# --------------------------------------------------
server {
listen 8001 ssl;
server_name demo-parichportal.loolootest.com;
# ใช้ใบรับรอง SSL ร่วมกันของโดเมนหลัก
ssl_certificate /etc/letsencrypt/live/demo-parichportal.loolootest.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demo-parichportal.loolootest.com/privkey.pem;
client_max_body_size 75M;
# ดึง Static files ตรงจากไดเรกทอรี Workspace ของผู้เรียน s1 บน Host OS
location /static/ {
alias /home/pui/workshop/s1/backend-project/backend/static/;
expires 30d;
add_header Cache-Control "public, no-transform";
}
location /media/ {
alias /home/pui/workshop/s1/backend-project/backend/media/;
expires 7d;
}
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
หลังจากบันทึกไฟล์คอนฟิกแล้ว ให้ทำการเปิดใช้งานบล็อคนั้นและสั่ง Reload Nginx:
sudo ln -sf /etc/nginx/sites-available/parich-s1 /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
10. Cron Jobs Isolation (การแยกงานตั้งเวลาของแต่ละคน)
เนื่องจากตัว Cron Daemon ทำงานในระดับ Host OS เพื่อความเสถียร สคริปต์ `deploy.sh` ของน้องๆ จะถูกเขียนให้สร้างคอนฟิกสำหรับนักเรียนแยกกันตามชื่อของโปรเจกต์:
# คอนฟิกใน /etc/cron.d/parich-backend-parich-s1 (สร้างโดยอัตโนมัติ)
0 * * * * root /home/pui/workshop/s1/backend-project/backend/cron_host.sh calculate_order_target --days-back=3
ช่วยให้น้องมั่นใจได้ว่าคำสั่ง Cron จะยิงงานเข้าไปยังตู้ parich-s1-backend ของตัวเองเท่านั้น ไม่ไปรบกวนข้อมูลของคนอื่น
11. Troubleshooting (การแก้ปัญหาเมื่อพบความผิดพลาด)
11.1 ปัญหา HTTP 403 Forbidden เมื่อเปิดหน้า Django Admin (CSS ไม่โหลด)
ปัญหานี้มักจะเกิดจากการที่สิทธิ์ในการเข้าถึงโฟลเดอร์ static ใน path ของผู้เรียน (เช่น /home/pui/...) ไม่ได้รับสิทธิ์ให้ user www-data ของ Nginx เดินผ่านได้ ให้รันคำสั่งเปิดทางเข้า (Execute) ดังนี้:
# เปิดสิทธิ์การเปิดอ่านและผ่านของโฟลเดอร์ไล่ระดับ
chmod 755 /home/pui
chmod 755 /home/pui/workshop
chmod 755 /home/pui/workshop/s1
chmod 755 /home/pui/workshop/s1/backend-project
chmod 755 /home/pui/workshop/s1/backend-project/backend