Jaynarol Blog

Docker : ใช้งาน Crontabs + ตั้งเวลา Log Rotation อัตโนมัติ

บทความนี้มีเนื่อหาต่อเนื่องนิดหน่อยกับ เข้าใจและจัดการ Logs ด้วย Syslog นะครับ เพราะก่อนเราจะทำ Log Rotation ได้ เราต้องมีข้อมูล Logs ก่อน

Crontabs มันทำอะไรได้เยอะมาก เช่นตั้งเวลา backup ข้อมูล, คำนวนสถิติ, เก็บ cache, เช็คความพร้อมของระบบ ฯลฯ เรียกได้ว่าทุกอย่างที่เราอยากให้มันทำงานอัตโนมัติตามเวลาที่เรากำหนด มันจึงถือเป็นหนึ่งในกำลังสำคัญของแทบทุกระบบเลยก็ว่าได้ครับ และในบทความนี้เราจะทำให้ Crontabs ทำงานใน Docker กันครับ

 

Crontabs ใน Docker เนี่ยนะ?

“Crontabs ใน Docker เนี่ยนะ? / Server ที่เราติดตั้ง Docker มันก็ใช้งาน Crontabs ได้อยู่แล้วไม่ใช่หรอ?”

อันนี้เป็นความชอบส่วนตัวครับ ผมชอบให้ทั้งระบบมันจบใน docker-compose เดียว เพื่อให้ง่ายต่อการย้าย การจัดการ ต่างๆนาๆ ถ้าให้ผมพูดว่าการผูกติด Service ไว้กับ System เป็นเรื่องที่หมดยุคไปแล้ว ควรหลีกเลียงได้แล้ว ก็อาจจะดูโอเวอร์เกินไป แต่ให้ตาย ผมคิดแบบนั้นจริงๆครับ

ถ้าเราใช้ Docker แต่ตอนเรา deploy ระบบขึ้น server หรือ migrate ระบบไปที่อื่น เรายังต้องมานั่งจุ้มปุ๊กตั้งค่าต่างๆใน Server อยู่อีก “ผมว่าหลงทางแล้วนะครับ” ไหนๆก็ใช้ Docker ทั้งที การ deploy และ migrate มันต้องง่ายที่สุด และสำหรับผม docker-compose up -d --build คำสั่งเดียว ทุกระบบในโปรเจคต้องพร้อมใช้งาน ถึงจะเรียกได้เต็มปากว่า “เราใช้ Docker แล้ว”

ยินต้อนรับสู่ยุค Infrastructure as Code ที่ผมคิดว่าไม่ช้าก็เร็วทุกคนต้องมาจุดนี้แน่ๆครับ จะมาเองหรือโดนบังคับให้มานั่นอีกเรื่องนึงนะ 🙂

 

ลองเล่นกันเลย

ในการสร้าง Container ที่เป็นงานย่อยๆ อย่าง Logs Container หรือ Crontabs ที่กำลังจะเห็นในบทความนี้ เราจะพยายามให้ข้อมูลมันเล็กที่สุดเพื่อให้การ pull push deploy migrate เป็นไปอย่างรวดเร็ว เทคนิคที่สำคัญที่สุดคือ

ใช้ Alpine เป็น Base เสมอ

เพราะมันเล็กมากๆประมาณ 5 mb เท่านั้นครับ แต่ก็มีเรื่องที่ต้องระวังไว้ด้วยเพราะมันยังใหม่ มีการเปลี่ยนแปลงและอัพเดทบ่อย ห้ามใช้ image alpine:latest เด็ดขาด ควรระบุเวอร์ชั่นไปด้วยเสมอครับเช่น alpine:3.3 และเราสามารถเปลี่ยนแปลงเลขได้เสมอเมื่อเราทดสอบเรียบร้อยแล้วว่ามันยังโอเคอยู่ ผมเชื่อว่าคงไม่มีใครอยากเจอเรื่อง Surprise ตอนกำลัง deploy ขึ้น production หรอกนะ 😀

 

และด้านบนนี้คือ DockerFile สำหรับสร้าง Crontabs Container ของเราครับ จริงๆมันไม่มีนัยยะสำคัญอะไรหรอกนะ แค่ไม่อยากให้มีแต่ Text พรืดๆแค่นั้นเอง 555+ เพื่อความรวดเร็ว Clone ตัวอย่างของผมลงมาในเครื่องเลยครับ

 

ทดสอบ Crontabs

หลังจาก clone มาแล้วก็ไม่ต้องพูดพร่ำทำเพลงให้เสียเวลา สั่งให้ระบบเริ่มทำงานได้เลยด้วยคำสั่งนี้ครับ

หลังจากระบบ pull และ compile เสร็จจนเริ่มทำงาน เราสามารถเข้าไปดูการทำงานของ Crontabs เราได้ด้วยคำสั่ง

รอสักพักประมาณ 1 นาที ถ้ามีข้อความขึ้นดังภาพ แสดงว่า Crontabs เราทำงานได้แล้ว (กด Ctrl + C เพื่อออกจากการแสดงผล Logs นะครับ)

 

เข้าใจการทำงาน

สาเหตุที่ในหัวข้อที่แล้วมันแสดงผลออกมาได้เพราะ 3 ปัจจัยหลักๆ ดังนี้

  1. ./build/cron/periodic.conf เป็นไฟล์ที่กำหนดให้ Crontabs ทำงานตามช่วงเวลา
  2. ./build/cron/DockerFile สั่งให้ copy periodic.conf ไปไว้ใน Crontabs Container ในช่วง build
  3. docker-compose.yml สั่งให้ Volume ข้อมูลทั้งโปรเจคเข้าไปใน Crontabs Container

ดังนั้น เมื่อเราสั่งให้ระบบเริ่มทำงาน ข้อมูลเราทั้งหมดจะถูกเชื่อมโยง (Volume) ไปที่ /my/prj/ ใน Crontabs Container  ภาพจะประมาณนี้ (host) ./ <=>  /my/prj/ (Container) นะครับ ต่อมาถ้าเราสังเกตเราจะเห็นว่า ข้อมูลในไฟล์ periodic.conf มีบรรทัดนึงเขียนไว้ว่า * * * * * /my/prj/cmd/test.sh นั่นหมายถึงให้ Corntabs เรียกทำงานไฟล์ /my/prj/cmd/test.sh (ซึ่งก็คือ ./cmd/test.sh) ทุกๆ 1 นาที ดังนั้นทุกๆ 1 นาทีเราจึงเห็น Hi Jaynarol!!!! โผล่ออกมานั่นเองครับ

 

Log Rotation

ท่าง่ายๆผ่านไปแล้ว เรามาต่อด้วยท่าที่ซับซ้อนขึ้นมาอีกนิดนึงคือการสั่งให้ Crontabs บีบอีดและจัดเก็บ Logs ของเราทุกๆวันตอนตี 2 ครับ

หัวใจหลักของ Crontabs มันก็มีแค่ 2 เรื่องครับ ทำเมื่อไหร่ และ ทำที่ไหน โดยเราจะกำหนดไว้ที่ไฟล์ ./build/cron/periodic.conf ครับ

  • ฝั่งซ้าย * * * * * คือการกำหนดว่า ทำเมื่อไหร่ (รายละเอียด)
  • ฝั่งขวา /my/prj/cmd/logrotator.sh คือการกำหนดว่า ทำที่ไหน (สั่งรันไฟล์ไหน)

สคริปของ Log Rotation ผมไปเจอมาจาก lingtalfi/logrotator ดังนั้นกดเข้าไปอ่านรายละเอียดการใช้งานได้เลยนะครับ เบื่องต้นที่ผมตั้งค่าไว้ให้คือ ให้ดึงข้อมูลจาก /my/prj/logs/messages ไปบีบอัดและเก็บไว้ที่ /my/prj/keep ครับ

 

ทดสอบ Log Rotation

การทดสอบรอบนี้ ถ้าจะให้รอดูว่ามันเวิร์กไหมตอนตี 2 ก็คงไม่ใช่ หรือปรับจะให้มันทำงานทุก 1 นาทีแล้วรอผลก็ยังดูตลกอยู่ดี ผมมีวิธีที่ดีกว่านั้นครับ

 

docker exec เป็นคำสั่งที่ให้เราเสมือน ssh เข้าไปใน Container สามารถทำงานได้ในนั้นเสมือนตัว Container ทำงานเองครับ

ถ้าเราคิดดีๆตัว Crontabs ก็แค่เอาไว้สั่งรันไฟล์ตามช่วงเวลา และเราก็ทดสอบมันไปแล้วว่ามันทำงานได้ รอบนี้ที่เราต้องการทดสอบไม่ใช่ Crontabs แต่เป็น Log Rotation นะครับ เริ่มตามผมทันแล้วไหมครับ เราไม่จำเป็นต้องอาศัย Crontabs อีกแล้ว แล้วทำไมไม่สั่งรันสคริปข้างนอกเลยละ exec เข้าไปใน Container ทำไม? ก็เพราะเราต้องการความแม่นยำ ไม่ว่าจะเป็นเรื่อง path / permission ต่างๆ เราจำเป็นต้องจำลองให้เหมือนมากที่สุด และคงไม่มีอะไรเหมือนเท่ากับมาลองรันด้วยตัวมันเองเลย จริงไหมครับ

มาเริ่มจากการทดสอบเล็กๆก่อนนะครับ

โอเคครับ ทำงานได้ มาเล่นของจริงเลยดีกว่า

ตอนนี้ที่ ./logs มีไฟล์ messages ขนาด 2mb กว่าๆอยู่ และ ./keep ก็โล่งๆตามภาพนะครับ ลองสั่งรันสคริปเลยครับ

หลังจากสั่งรันเหมือนมันขึ้น error ว่าลบไฟล์ไม่ได้ ช่างมัน นะครับ มันเป็น bug ของทางเจ้าของสคริป แต่ในไฟล์ที่ clone ไปจากผม ผมแก้เรียบร้อยแล้วแหละ 😀

ที่เราต้องดูคือตัวนี้ครับ

ไฟล์ ./logs/messages ขนาดเหลือ 0 เพราะมันโดนดึงข้อมูลไปบีบอัดและเก็บไว้ที่ ./keep นั่นเองครับ ขนาดจาก 2.5mb เหลือ 16kb เท่านั้นครับ เป็นอันเรียบร้อย ใช้งานได้ตามเป้าหมายครับ

ออกจาก Container ด้วยคำสั่ง exit และทำความสะอาดระบบด้วยคำสั่ง docker-compose down เป็นอันเรียบร้อยครับ 🙂

 

ข้อควรระวัง

  1. ต้องตรวจสอบ Path ให้ดี ใน Container ไฟล์โปรเจคเราจะอยู่ที่ /my/prj ดังนั้นการเขียนสคริปต้องใช้ path นี้เป็นหลักเพราะคนรันคือ Container ไม่ใช่ host นะครับ
  2. ระวังเรื่อง permission ในการเข้าไปอ่าน shell script และ ข้อมูลที่เราต้องเข้าไปยุ่งด้วย เช่นไฟล์เว็บไซต์ ที่ให้สิทธิ์เฉพาะ user web เป็นต้นครับ ต้องทดสอบและหาวิธีจัดการให้ดีครับ

 

ปิดท้าย

อย่างที่บอกไปครับว่า Crontabs สามารถนำไปประยุกต์ใช้ได้หลากหลายตามแต่ความต้องการและสถานการณ์ บทความนี้เป็นเพียงน้ำจิ้มเพื่อให้เห็นแนวทางเท่านั้นครับ

เรื่องของ Docker ยังไม่หมดแค่นี้ครับ ผมยังเหลืออะไรๆไว้พาให้เล่นอีกเพียบ เจอกันใหม่บทความหน้านะครับ

สวัสดีครับ 🙂