เริ่มต้น Jenkins part 6: สอนแมวจับปลา
2 ไฟล์สำคัญที่เราต้องจัดการใน part นี้ของ Apache Tomcat คือ context.xml และ tomcat-users.xml หนนี้แหละที่ปลาจะเข้าปากโดยสะดวกแฮ
ความเดิมจากตอนที่แล้ว
Apache Tomcat: Manager App
เหมือนกับที่เครื่อง local ที่เราได้ทำไปแล้ว การจะ deploy หรือรัน script ใดๆต้องได้รับสิทธิ์เสียก่อน ซึ่งการจะได้มาก็ต้องไปบอกกับ Apache Tomcat
จากภาพ หากเรากดที่ปุ่ม Manager App จะพบกับ 403 Access Denied
งานนี้เราต้องการคนหนึ่งคน (admin) ให้สามารถเข้า UI ได้
จึงได้ว่า username เป็น admin ส่วน password ก็ตามฝัน สำคัญคือ roles ให้เป็น manager-gui นะครับ
Apache Tomcat: tomcat-users.xml
sudo su -cd /opt/apache-tomcat-8.5.49/conf/vi tomcat-users.xml
จากนั้น restart อีกครั้ง
cd /opt/apache-tomcat-8.5.49/bin./shutdown.sh./startup.sh
กลับไปกดปุ่ม Manager App ใหม่
OOP! ยังเข้าไม่ได้งั้นรึเนี่ย?
ที่ผ่านมาเราใช้ Apache Tomcat 7 ไม่ติดอะไร แสดงว่า Apache Tomcat 8 ต้องมีอะไรเพิ่มเติมแน่ๆครับ
Apache Tomcat: context.xml
เนื่องจากค่าโดย default เจ้าแมวจะยืนที่ 127.0.0.1 หรือ localhost เป็นหลัก เป็นผลให้เรายังกดปุ่ม Manager App ไม่ได้ (เดานะ 555) ให้ค้นหาไฟล์ชื่อ context.xml
find / -name context.xml
เจอมา 3 ตัวแฮะ
/opt/apache-tomcat-8.5.49/webapps/manager/META-INF/context.xml/opt/apache-tomcat-8.5.49/webapps/host-manager/META-INF/context.xml/opt/apache-tomcat-8.5.49/conf/context.xml
ก็น่าจะเป็น 2 อันบนนะ เปิดไปดู
vi /opt/apache-tomcat-8.5.49/webapps/manager/META-INF/context.xml
อย่างจัง! ให้ comment หรือลบออกเสีย หากจะ comment เหมือนผมให้ใส่เครื่องหมายปิดหัวปิดท้ายมัน ผนึกมันไว้ในความมืดตลอดไป!
<!-- comment -->
อีกแห่งหนึ่ง
vi /opt/apache-tomcat-8.5.49/webapps/host-manager/META-INF/context.xml
จัดการให้เรียบร้อยเหมือนอันข้างบนเลยนะ (comment หรือลบ)
เสร็จแล้วก็กลับไป restart เจ้าแมวอีกรอบ
แล้วก็กลับไปกดปุ่ม Manager App อ๊า!
รอช้าอะไร จัดไปสิ admin กับ password ที่กำหนดไว้ไง
โป๊ะ
Jenkins: Deploy to Container plugin
พ่อบ้าน Jenkins มี plugin อยู่หลายตัวครับ เลือกเอาที่ใช่ หนนี้เราจะมองหา Deploy to container กัน
ทำไมเป็นตัวนี้ใช่ไหม? คำตอบคือ มันเขียนว่า allows you to deploy a war to a container ไงล่ะ
กลับไปแก้ไขโปรเจกต์ hello-jenkins ที่ผ่านมา
จากนั้นกดปุ่ม Add Container เลือกเป็น Apache Tomcat 8.x Remote
ส่วนของ Containers ตามรูปข้างต้นนี้ ให้กดปุ่ม Add เพราะเราต้องกำหนด credentials เพื่อระบุตัวตนของคนที่มีสิทธ์ใน Apache Tomcat แก่ Jenkins ว่าจะต้องส่ง .war นี้ให้ในนามของเขา ซึ่งเป็นใครไม่ได้นอกจาก admin (ก็ตอนนี้มีแค่คนเดียว)
บันทึกแล้วกดปุ่ม Build Now
อย่างไรก็ตามอยากให้เข้าไปดูที่ webapps folder ของ Apache Tomcat
cd /opt/apache-tomcat-8.5.49/webapps/ls
พบว่ามีเท่านี้
docs examples host-manager manager ROOT
และหากว่าเรา build สำเร็จ ก็จะต้องปรากฏ folder ชื่อ HelloJenkins อยู่ในนี้ด้วย นั่นเท่ากับว่า plugin ทำงานสมบูรณ์ดี
พัง!
ต้องการ username ที่สามารถทำ text-based ได้? อื่ม… คงหมายถึง role ที่เรียกว่า manager-script
แก้ไข
กลับไปเปิดไฟล์ที่ชื่อ tomcat-users.xml แล้วเพิ่ม manager-script ลงไป
จากนั้น restart เจ้าแมวก่อนจะ Build Now อีกครั้ง
ตรวจดู webapps folder
docs examples HelloJenkins HelloJenkins.war host-manager manager ROOT
ไปที่ Browser กด refresh
อะไรนะ กระบวนการนี้ไม่อัตโนมัติงั้นเหรอ? ใช่สิ เหลือทำให้อัตโนมัติ กล่าวคือพอเรา push code ไปที่ Github ฉันใด Jenkins มันจะต้อง auto build และ deploy ให้เราฉันนั้น
Jenkins: Poll SCM
SCM ย่อมาจาก Software Configuration Management บ้างเรียก S/W หรือ CM ง่ายๆว่าเป็นงาน tracking เพื่อจะจัดการอะไรก็ตามเมื่อเกิด change
อ่านเพิ่มเติม
เราจะให้ Jenkins ทำคำสั่งที่ต้องการเมื่อใดก็ตามที่ Github บอกว่ามี change หรือมีการแก้ไขโค้ดเกิดขึ้นถูกไหม ดังนั้นเพื่อนๆต้องทราบก่อนว่าการกด Build Now โดยเฉพาะครั้งแรก Jenkins จะคัดลอก source code ทั้งหมดมาเก็บไว้กับตัว ซึ่งอยู่ที่ workspace folder หรือจะชมดูผ่าน UI ก็ได้
หรือไปดูสถานที่จริง
cd /var/lib/jenkins/workspacels
เห็นไหมอยู่ครบเลย
hello hello-jenkins
ผมกำลังพูดว่า สิ่งที่เราต้องบอกให้ Jenkins ทำเมื่อมี change ครั้งใดๆ ก็คือให้ไปคัดลอก (poll) โค้ดทั้งหมดมาเสียก่อน ทีนี้จะ build ต่อด้วย deploy ค่อยทำไปตามความอยาก
ขอเลือกเป็น Poll SCM (จริงๆมันเป็น plugin ที่ติดตั้งไว้ให้แล้ว) เพราะมันง่าย อะไรนะ อยากรู้เหรอ ได้สิ
อ่านเพิ่มเติมเกี่ยวกับ Poll SCM และรูปแบบอื่นๆ
กลับไปแก้ไขโปรเจกต์ hello-jenkins ส่วนของ Build Triggers เลือก Poll SCM
ระบุเงื่อนไขใน Schedule แบบไม่ต้องคอยสักวินาที
* * * * *
บันทึก
การสังเกต ตอนนี้ที่หน้า UI ของโปรเจกต์นี้ build ไปแล้ว 3 ครั้ง
ทดลองกลับไปแก้ไขไฟล์
แล้ว push code ขึ้น Github
รอสักพัก (ระยะทางระหว่าง server มันไกล) ก็จะปรากฏครั้งที่ 4
และทันใดนั้นก็…ดูเหมือนจะ work แต่ เมื่อลองเรียก servlet
http://X.X.X.X:8080/HelloJenkins/hello?name=ProS
สรุป
ขอสรุปตรงนี้ก่อนว่า
- โดยการแก้ไขไฟล์ context.xml ของ Apache Tomcat 8 ทั้งสองแห่ง กล่าวคือ comment สิ่งที่เรียกว่า loopback ออกไป ก็ทำให้สามารถเข้าหน้า Manager App ได้
- ติดตั้ง Deploy to Container plugin ส่งผลให้สามารถกำหนดค่าการ deploy ไฟล์ .war ที่เกิดจากกระบวนการ build แก่ปลายทาง Apache Tomcat
- การกำหนดสิทธิ์ manager-script ส่งผลให้ script deploy ทำงานได้เป็นปกติ
- ใช้ Poll SCM ดึงโค้ดก่อนจะเริ่มกระบวนการ build และ deploy ตามลำดับเมื่อใดก็ตามที่เกิด change เกิดขึ้นที่ Github
- เป็นอันว่าเราสามารถให้ปลา (.war) แก่เจ้าแมว (จริงๆน่าจะเป็นสิงโตตัวเมีย) Apache Tomcat สำเร็จ และกระบวนทั้งหมดเป็นไปอัตโนมัติหลังจาก push code ขึ้น Github
สิ่งที่ตั้งเป้าไว้สำเร็จแล้วนี่คือสิ่งที่ผมอยากบอก ส่วน error ที่เกิดก็อีกเรื่องหนึ่ง
แก้ไข 404 Not Found /hello
เล่าให้มือใหม่เข้าใจก่อนว่า เวลาเราเขียนภาษาจาวาแล้วอยากให้มันทำงานเว็บได้เราจะต้องเขียนมันเข้ารูป Servlet ตัว servlet เองเป็นเพียงจาวาคลาสเท่านั้นแหละ จำต้องอาศัยไฟล์ที่เรียกว่า deployment descriptor เป็นหนทางสู่ดวงดาวอีกที ซึ่งไฟล์นี้จะสร้างไว้ใน folder ชื่อ WEB-INF อันเป็น private area คือไม่สามารถเข้าถึงผ่าน address bar ของ Browser ได้ (ปลอดภัยว่างั้นเถอะ) ตามกฏแล้วไฟล์นี้จะใช้ชื่อว่า web.xml
เมื่อเปิดเข้าไปใน web.xml จะพบ 2 tags สำคัญชื่อ <servlet> และ <servlet-mapping> ที่ทำหน้าที่ mapping ระหว่าง servlet กับ path ตอนนี้เราได้ mapping ระหว่าง com.pros.example.HelloServlet เข้ากับ /hello ครับ พูดง่ายๆว่าเมื่อใดเรียก /hello เมื่อนั้น HelloServlet ก็จะทำงาน
ปัญหาคือ /hello นี้จะถูกเรียกแบบ dynamic กล่าวคือเรียกขณะ runtime คือโปรแกรมทำงานไปแล้ว deploy สู่สายตาชาวบ้านแล้ว มันจึงเป็นอะไรที่ต้องลุ้นว่ารอดหรือตาย (ปกติจะรอดถ้าทำตามขั้นตอนของการ mapping ถูกต้องทุกประการ)
ถามว่าเราทำอะไรพลาดไป? คำตอบน่าจะกลายเป็นคำถาม ขอถามว่าใครทำงาน /hello นี้ให้เรา คำตอบ…
ลองตอบสิ
ผมเดาว่า JRE หรือก็คือโปรแกรมที่รันโปรแกรมจาวานั่นแหละ ตรวจสอบดูก่อนที่เครื่องที่ได้ลง Apache Tomcat ไว้
java version “1.7.0_231”
OpenJDK Runtime Environment (amzn-2.6.19.1.80.amzn1-x86_64 u231-b01)
OpenJDK 64-Bit Server VM (build 24.231-b01, mixed mode)
มันเป็นจาวาเวอร์ชัน 1.7
ทีนี้กลับไปดู target ที่เรากำหนดใน pom.xml อ่าว~ target บอกว่าใช้จาวาเวอร์ชัน 1.8
มันไม่สัมพันธ์กัน งั้นทางแก้ไขมี 2 ทาง
- ง่ายที่สุด เปลี่ยน target 1.8 ตรงนี้ให้เป็น target 1.7 (จะได้ตรงกับ JRE ในเครื่อง)
- เปลี่ยน JRE ในเครื่องเป็น 1.8 (จะได้พอดีกับ target ในโค้ด)
เราควรตัดสินใจให้ software เดินหน้า มิใช่ถอยหลัง ดังนั้นผมเลือกข้อ 2
update Java 1.7 to 1.8
ขอดูก่อน yum ได้ติดตั้งอะไรไว้บ้าง
yum list installed
พบเป้าหมาย
งั้นลบออก
yum remove java
แล้วติดตั้งใหม่ (เอาเฉพาะ JRE)
yum install java-1.8.*-openjdk
ตรวจสอบ
java -version
openjdk version “1.8.0_222”
OpenJDK Runtime Environment (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
ถัดไปผมกลับไปแก้เลขเวอร์ชันของ .war เสียหน่อย เปิดไฟล์ pom.xml มองหาแท็กชื่อ version แก้ไขจากเดิม 1.0-SNAPSHOT เป็น 1.0.0
push code ขึ้น Github
รอ…
ถ้ายังได้ 404 อีกให้ restart Apache Tomcat รอบหนึ่ง
เรียกใหม่
Apache Tomcat เจ้าสิงโตตัวเมีย
ยังมีเรื่อง Docker ที่อยากเอามาผนวก ไว้โอกาสหน้านะครับ