คู่มือดูแลระบบด้วย Docker (radioctl สำรองข้อมูล อัปเดต)

คู่มือนี้สำหรับผู้ดูแลเซิร์ฟเวอร์วิทยุออนไลน์ที่ติดตั้งด้วย scripts/install.sh (ดูคู่มือติดตั้ง) งานทุกอย่างในคู่มือนี้ทำบนเซิร์ฟเวอร์ด้วยคำสั่งเดียวคือ radioctl (ตัวติดตั้งวางไว้ใน /usr/local/bin แพ็กเกจ Debian วางไว้ใน /usr/bin ในโฟลเดอร์ติดตั้งคือ scripts/radioctl) ส่วนคำสั่งผู้ดูแลของแพลตฟอร์ม (create-admin, station-import, …) คือคำสั่ง radio ดูคู่มือติดตั้ง เว็บแอปไม่ได้ควบคุม Docker เลย ไม่มีสิทธิ์เข้าถึง Docker socket หน้าระบบในเว็บแสดงได้อย่างเดียวว่าคำสั่งในคู่มือนี้ทำอะไรไปแล้ว

รัน radioctl ด้วยสิทธิ์ root (หรือใช้ sudo) การติดตั้งอยู่ที่ /opt/radio และโปรเจกต์ Docker Compose ชื่อ radio เสมอ (วอลุ่ม radio_db-data, …)

sudo radioctl status

บน NAS ให้รัน sudo bash scripts/radioctl … ในโฟลเดอร์ติดตั้ง (ใช้ deploy/nas/docker-compose.yml และ deploy/nas/.env)

ข้อความทั้งหมดเป็นตัวอักษรธรรมดา บรรทัดละหนึ่งเรื่อง อ่านด้วยโปรแกรมอ่านหน้าจอได้สะดวก แสดงเป็นภาษาไทยเมื่อภาษาของระบบเป็นไทย เลือกเองได้ด้วย --lang th หรือ --lang en ตัวเลือก --yes ตอบทุกคำถามด้วยค่าเริ่มต้น (สำหรับสคริปต์อัตโนมัติ)

คำสั่งโดยสรุป

คำสั่ง ทำอะไร
radioctl status บริการและสถานะสุขภาพ CPU และหน่วยความจำของแต่ละคอนเทนเนอร์ จำนวนสถานีเทียบกับขนาดโปรไฟล์ การสำรองข้อมูลล่าสุด เวอร์ชัน และพื้นที่ดิสก์
radioctl logs [บริการ] [--follow] log 200 บรรทัดล่าสุดของทุกบริการหรือบริการเดียว (app, worker, icecast, db, caddy, backup)
radioctl doctor ตรวจ DNS พอร์ต ดิสก์ นาฬิกา ใบรับรอง ค่าตั้ง migration Icecast และการสำรองข้อมูล แล้วบอกวิธีแก้แต่ละปัญหา
radioctl update [--version แท็ก] [--offline ไฟล์] สำรองข้อมูล ดึงอิมเมจใหม่ (หรือโหลดจากไฟล์อิมเมจของรุ่น) แล้วเริ่มบริการใหม่ทีละตัว
radioctl rollback กลับไปใช้เวอร์ชันก่อนการอัปเดตครั้งล่าสุด
radioctl backup [run|list|status|check] สำรองข้อมูลทันที (ค่าเริ่มต้น) ดูรายการข้อมูลสำรอง ดูผลครั้งล่าสุด ตรวจที่เก็บข้อมูลสำรอง
radioctl restore [รหัสสำรอง] [--from local|s3] กู้คืนฐานข้อมูลและไฟล์ทั้งหมดจากข้อมูลสำรอง
radioctl scale --shards N แบ่งระบบออกอากาศเป็น N คอนเทนเนอร์
radioctl profile small|medium|large ใช้โปรไฟล์ขนาด (ขีดจำกัดหน่วยความจำและ CPU หน่วยความจำของฐานข้อมูล จำนวน shard)
radioctl outbox [N] แสดงอีเมล N ฉบับล่าสุดที่ไม่ได้ส่งออก (ยังไม่ได้ตั้งเซิร์ฟเวอร์อีเมล หรือส่งไม่สำเร็จ)
radioctl login-link อีเมล [--minutes 15] ลิงก์เข้าสู่ระบบใช้ครั้งเดียวสำหรับบัญชีที่มีอยู่ (เมื่ออีเมลไม่มาถึง)
radioctl password อีเมล รหัสผ่านชั่วคราวให้บัญชีใดก็ได้ รวมผู้ดูแลระบบ (แสดงครั้งเดียว ใช้ได้ 7 วัน ต้องเปลี่ยนเมื่อเข้าสู่ระบบครั้งแรก) --link [--minutes 60]: ลิงก์ใช้ครั้งเดียวที่พาไปหน้าตั้งรหัสผ่าน --remove: ลบรหัสผ่าน เจ้าของบัญชีได้รับอีเมลแจ้ง (ไม่มีรหัสในอีเมล)
radioctl migrate-name [--dry-run] ย้ายการติดตั้งที่ทำภายใต้โฟลเดอร์หรือชื่อโปรเจกต์อื่นมาเป็นโปรเจกต์ radio ที่ /opt/radio (ดูด้านล่าง)
radioctl up, down, restart [บริการ], version เริ่ม หยุด เริ่มใหม่ และดูเวอร์ชันอิมเมจ

บริการที่ทำงานอยู่

บริการ อิมเมจ หน้าที่
db postgres:16 ฐานข้อมูล ค่าหน่วยความจำมาจากโปรไฟล์ขนาด
app radio-app เว็บไซต์ หน้าผู้ฟัง หน้าผู้ดูแล API และปรับฐานข้อมูล (migration) ทุกครั้งที่เริ่ม
worker (และ worker-1, worker-2, ...) radio-engine Liquidsoap 1 ตัวต่อสถานี รับเสียงสดจากดีเจงานเบื้องหลัง worker (shard 0) ยังรันงานตามเวลาด้วย เช่น ตารางออกอากาศ ช่วงโฆษณา การแจ้งเตือน สถิติ และเขียนค่าตั้งของ Icecast ให้ตรงกับรายการสถานี (Icecast อ่านค่าใหม่เอง)
engine-net radio-icecast คอนเทนเนอร์เล็ก ๆ ที่ถือเครือข่ายซึ่งทุก shard ใช้ร่วมกัน และเปิดพอร์ตดีเจ
icecast radio-icecast ส่งสตรีมให้ผู้ฟัง และเล่นเสียงรอสัญญาณ (ดูด้านล่าง)
caddy caddy:2.10 HTTPS ของเว็บไซต์ โดเมนสถานี และสตรีมใต้ /stream (หรือ HTTP ธรรมดาในแบบ ip-http) ค่าตั้งอยู่ที่ deploy/caddy/<PUBLIC_MODE>.Caddyfile
backup radio-backup สำรองข้อมูลตามเวลา บริการ restore ใช้อิมเมจเดียวกันเฉพาะตอนกู้คืน
pgbouncer radio-pgbouncer รวมการเชื่อมต่อฐานข้อมูล ใช้เฉพาะโปรไฟล์ medium และ large

อิมเมจคือ <RADIO_IMAGE_PREFIX>/radio-* (เช่น ghcr.io/<owner>/radio-app) หรือ local/radio-* ที่สร้างบนเครื่อง ทุกบริการมีการตรวจสุขภาพ เริ่มใหม่เองเมื่อล่ม และเก็บ log ไม่เกิน 3 ไฟล์ ไฟล์ละ 10 MB (LOG_MAX_SIZE, LOG_MAX_FILE)

โปรไฟล์ขนาดและความจุ

โปรไฟล์ เครื่อง สถานี shard ของระบบออกอากาศ PgBouncer
small 2 vCPU, RAM 4 GB ไม่เกิน 5 1 ไม่ใช้
medium 4 vCPU, RAM 8 GB ไม่เกิน 15 2 ใช้
large 8 vCPU, RAM 16 GB ไม่เกิน 40 4 ใช้

วัดจริงบนโปรไฟล์ small มี 5 สถานีเล่นเล่นเพลงอัตโนมัติ (MP3 128 kb/s สตรีมประหยัดเน็ตและ HLS เริ่มเมื่อมีคนฟังเท่านั้น): ทั้งระบบใช้หน่วยความจำราว 780 MB คอนเทนเนอร์ระบบออกอากาศราว 575 MB และ CPU หนึ่งในสามของคอร์ เว็บแอป 112 MB PostgreSQL 65 MB Icecast 10 MB (รวม relay รอสัญญาณ 10 ตัว) Caddy 11 MB ถ้าเปิดสตรีมประหยัดเน็ตและ HLS ของทั้ง 5 สถานีตลอด ระบบออกอากาศใช้ราวครึ่งคอร์และ 625 MB ระบบออกอากาศของแต่ละสถานีใช้หน่วยความจำของคอนเทนเนอร์ราว 100 MB (โปรเซสแสดงราว 158 MB แต่บางส่วนเป็นไลบรารีที่ใช้ร่วมกัน) แบนด์วิดท์ผู้ฟังคิดแยก = จำนวนผู้ฟัง × bitrate (ผู้ฟัง 500 คนที่ 128 kb/s ต้องการขาออกราว 64 Mbit/s)

โปรไฟล์กำหนดขีดจำกัดหน่วยความจำและ CPU ของแต่ละคอนเทนเนอร์ (*_MEM_LIMIT, *_CPUS, *_PIDS ใน .env) หน่วยความจำของ PostgreSQL (PG_SHARED_BUFFERS, PG_EFFECTIVE_CACHE_SIZE, PG_WORK_MEM, PG_MAX_CONNECTIONS) จำนวนพอร์ตดีเจ (HARBOR_PORT_COUNT) และหน่วยความจำสำหรับ HLS (HLS_TMPFS_SIZE) ค่าทั้งหมดอยู่ใน deploy/profiles/*.env ถ้าจะเปลี่ยนค่าเดียว ให้แก้ใน .env แล้วรัน radioctl up ส่วน radioctl profile <ชื่อ> เขียนค่าทั้งหมดของโปรไฟล์ใหม่อีกครั้ง

ถ้า radioctl status แสดงสถานีที่เปิดอยู่มากกว่าขนาดของโปรไฟล์ ให้ย้ายไปเครื่องที่ใหญ่ขึ้น แล้วรัน radioctl profile medium (หรือ large)

เมื่อหน่วยความจำไม่พอ

  • ทุกคอนเทนเนอร์มีขีดจำกัดหน่วยความจำ เมื่อคอนเทนเนอร์ระบบออกอากาศใช้ถึงขีดจำกัด เคอร์เนลจะหยุดระบบออกอากาศของสถานีเดียว (ตั้งไว้ให้ถูกหยุดก่อน) worker เริ่มสถานีนั้นใหม่ในไม่กี่วินาที สถานีอื่นเล่นต่อตามปกติ ฐานข้อมูล เว็บแอป และ Icecast ไม่ได้รับผลกระทบ
  • เมื่อทั้งเครื่องหน่วยความจำไม่พอ เคอร์เนลหยุดโปรเซสตามลำดับนี้: backup, เว็บแอป, ระบบออกอากาศของแต่ละสถานี, แล้วจึง worker, Icecast, Caddy และฐานข้อมูลเป็นลำดับสุดท้าย
  • เหตุการณ์สตรีมของสถานีบันทึกทุกครั้งที่ระบบออกอากาศล่ม และถ้าเริ่มใหม่ซ้ำ ๆ แพลตฟอร์มจะแจ้งเตือนเรื่องระบบออกอากาศเริ่มใหม่บ่อย บนเซิร์ฟเวอร์ คำสั่ง dmesg | grep -i "out of memory" บอกว่าเคอร์เนลหยุดโปรเซสไหน ถ้าเกิดบ่อยแปลว่าโปรไฟล์เล็กเกินไปสำหรับจำนวนสถานี

แบ่งระบบออกอากาศเป็น shard

เมื่อใช้ shard สถานีจะถูกกระจายไปหลายคอนเทนเนอร์ (worker, worker-1, ...) แต่ละ shard มีขีดจำกัดหน่วยความจำและ CPU ของตัวเอง สถานีที่มีปัญหาจึงกระทบได้เฉพาะสถานีใน shard เดียวกัน

sudo radioctl scale --shards 3

เมื่อเปลี่ยนจำนวน shard สถานีจะถูกย้ายระหว่าง shard และแต่ละสถานีเริ่มใหม่หนึ่งครั้ง ทุก shard ใช้เครือข่ายเดียวกันดีเจจึงใช้ที่อยู่และพอร์ตเดิม ไฟล์ docker-compose.shards.yml สร้างขึ้นอัตโนมัติ อย่าแก้เอง

เสียงรอสัญญาณระหว่างเริ่มใหม่

ขณะระบบออกอากาศของสถานีเริ่มใหม่ (อัปเดต ล่ม หรือหน่วยความจำเต็ม) Icecast จะย้ายผู้ฟังไปฟังเสียงรอสัญญาณ (เสียงกระดิ่งเบา ๆ) และย้ายกลับไปที่สถานีเดิมเมื่อสถานีกลับมา เครื่องเล่นไม่หลุดการเชื่อมต่อ ทุก mount ของสถานีมี relay ของตัวเอง (/<สถานี>.standby, /<สถานี>-low.standby) จากสตรีมรอสัญญาณ /rp-standby (MP3) และ /rp-standby-low (AAC) ที่คอนเทนเนอร์ Icecast เล่นตามเวลาจริง (ICECAST_STANDBY=true ค่าเริ่มต้นของ Docker) worker ปรับค่าตั้งของ Icecast ตามรายการสถานีเอง และ Icecast อ่านค่าใหม่โดยผู้ฟังไม่หลุด ผลทดสอบ: หลัง kill -9 คอนเทนเนอร์ระบบออกอากาศ และระหว่าง radioctl update ผู้ฟังได้รับข้อมูล 15–17 KB/s (ตามเวลาจริงของ 128 kb/s) และกลับมาที่สถานีของตัวเองภายใน 25 วินาที ถ้าตั้ง ICECAST_STANDBY=false แต่ละสถานีจะใช้ไฟล์ของตัวเองแทน (DATA_DIR/ops/icecast-fallback/<สถานี>.mp3 เปลี่ยนได้) ซึ่ง Icecast ส่งเร็วกว่าเวลาจริงหลายเท่า เครื่องเล่นจึงเก็บไว้ในบัฟเฟอร์

ที่อยู่และโดเมน

ตัวติดตั้งถามวิธีเข้าถึงแพลตฟอร์ม (โดเมน, IP แบบ HTTPS, IP แบบ HTTP ธรรมดา) แล้วเขียนที่อยู่แรกลง .env (PUBLIC_MODE, BASE_URL, BASE_DOMAIN, ICECAST_PUBLIC_URL, HARBOR_PUBLIC_HOST) หลังจากนั้น:

  • เปลี่ยนโดเมนในเว็บ ไม่ใช่ใน .env: การจัดการแพลตฟอร์ม → โดเมนและที่อยู่ (ที่อยู่หลัก โดเมนย่อยของสถานี ที่อยู่สตรีม โดเมนของสถานีเอง) แพลตฟอร์มเก็บไว้ในฐานข้อมูล ค่าใน .env เป็นแค่ค่าแรก ใช้จนกว่าจะตั้งในหน้านั้น Caddy ถามแพลตฟอร์มก่อนออกใบรับรองทุกครั้ง (/internal/tls-check) ชื่อที่เพิ่มในหน้านั้นจึงได้ใบรับรอง HTTPS ตั้งแต่เปิดครั้งแรกโดยไม่ต้องเริ่มอะไรใหม่ แต่ DNS ของชื่อนั้นต้องชี้มาที่เซิร์ฟเวอร์ก่อน
  • วิธีเข้าถึง (โดเมน, IP แบบ HTTPS, HTTP ธรรมดา) เป็นค่าตั้งของเซิร์ฟเวอร์: รัน sudo bash /opt/radio/scripts/install.sh อีกครั้งแล้วเลือกแบบใหม่ รหัสลับและข้อมูลทั้งหมดยังอยู่ และ Caddy เริ่มใหม่ด้วยไฟล์ deploy/caddy/<แบบ>.Caddyfile ที่ตรงกัน
  • สตรีมอยู่ที่ <ที่อยู่>/stream/<สถานี> เสมอ (Caddy ส่งต่อให้ Icecast) โดเมนสตรีมแยก (ถ้ามี) ส่งไป Icecast ทั้งหมด
  • แบบ IP พร้อม HTTPS: ใบรับรอง IP ของ Let's Encrypt มีอายุประมาณ 6 วัน Caddy ต่ออายุเมื่อผ่านไปประมาณ 3 วัน พอร์ต 80 และ 443 ต้องเปิดให้อินเทอร์เน็ตเข้าถึงได้ตลอด radioctl doctor เตือนเมื่อใบรับรองจะหมดอายุภายในหนึ่งวัน ถ้า Let's Encrypt ออกให้ไม่ได้ Caddy ใช้ใบรับรองของตัวเองแทน (เบราว์เซอร์เตือน)

การอัปเดต

ถ้าติดตั้งด้วยแพ็กเกจ Debian ให้ติดตั้งแพ็กเกจใหม่ก่อน (sudo apt install ./radio_<new>_all.deb) แพ็กเกจจะแทนที่ไฟล์โปรแกรมและเก็บ .env ไว้ แล้ว radioctl update จะเปลี่ยนระบบที่ทำงานอยู่เป็นเวอร์ชันนั้น ดูคู่มือติดตั้งบน Ubuntu ทีละขั้น

sudo radioctl update                      # เวอร์ชันของไฟล์โปรแกรมใน /opt/radio (VERSION)
sudo radioctl update --version 1.4.0      # รุ่นที่ระบุ

ขั้นตอนการอัปเดต

  1. สำรองข้อมูล (ข้ามได้ด้วย --no-backup)
  2. ดึงอิมเมจใหม่
  3. เริ่มเว็บแอปรุ่นใหม่และรอจนพร้อม (เว็บแอปปรับฐานข้อมูลเอง)
  4. เริ่ม Icecast และเครือข่ายของระบบออกอากาศใหม่ เฉพาะเมื่ออิมเมจเปลี่ยน
  5. เริ่ม shard ของระบบออกอากาศใหม่ทีละ shard ระหว่างนั้นผู้ฟังได้ยินเสียงรอสัญญาณไม่กี่วินาทีต่อสถานี

ถ้ามีขั้นไหนล้มเหลว การอัปเดตจะหยุดและบอกว่าต้องดูอะไร ถ้าต้องการย้อนกลับ

sudo radioctl rollback

การย้อนเวอร์ชันไม่ได้ย้อนการเปลี่ยนแปลงของฐานข้อมูล ถ้ารุ่นใหม่ปรับฐานข้อมูลไปแล้วและรุ่นเก่าใช้กับฐานข้อมูลนั้นไม่ได้ ให้กู้คืนข้อมูลสำรองที่การอัปเดตทำไว้ก่อน (radioctl backup list แสดงพร้อมเวลาที่อัปเดต)

ถ้าเครื่องไม่มีอินเทอร์เน็ต ใช้ไฟล์อิมเมจของรุ่น: sudo radioctl update --offline radio-images-1.4.0-amd64.tar.gz โหลดไฟล์และใช้เวอร์ชันจากไฟล์นั้น (ถ้าไฟล์ในรุ่นเปลี่ยน ให้แตก radio-1.4.0.tar.gz ทับ /opt/radio ก่อน) อิมเมจที่โหลดไว้ก่อนด้วย docker load ใช้กับ --offline อย่างเดียวได้ ถ้าต้องการสร้างอิมเมจบนเครื่องจากซอร์สโค้ดแทน ใช้ radioctl update --build

อิมเมจที่เผยแพร่เปลี่ยนชื่อจาก saint-radio-* เป็น radio-* ในช่วงเปลี่ยนผ่านเผยแพร่ทั้งสองชื่อ radioctl แก้ RADIO_IMAGE_PREFIX แบบเก่า (ลงท้ายด้วย /saint-radio) ให้เอง

การสำรองข้อมูล

บริการ backup สำรองข้อมูลทุกวันเวลา 03:30 (เวลากรุงเทพฯ) ข้อมูลสำรองแต่ละครั้งมี

  • ฐานข้อมูล เป็น pg_dump แบบ custom format พร้อม role ของฐานข้อมูล (ไม่มีรหัสผ่าน)
  • ไฟล์ทุกไฟล์ใน volume ข้อมูล: คลังเสียง ไฟล์บันทึกรายการ ไฟล์ส่งออก เสียงเมนูโทรศัพท์ (ยกเว้นไฟล์ HLS ซึ่งสร้างใหม่ได้)
  • ไฟล์ .env

ข้อมูลสำรองเข้ารหัสด้วย RESTIC_PASSWORD และเก็บเฉพาะส่วนที่เปลี่ยน (สำรองรายวันจึงเก็บแค่สิ่งที่เปลี่ยนไป) เก็บไว้ที่ BACKUP_DIR บนเครื่องนี้ (ค่าเริ่มต้น /var/backups/radio) และเมื่อตั้ง BACKUP_S3_REPOSITORY จะเก็บที่ S3 ด้วย (AWS S3, Cloudflare R2, Wasabi, MinIO) เก็บไว้ 7 ชุดรายวัน 4 ชุดรายสัปดาห์ และ 6 ชุดรายเดือน

เก็บสำเนาไฟล์ .env (อย่างน้อย RESTIC_PASSWORD) ไว้ที่ปลอดภัยนอกเครื่องนี้ ถ้าไม่มีรหัสนี้จะอ่านข้อมูลสำรองไม่ได้เลย

ค่าตั้ง ค่าเริ่มต้น ความหมาย
BACKUP_TIMES 03:30 เวลาในแต่ละวัน รูปแบบ HH:MM คั่นด้วยจุลภาค off = สำรองด้วยมือเท่านั้น
BACKUP_TZ Asia/Bangkok เขตเวลาของ BACKUP_TIMES
BACKUP_DIR /var/backups/radio โฟลเดอร์เก็บข้อมูลสำรองบนเครื่อง
BACKUP_LOCAL true false = เก็บที่ S3 อย่างเดียว
BACKUP_S3_REPOSITORY ว่าง เช่น s3:https://s3.ap-southeast-1.amazonaws.com/my-bucket/radio
BACKUP_S3_ACCESS_KEY_ID, BACKUP_S3_SECRET_ACCESS_KEY, BACKUP_S3_REGION ข้อมูลเข้าใช้ S3
BACKUP_KEEP_DAILY, BACKUP_KEEP_WEEKLY, BACKUP_KEEP_MONTHLY 7, 4, 6 จำนวนชุดที่เก็บไว้

เปลี่ยนค่าแล้วรัน radioctl up

คำสั่ง

sudo radioctl backup            # สำรองข้อมูลทันที
sudo radioctl backup list       # ข้อมูลสำรองในเครื่อง (เพิ่ม s3 เพื่อดูใน S3)
sudo radioctl backup status     # ผลการสำรองครั้งล่าสุด
sudo radioctl backup check      # ตรวจที่เก็บข้อมูลสำรอง (อ่านข้อมูล 5%)

ผลการสำรองครั้งล่าสุดถูกเขียนลง DATA_DIR/ops/backup-status.json หน้า "ทรัพยากรเซิร์ฟเวอร์" ของแพลตฟอร์มแสดงผลนี้ และแจ้งเตือนเมื่อการสำรองที่สำเร็จครั้งล่าสุดเก่ากว่า ALERT_BACKUP_HOURS (36 ชั่วโมง) การสำรองที่ล้มเหลว (เช่น ติดต่อ S3 ไม่ได้) แสดงใน radioctl status และ radioctl doctor ด้วย ถ้าล้มเหลวเฉพาะ S3 ข้อมูลสำรองในเครื่องยังถูกสร้างตามปกติ

การกู้คืน

sudo radioctl restore                    # ข้อมูลสำรองล่าสุด จากที่เก็บในเครื่อง
sudo radioctl restore 0d4e78d3 --from s3 # ข้อมูลสำรองที่ระบุ จาก S3

คำสั่งจะแสดงรายการข้อมูลสำรอง ให้พิมพ์คำว่า restore เพื่อยืนยัน หยุดเว็บแอปและระบบออกอากาศ แทนที่ฐานข้อมูลและไฟล์ทั้งหมด แล้วเริ่มทุกอย่างใหม่ ข้อมูลที่เกิดหลังเวลาสำรองจะหายไป

กู้คืนบนเครื่องใหม่ (เครื่องเดิมใช้ไม่ได้แล้ว)

  1. รันตัวติดตั้งด้วยวิธีเข้าถึงและโดเมนเดิม ใช้ RESTIC_PASSWORD และค่าตั้ง S3 ชุดเดิม (ใส่ใน .env ก่อนรัน หรือเพิ่มภายหลังแล้วรัน radioctl up)
  2. รัน sudo radioctl restore --from s3
  3. ข้อมูลสำรองมาจากการติดตั้งอื่น radioctl จึงถามว่าจะใช้รหัสลับของข้อมูลสำรอง (SESSION_SECRET, IP_HASH_SALT, DB_SCOPE_SECRET) และช่วงพอร์ตดีเจเดิมหรือไม่ ให้ตอบ y ลิงก์เข้าสู่ระบบ สถิติผู้ฟัง และค่าตั้งของดีเจจะใช้ได้ต่อ

ซ้อมกู้คืน

ทำทุก 2–3 เดือน บนเครื่องสำรองหรือเครื่องเสมือน

  1. ติดตั้งด้วย scripts/install.sh แล้วกู้คืนข้อมูลสำรองล่าสุดจาก S3 ตามข้างบน
  2. radioctl status: ทุกบริการต้องปกติ (healthy)
  3. เข้าสู่ระบบ เปิดสถานี ฟังสตรีม และเล่นไฟล์จากคลังเสียง
  4. จดเวลาที่ใช้

ผลทดสอบ: กู้คืนระบบที่มี 5 สถานีจาก S3 ลงการติดตั้งใหม่ใช้เวลา 15 วินาที สถานี ผู้ใช้ คลังเสียง และสตรีมกลับมาครบ

ย้ายการติดตั้งรุ่นก่อนมาใช้ชื่อ "radio"

ก่อนรุ่นนี้ โปรเจกต์ Docker ของการติดตั้ง และวอลุ่มของมัน ตั้งชื่อตามโฟลเดอร์ (/opt/saint-radio → saint-radio_db-data, …) ตอนนี้ docker-compose.yml ใช้ชื่อโปรเจกต์ radio เสมอ เมื่อ radioctl หรือตัวติดตั้งพบข้อมูลในวอลุ่มชื่อเดิมและยังไม่มีใน radio_* จะหยุด แทนที่จะเริ่มแพลตฟอร์มที่ว่างเปล่า ให้ย้ายหนึ่งครั้ง:

  1. แตกรุ่นใหม่ทับโฟลเดอร์เดิม (หรือ git pull ในโฟลเดอร์นั้น)
  2. ดูแผนก่อน: sudo bash scripts/radioctl migrate-name --dry-run
  3. ย้าย: sudo bash scripts/radioctl migrate-name

คำสั่งนี้สำรองข้อมูล (ข้ามได้ด้วย --no-backup) หยุดและลบ container เดิมและเครือข่ายของมัน คัดลอกแต่ละวอลุ่ม (db-data, radio-data, caddy-data, caddy-config, icecast-config, backup-state) ไปเป็น radio_* ด้วย container ชั่วคราว ลบค่าที่ค้าง เช่น COMPOSE_PROJECT_NAME ออกจาก .env แก้ RADIO_IMAGE_PREFIX แบบเก่า และตั้งชื่อใหม่ให้อิมเมจที่มีในเครื่อง ย้าย /var/backups/saint-radio ไปเป็น /var/backups/radio ย้ายโฟลเดอร์ไปที่ /opt/radio (ใช้ --to โฟลเดอร์ ถ้าต้องการที่อื่น ที่เดิมเหลือเป็นลิงก์) ติดตั้งคำสั่ง เริ่มแพลตฟอร์ม แล้วเทียบจำนวนสถานี ผู้ใช้ ไฟล์เสียง และองค์กรก่อนและหลังย้าย ระหว่างนั้นสถานีหยุดออกอากาศไม่กี่นาที

รันซ้ำได้อย่างปลอดภัย: วอลุ่มที่คัดลอกแล้วบันทึกไว้ใน .migrate-name.state และจะข้าม ถ้าข้อมูลอยู่ใน radio_* แล้วก็แค่ตรวจว่าแพลตฟอร์มทำงาน คำสั่งนี้ไม่ยอมเขียนทับวอลุ่ม radio_* ที่มีข้อมูลจากที่อื่น วอลุ่มเดิมไม่ถูกแก้ไขเลย เมื่อตรวจเว็บและสตรีมแล้ว ลบด้วยคำสั่ง docker volume rm … ที่คำสั่งนี้แสดง ถ้าหาโปรเจกต์เดิมเองไม่พบ ระบุด้วย --from ชื่อ

แก้ปัญหา

เริ่มจาก

sudo radioctl doctor

คำสั่งนี้แสดงทุกปัญหาพร้อมวิธีแก้ ปัญหาที่พบบ่อย

อาการ สาเหตุและวิธีแก้
เว็บไซต์ขึ้นข้อผิดพลาดเรื่องใบรับรอง DNS ยังไม่ชี้มาที่เครื่อง หรือพอร์ต 80/443 ปิดอยู่ doctor บอกว่าข้อไหน Caddy จะลองใหม่เอง ถ้าใช้ใบรับรองของ Caddy เอง (IP ส่วนตัว, internal) การเตือนเป็นเรื่องปกติ ให้ติดตั้งใบรับรองหลักของ Caddy (ดูคู่มือติดตั้ง)
เห็นหน้าติดตั้งว่างแทนแพลตฟอร์มของคุณ ข้อมูลยังอยู่ในวอลุ่มของชื่อโปรเจกต์เดิม radioctl จะบอก ให้รัน migrate-name
โดเมนใหม่ไม่ได้ใบรับรอง DNS ต้องชี้มาที่เซิร์ฟเวอร์ และชื่อต้องอยู่ใน การจัดการแพลตฟอร์ม → โดเมนและที่อยู่ (หรือเป็นโดเมนของสถานี) radioctl logs caddy บอกสาเหตุ
เปิดโดเมนย่อยของสถานีไม่ได้ ยังไม่มีระเบียน DNS แบบ wildcard *.โดเมนของคุณ
ดีเจเชื่อมต่อไม่ได้ พอร์ตดีเจปิดในไฟร์วอลล์ (ufw allow 8100:8119/tcp) หรือพอร์ตของสถานีอยู่นอกช่วงที่เปิด (doctor บอก ให้เพิ่ม HARBOR_PORT_COUNT แล้วรัน radioctl profile <ชื่อ>)
ไม่มีใครเข้าสู่ระบบได้ ใช้ radioctl login-link อีเมล หรืออ่านรหัสด้วย radioctl outbox แล้วตั้งเซิร์ฟเวอร์อีเมลที่หน้าผู้ดูแลระบบ › อีเมล (กดส่งอีเมลทดสอบเพื่อดูสาเหตุ)
สถานีเริ่มใหม่ซ้ำ ๆ ดู radioctl logs worker ถ้าหน่วยความจำเต็ม ดูหัวข้อ "เมื่อหน่วยความจำไม่พอ"
สำรองข้อมูลล้มเหลว radioctl backup status แสดงข้อผิดพลาด S3: ตรวจคีย์ ชื่อบักเก็ต และ region ในเครื่อง: ดิสก์เต็ม
บริการแสดง unhealthy radioctl logs <บริการ> แล้ว radioctl restart <บริการ>
ดิสก์ใกล้เต็ม docker system prune ลบอิมเมจเก่า ลดจำนวนข้อมูลสำรองด้วย BACKUP_KEEP_* หรือย้าย BACKUP_DIR ไปดิสก์อื่น

ดู log ของบริการ: radioctl logs app ดูต่อเนื่อง: radioctl logs worker --follow Docker เก็บ log ไม่เกิน 30 MB ต่อบริการ เกินแล้วลบส่วนเก่าทิ้ง

ความปลอดภัย

  • .env เก็บรหัสลับทั้งหมด อ่านได้เฉพาะ root (สิทธิ์ 600) doctor เตือนถ้าสิทธิ์เปลี่ยน
  • เปิดออกนอกเครื่องเฉพาะพอร์ต 80, 443 และช่วงพอร์ตดีเจฐานข้อมูล เว็บแอป และ Icecast เข้าถึงได้เฉพาะภายใน Docker
  • คอนเทนเนอร์ทำงานด้วยผู้ใช้ที่ไม่มีสิทธิ์พิเศษ (uid 10001) และไม่มี Linux capability ยกเว้น PostgreSQL (อิมเมจทางการ) Caddy (เปิดพอร์ต 80/443 ได้) และ backup (อ่านไฟล์เพื่อสำรอง)
  • เว็บแอปเริ่ม หยุด หรืออัปเดตคอนเทนเนอร์ไม่ได้ ตั้งใจออกแบบไว้แบบนี้ ข้อบกพร่องในเว็บจึงยึดเซิร์ฟเวอร์ไม่ได้