Jenkins: ติดตั้งเซิร์ฟเวอร์ CI/CD ด้วย Docker บน Cloud VPS

ติดตั้ง Jenkins LTS ด้วย Docker Compose หลัง HTTPS ผ่าน Setup Wizard ตั้งค่าความปลอดภัย แยก build ไปรันบน agent แบบ WebSocket และสำรองข้อมูล JENKINS_HOME

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 10 นาที

แชร์FacebookXLINELinkedIn
Jenkins — Jenkins: ติดตั้งเซิร์ฟเวอร์ CI/CD ด้วย Docker บน Cloud VPS
Jenkins: ติดตั้งเซิร์ฟเวอร์ CI/CD ด้วย Docker บน Cloud VPS

คำตอบสั้น ๆ: ติดตั้ง Jenkins LTS ด้วย Docker Compose หลัง HTTPS ผ่าน Setup Wizard ตั้งค่าความปลอดภัย แยก build ไปรันบน agent แบบ WebSocket และสำรองข้อมูล JENKINS_HOME

คู่มือนี้อธิบาย Jenkins ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

Jenkins คือเซิร์ฟเวอร์ CI/CD แบบโอเพนซอร์สที่องค์กรทั่วโลกใช้สั่ง build, test และ deploy อัตโนมัติทุกครั้งที่มีโค้ดใหม่ เขียนขั้นตอนเป็นโค้ดในไฟล์ Jenkinsfile และมีปลั๊กอินหลายพันตัวเชื่อมกับ Git, Docker, การแจ้งเตือน และระบบคลาวด์ เหมาะกับทีมพัฒนาที่ต้องการควบคุม pipeline และข้อมูลลับของตัวเองบนเซิร์ฟเวอร์ขององค์กร

คู่มือนี้ติดตั้งตัวควบคุม (controller) ด้วย Docker Compose หลัง HTTPS ผ่านขั้นตอน Setup Wizard ปิดช่องโหว่ที่พบบ่อย แล้วเพิ่มเครื่อง agent สำหรับรันงาน build จริง เมื่อจบคุณจะมีระบบ CI ที่แยกหน้าที่ชัดเจนและสำรองข้อมูลได้

สิ่งที่ต้องเตรียม

  • Cloud VPS ที่ใช้ Ubuntu 24.04 พร้อม Docker Engine และ Compose plugin สำหรับ controller ขนาดเริ่มต้นราว 2 vCPU / RAM 4 GB (ค่าประมาณ ปรับตามจำนวน job และปลั๊กอิน)
  • เครื่อง agent อีกอย่างน้อยหนึ่งเครื่องสำหรับรัน build ขนาดขึ้นกับงาน เช่น คอมไพล์โค้ดหรือ build image
  • ซับโดเมน เช่น ci.example.com และ Nginx Proxy Manager พร้อมเครือข่าย proxy
  • Git Server ที่ทีมใช้อยู่ เช่น Gitea หรือ GitLab

หลักสำคัญคือ controller ทำหน้าที่จัดคิว เก็บผลลัพธ์ และเก็บข้อมูลลับ ไม่ควรรัน build เอง เพราะโค้ดที่ build อาจอ่านไฟล์ทุกอย่างใน JENKINS_HOME รวมถึง credential ของทุกโปรเจกต์ได้

แผนภาพ Jenkins controller หลัง Nginx Proxy Manager รับ webhook จาก Git Server และสั่งงาน build ไปที่ agent ผ่าน WebSocket
controller จัดคิวและเก็บข้อมูลลับ ส่วน build จริงรันบน agent ที่เชื่อมเข้ามาผ่าน HTTPS

ขั้นตอนที่ 1: เตรียมโฟลเดอร์และสิทธิ์ไฟล์

คอนเทนเนอร์รันด้วยผู้ใช้ UID 1000 จึงต้องกำหนดเจ้าของโฟลเดอร์ข้อมูลให้ตรง ไม่เช่นนั้นจะเริ่มระบบไม่ได้

sudo mkdir -p /opt/ci/home
sudo chown -R 1000:1000 /opt/ci/home
sudo chown $USER: /opt/ci
cd /opt/ci
echo 'JAVA_OPTS=-Xmx2g -Duser.timezone=Asia/Bangkok' > .env

ขั้นตอนที่ 2: เขียน compose.yaml แล้วเริ่มระบบ

services:
  jenkins:
    image: jenkins/jenkins:lts-jdk21
    container_name: jenkins
    restart: unless-stopped
    environment:
      TZ: Asia/Bangkok
      JAVA_OPTS: ${JAVA_OPTS}
    volumes:
      - ./home:/var/jenkins_home
    networks:
      - proxy

networks:
  proxy:
    external: true

แท็ก lts-jdk21 คือสาย Long-Term Support ที่ออกรุ่นแก้ไขสม่ำเสมอ เหมาะกับงาน production มากกว่ารุ่น weekly ไฟล์นี้ไม่ publish พอร์ต 8080 และไม่เปิดพอร์ต 50000 เพราะเราจะให้ agent เชื่อมต่อผ่าน WebSocket บน HTTPS แทน และ ไม่ mount /var/run/docker.sock เข้า controller เพราะเท่ากับให้สิทธิ์ root ของเครื่องแก่ทุก job

docker compose up -d
docker compose logs -f

ขั้นตอนที่ 3: เปิด HTTPS แล้วผ่าน Setup Wizard

ใน Nginx Proxy Manager เพิ่ม Proxy Host กรอก Domain Names ci.example.com, Forward Hostname jenkins, Forward Port 8080 เปิด Websockets Support (จำเป็นสำหรับ agent แบบ WebSocket) และ Block Common Exploits จากนั้นขอใบรับรองพร้อม Force SSL

เปิด https://ci.example.com จะเจอหน้า Unlock Jenkins ดูรหัสผ่านเริ่มต้นด้วยคำสั่งนี้แล้ววางในช่อง Administrator password

docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
ลำดับ Setup Wizard ของ Jenkins ตั้งแต่ Unlock Jenkins ติดตั้งปลั๊กอิน สร้างผู้ดูแล จนถึงตั้ง Jenkins URL
ทำให้จบในรอบเดียวผ่าน HTTPS และอย่าเปิดหน้านี้ทิ้งไว้ให้คนอื่นเข้าก่อน

เลือก Install suggested plugins สำหรับการเริ่มต้น ในหน้า Create First Admin User ตั้งชื่อผู้ใช้ที่ไม่ใช่ admin พร้อมรหัสผ่านยาว ในหน้า Instance Configuration ตรวจว่า Jenkins URL เป็น https://ci.example.com/ แล้วกด Save and Finish

ขั้นตอนที่ 4: ตั้งค่าความปลอดภัยให้ controller

ไปที่ Manage Jenkins → Security แล้วตรวจค่าต่อไปนี้

  • Security Realm: Jenkins' own user database และปิด Allow users to sign up
  • Authorization: เลือก Matrix-based security ให้สิทธิ์ Overall/Administer เฉพาะผู้ดูแล ส่วนนักพัฒนาได้ Overall/Read กับสิทธิ์ Job ที่จำเป็น และไม่ให้สิทธิ์ใดกับ Anonymous
  • Agents → TCP port for inbound agents: เลือก Disable เมื่อใช้ agent แบบ WebSocket ทั้งหมด
ภาพจำลองหน้า Manage Jenkins Security ตั้ง Security Realm ปิดการสมัคร ใช้ Matrix-based security และปิด TCP port สำหรับ agent
ปิดการสมัครเอง ใช้สิทธิ์แบบ Matrix และปิดพอร์ต TCP เมื่อ agent ใช้ WebSocket (ภาพจำลอง)

จากนั้นกลับไปที่หน้าจัดการระบบ เลือก Nodes → Built-In Node → Configure ตั้ง Number of executors เป็น 0 เพื่อไม่ให้ build ใดรันบน controller อีก เก็บรหัสผ่านและ token ทั้งหมดในเมนู Credentials ห้ามเขียนลงในไฟล์ pipeline และเมื่อระบบแสดงคำเตือนความปลอดภัยของปลั๊กอิน ให้อัปเดตหรือถอดปลั๊กอินนั้นทันที

ขั้นตอนที่ 5: เพิ่ม agent แบบ WebSocket

ไปที่ Manage Jenkins → Nodes → New Node ตั้งชื่อ linux-agent-01 เลือก Permanent Agent ตั้ง Remote root directory เป็น /home/jenkins/agent ใส่ Labels เช่น linux docker เลือก Launch method เป็น Launch agent by connecting it to the controller และติ๊ก Use WebSocket แล้วกด Save หน้า node จะแสดงค่า secret ของ agent

บนเครื่อง agent ที่ติดตั้ง Docker แล้ว รัน agent เป็นคอนเทนเนอร์ (หรือดาวน์โหลด agent.jar แล้วรันด้วย Java 21 ตามคำสั่งที่หน้า node แสดง)

docker run -d --init --name ci-agent --restart unless-stopped \
  jenkins/inbound-agent:latest-jdk21 \
  -url https://ci.example.com/ -webSocket -workDir=/home/jenkins/agent \
  ค่า_secret_จากหน้า_node linux-agent-01

ไม่กี่วินาทีสถานะ node จะเปลี่ยนเป็น online ทดสอบด้วย Pipeline ง่าย ๆ ที่ระบุ agent { label 'linux' } แล้วสั่ง sh 'uname -a' ผลลัพธ์ต้องแสดงชื่อเครื่อง agent ไม่ใช่ controller

ขั้นตอนที่ 6: สำรองข้อมูลและอัปเดต

ทุกอย่างที่สำคัญอยู่ในโฟลเดอร์ home ได้แก่ การตั้งค่า job ประวัติ build ปลั๊กอิน และ credential ที่เข้ารหัสด้วยไฟล์ใน secrets/ ต้องสำรองคู่กันเสมอ ส่วน workspace และแคชสร้างใหม่ได้ จึงตัดออกเพื่อลดขนาด

sudo mkdir -p /var/backups/ci
sudo tar czf /var/backups/ci/home-$(date +%F).tar.gz \
  --exclude='./workspace' --exclude='./caches' -C /opt/ci/home .

ส่งไฟล์ออกนอกเครื่องแบบเข้ารหัส เพราะมีข้อมูลลับของทุกระบบอยู่ข้างใน อัปเดตด้วย docker compose pull && docker compose up -d หลังสำรองข้อมูล แล้วอัปเดตปลั๊กอินที่เมนู Plugins → Updates ต่อ อ่านแนวทางเพิ่มเติมที่ Securing Jenkins

ปัญหาที่พบบ่อยเกี่ยวกับ Jenkins

คอนเทนเนอร์รีสตาร์ตวนและล็อกขึ้น Permission denied ที่โฟลเดอร์ข้อมูล?

โฟลเดอร์บนโฮสต์เป็นของ root คอนเทนเนอร์ที่รันด้วย UID 1000 จึงเขียนไฟล์ไม่ได้ แก้ด้วย sudo chown -R 1000:1000 /opt/ci/home แล้วรัน docker compose up -d อีกครั้ง

หน้า Manage Jenkins เตือนว่า reverse proxy setup is broken?

ค่า Jenkins URL ในหน้า System ไม่ตรงกับ URL ที่เปิดอยู่ หรือ proxy ไม่ส่ง header X-Forwarded-Proto ตั้ง Jenkins URL เป็น https://ci.example.com/ และเข้าผ่านโดเมนนี้เท่านั้น Nginx Proxy Manager ส่ง header ที่จำเป็นให้อยู่แล้ว

ต้องการ build Docker image ใน pipeline ทำอย่างไรให้ปลอดภัย?

ติดตั้ง Docker บนเครื่อง agent แล้วให้ job ที่ต้อง build image รันบน agent ที่มี label docker อย่าแก้ปัญหาด้วยการ mount docker.sock เข้า controller เพราะ job ใดก็ตามจะได้สิทธิ์เทียบเท่า root ของเครื่อง controller ทันที

agent ขึ้น offline หรือเชื่อมต่อไม่สำเร็จ?

ตรวจว่าเปิด Websockets Support ใน Proxy Host แล้ว, ค่า -url เป็น https และลงท้ายด้วย /, ชื่อ agent กับ secret ตรงกับหน้า node และดูล็อกด้วย docker logs ci-agent รายละเอียดของ agent ดูได้ที่ Managing Nodes

เช็กลิสต์ความปลอดภัย Jenkins เช่น executors บน controller เป็น 0 ไม่ mount docker.sock และอัปเดตปลั๊กอิน
ตรวจซ้ำทุกเดือน และทุกครั้งที่ติดตั้งปลั๊กอินใหม่

ต้องการแยกเครื่อง controller และ agent ให้เหมาะกับขนาดงาน build ดู Cloud Server หรือ ติดต่อทีมงาน THAI DATA CLOUD เพื่อช่วยวางระบบ CI/CD ขององค์กร

อ่านเพิ่มเติมเกี่ยวกับ Jenkins

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน