เริ่มต้น Jenkins part 6: สอนแมวจับปลา

Phai Panda
6 min readDec 8, 2019

--

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 กัน

filter ไปว่า deploy to container

ทำไมเป็นตัวนี้ใช่ไหม? คำตอบคือ มันเขียนว่า allows you to deploy a war to a container ไงล่ะ

กลับไปแก้ไขโปรเจกต์ hello-jenkins ที่ผ่านมา

เลือก hello-jenkins
แก้ configure
มองหาส่วนที่เรียกว่า Post-build Action อยู่ท้ายๆแหละ
เลือก Deploy war/ear to a container
ระบุเป็น **/*.war ตามคำแนะนำ

จากนั้นกดปุ่ม Add Container เลือกเป็น Apache Tomcat 8.x Remote

ส่วนของ Containers ตามรูปข้างต้นนี้ ให้กดปุ่ม Add เพราะเราต้องกำหนด credentials เพื่อระบุตัวตนของคนที่มีสิทธ์ใน Apache Tomcat แก่ Jenkins ว่าจะต้องส่ง .war นี้ให้ในนามของเขา ซึ่งเป็นใครไม่ได้นอกจาก admin (ก็ตอนนี้มีแค่คนเดียว)

กรอกแค่ username กับ password
เสร็จแล้วจึงเลือก admin (Apache Tomcat)
อย่าลืมระบุจุดหมายปลายทาง (ไปหา Apache Tomcat)

บันทึกแล้วกดปุ่ม 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 ทำงานสมบูรณ์ดี

พัง!

มันพ้องว่า ท่านไม่มีอำนาจ 403

ต้องการ 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 ก็ได้

เข้าผ่าน Workspace ของแต่ละโปรเจกต์
โค้ดถูก copy อยู่นี่หมดทุกครั้ง

หรือไปดูสถานที่จริง

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 ครั้ง

ทดลองกลับไปแก้ไขไฟล์

ลองใส่ tag h1 กับสีเขียวลงไปแล้วกัน

แล้ว push code ขึ้น Github

รอสักพัก (ระยะทางระหว่าง server มันไกล) ก็จะปรากฏครั้งที่ 4

และทันใดนั้นก็…ดูเหมือนจะ work แต่ เมื่อลองเรียก servlet

http://X.X.X.X:8080/HelloJenkins/hello?name=ProS
ปรากฏว่า /hello ไม่สามารถเรียกได้ กลับได้ 404 Not Found

สรุป

ขอสรุปตรงนี้ก่อนว่า

  • โดยการแก้ไขไฟล์ 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 ทาง

  1. ง่ายที่สุด เปลี่ยน target 1.8 ตรงนี้ให้เป็น target 1.7 (จะได้ตรงกับ JRE ในเครื่อง)
  2. เปลี่ยน 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 ที่อยากเอามาผนวก ไว้โอกาสหน้านะครับ

--

--

No responses yet