Drone CI คืออะไรทำไมถึงน่าสนใจ
ผมเปลี่ยนมาใช้ Drone CI ตั้งแต่ปี 2020 หลังจากที่ใช้ Jenkins มาเกือบ 10 ปีเหตุผลหลักคือ Jenkins มันหนักเกินไปสำหรับทีมเล็กๆแค่ติดตั้ง plugins ก็ปวดหัวแล้ว Java กิน RAM เป็น GB ส่วน Drone CI เขียนด้วย Go binary เดียวกิน RAM แค่ 50-100 MB ทุก step ใน pipeline รันใน container ทำให้ environment สะอาดทุกครั้งไม่มีปัญหา "works on my machine"
Drone CI เป็น CI/CD platform แบบ Container Native ที่ออกแบบมาให้เรียบง่าย Pipeline ทั้งหมดถูก define ด้วย YAML file ที่ชื่อ .drone.yml วางไว้ใน root ของ repository ทุก step รันใน Docker container แยกจากกันทำให้ isolation ดีมากและเนื่องจากใช้ Docker image เป็น runtime แต่ละ step สามารถใช้ tool version ที่ต่างกันได้โดยไม่ conflict
จุดเด่นของ Drone CI
สิ่งที่ทำให้ Drone โดดเด่นคือความเรียบง่าย configuration file ไม่ซับซ้อนเรียนรู้ได้ใน 30 นาทีถ้าคุณเคยเขียน Docker Compose มาก่อนจะรู้สึกคุ้นเคยทันทีเพราะ .drone.yml มี syntax คล้ายกันมากนอกจากนี้ Drone ยังมี Plugin system ที่ยอดเยี่ยมแต่ละ plugin ก็เป็น Docker image ทำให้สร้าง custom plugin ได้ง่าย
Drone CI กับ Woodpecker CI
ต้องเล่าให้ฟังว่าหลังจาก Harness ซื้อ Drone CI ไปในปี 2020 community ก็ fork ออกมาเป็น Woodpecker CI ซึ่ง maintain โดย community เป็นหลักสำหรับปี 2026 ถ้าคุณต้องการ open-source ล้วนๆผมแนะนำ Woodpecker CI แต่ถ้าต้องการ enterprise support และ integration กับ Harness platform ก็ใช้ Drone CI เลยทั้งคู่ใช้ .drone.yml format เดียวกัน
ติดตั้ง Drone CI Server + Runner
Drone CI มี 2 components หลักคือ Server ที่เป็น Web UI และจัดการ pipeline queue กับ Runner ที่รับ job มา execute จริงๆผมจะแสดงการติดตั้งแบบ Docker Compose ที่เชื่อมกับ Gitea (self-hosted Git)
เตรียม OAuth Application
# สำหรับ Gitea: ไปที่ Settings > Applications > สร้าง OAuth2 Application
# Application Name: Drone CI
# Redirect URI: https://drone.example.com/login
# จดบันทึก Client ID และ Client Secret
# สำหรับ GitHub: ไปที่ Settings > Developer Settings > OAuth Apps
# Homepage URL: https://drone.example.com
# Authorization callback URL: https://drone.example.com/login
Docker Compose สำหรับ Drone Server
# docker-compose.yml
services:
drone-server:
image: drone/drone:2
ports:
- "8080:80"
- "8443:443"
volumes:
- drone-data:/data
environment:
# Gitea configuration
DRONE_GITEA_SERVER: https://gitea.example.com
DRONE_GITEA_CLIENT_ID: your-client-id
DRONE_GITEA_CLIENT_SECRET: your-client-secret
# Server configuration
DRONE_RPC_SECRET: super-secret-rpc-key-change-me
DRONE_SERVER_HOST: drone.example.com
DRONE_SERVER_PROTO: https
# Admin
DRONE_USER_CREATE: username:bomadmin, admin:true
# Database (default: SQLite, production ใช้ PostgreSQL)
DRONE_DATABASE_DRIVER: postgres
DRONE_DATABASE_DATASOURCE: postgres://drone:dronepass@db:5432/drone?sslmode=disable
# Logging
DRONE_LOGS_DEBUG: "false"
DRONE_LOGS_TRACE: "false"
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: drone
POSTGRES_USER: drone
POSTGRES_PASSWORD: dronepass
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
drone-runner:
image: drone/drone-runner-docker:1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
DRONE_RPC_PROTO: https
DRONE_RPC_HOST: drone.example.com
DRONE_RPC_SECRET: super-secret-rpc-key-change-me
DRONE_RUNNER_CAPACITY: 4
DRONE_RUNNER_NAME: runner-01
# Resource limits per step
DRONE_MEMORY_LIMIT: 2147483648 # 2 GB
DRONE_CPU_LIMIT: 2000 # 2 CPU cores
depends_on:
- drone-server
restart: unless-stopped
volumes:
drone-data:
postgres-data:
# Start ทุกอย่าง
docker compose up -d
# ตรวจสอบ logs
docker compose logs -f drone-server
docker compose logs -f drone-runner
# เปิด browser ไปที่ https://drone.example.com
# Login ด้วย Gitea/GitHub account
ติดตั้ง Drone CLI
# Linux
curl -L https://github.com/harness/drone-cli/releases/latest/download/drone_linux_amd64.tar.gz | tar zx
sudo install -t /usr/local/bin drone
# ตั้งค่า CLI
export DRONE_SERVER=https://drone.example.com
export DRONE_TOKEN=your-personal-token # ได้จาก Web UI > Account Settings
# ทดสอบ
drone info
drone repo ls
เขียน Pipeline แรกด้วย .drone.yml
Pipeline ของ Drone เป็น YAML file ที่อยู่ใน root ของ repository ผมจะเริ่มจากตัวอย่างง่ายๆแล้วค่อยเพิ่มความซับซ้อน
Pipeline พื้นฐาน
# .drone.yml — Node.js application
kind: pipeline
type: docker
name: build-and-test
steps:
- name: install
image: node:20-alpine
commands:
- npm ci
- name: lint
image: node:20-alpine
commands:
- npm run lint
- name: test
image: node:20-alpine
commands:
- npm run test -- --coverage
- npm run test:e2e
- name: build
image: node:20-alpine
commands:
- npm run build
trigger:
branch:
- main
- develop
event:
- push
- pull_request
Pipeline สำหรับ Go Application
kind: pipeline
type: docker
name: go-pipeline
steps:
- name: test
image: golang:1.22-alpine
commands:
- go test -v -race -coverprofile=coverage.out ./...
- go vet ./...
- name: build
image: golang:1.22-alpine
commands:
- CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o app ./cmd/server
- name: docker
image: plugins/docker
settings:
repo: registry.example.com/myapp
registry: registry.example.com
username:
from_secret: docker_username
password:
from_secret: docker_password
tags:
- latest
-
when:
branch:
- main
event:
- push
Services — Database สำหรับ Integration Test
kind: pipeline
type: docker
name: integration-tests
services:
- name: database
image: postgres:16-alpine
environment:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
- name: redis
image: redis:7-alpine
steps:
- name: wait-for-db
image: postgres:16-alpine
commands:
- until pg_isready -h database -U testuser; do sleep 1; done
- name: migrate
image: golang:1.22-alpine
environment:
DATABASE_URL: postgres://testuser:testpass@database:5432/testdb?sslmode=disable
commands:
- go run ./cmd/migrate up
- name: test
image: golang:1.22-alpine
environment:
DATABASE_URL: postgres://testuser:testpass@database:5432/testdb?sslmode=disable
REDIS_URL: redis://redis:6379
commands:
- go test -v ./tests/integration/...
Multi-Pipeline ที่ทำงานขนาน
---
kind: pipeline
type: docker
name: backend
steps:
- name: test-backend
image: golang:1.22-alpine
commands:
- cd backend && go test ./...
---
kind: pipeline
type: docker
name: frontend
steps:
- name: test-frontend
image: node:20-alpine
commands:
- cd frontend && npm ci && npm test
---
kind: pipeline
type: docker
name: deploy
steps:
- name: deploy-production
image: plugins/ssh
settings:
host: production.example.com
username: deploy
key:
from_secret: deploy_ssh_key
script:
- cd /opt/app && docker compose pull && docker compose up -d
depends_on:
- backend
- frontend
trigger:
branch:
- main
event:
- push
Matrix Builds
kind: pipeline
type: docker
name: matrix-test
steps:
- name: test
image: python:
commands:
- pip install -r requirements.txt
- pytest -v
trigger:
event:
- push
matrix:
PYTHON_VERSION:
- "3.10"
- "3.11"
- "3.12"
Secrets Management และ Security
Secrets เป็นเรื่องสำคัญมากใน CI/CD ผมเห็นหลายคนฝัง password ไว้ใน .drone.yml ตรงๆซึ่งผิดมากเพราะ file นี้อยู่ใน Git repository
การจัดการ Secrets
# เพิ่ม secret ผ่าน CLI
drone secret add --repository myorg/myrepo \
--name docker_password \
--data "my-registry-password"
drone secret add --repository myorg/myrepo \
--name deploy_ssh_key \
--data @/path/to/id_rsa
# ดู secrets ที่มี (จะไม่แสดง value)
drone secret ls --repository myorg/myrepo
# ใช้ secret ใน pipeline
steps:
- name: deploy
image: plugins/docker
settings:
password:
from_secret: docker_password
Organization Secrets
# Secret ที่ใช้ได้ทุก repo ใน organization
drone orgsecret add myorg docker_registry_url --data "registry.example.com"
drone orgsecret add myorg docker_username --data "deployer"
drone orgsecret add myorg docker_password --data "secret-password"
# สำหรับ Vault Integration
# Drone รองรับ HashiCorp Vault โดยตรง
# ดูบทความ Vault ของผม: vault-secrets-management-0037.html
ถ้าต้องการ Secrets Management ที่ซับซ้อนขึ้นเช่น dynamic secrets หรือ secret rotation ผมแนะนำให้ใช้ HashiCorp Vault ร่วมกับ Drone CI
Docker Plugin — Build และ Push Image
- name: publish
image: plugins/docker
settings:
repo: myorg/myapp
auto_tag: true # สร้าง tag จาก Git tag อัตโนมัติ
dockerfile: Dockerfile
context: .
username:
from_secret: docker_username
password:
from_secret: docker_password
Slack/Discord Notification
- name: notify-slack
image: plugins/slack
settings:
webhook:
from_secret: slack_webhook
channel: ci-notifications
template: >
{{#success build.status}}
✅ Build #{{build.number}} passed for {{repo.name}}
{{else}}
❌ Build #{{build.number}} failed for {{repo.name}}
{{/success}}
when:
status:
- success
- failure
SCP/SSH Deploy
- name: deploy
image: appleboy/drone-scp
settings:
host: production.example.com
username: deploy
key:
from_secret: ssh_key
port: 22
target: /opt/app/
source:
- dist/*
- docker-compose.yml
Drone CI vs Jenkins vs GitHub Actions
คำถามที่ถูกถามบ่อยที่สุดผมจะเปรียบเทียบตรงๆ
Drone CI
ข้อดี: เบามากติดตั้งง่าย config เข้าใจง่าย Container Native ตั้งแต่แรกข้อเสีย: community เล็กกว่า Jenkins plugin ecosystem น้อยกว่า GitHub Actions enterprise features ต้องจ่ายเงินเหมาะกับ: ทีมเล็กถึงกลางที่ host Git เอง (Gitea, GitLab) และต้องการ CI/CD ที่เร็วและเบา
Jenkins
ข้อดี: plugin มากที่สุดในโลก customize ได้ทุกอย่าง community ใหญ่ข้อเสีย: กิน resource เยอะ (Java) config ซับซ้อน Groovy syntax มึน security patch ต้องอัพเดทบ่อยเหมาะกับ: องค์กรใหญ่ที่มี DevOps team ดูแลโดยเฉพาะ
GitHub Actions
ข้อดี: integrate กับ GitHub ได้สมบูรณ์แบบ marketplace มี actions เยอะ free tier ดีข้อเสีย: ผูกกับ GitHub ไม่สามารถ self-host ได้ทั้งหมด (runner ได้แต่ platform ไม่ได้) ราคาแพงสำหรับ private repos ที่ใช้เยอะเหมาะกับ: ทีมที่ใช้ GitHub เป็นหลักอยู่แล้ว
Drone CI กิน resource เท่าไร?
Drone Server ต้องการ RAM ประมาณ 100-200 MB และ CPU 1 core สำหรับ small-medium workloads ส่วน Runner ขึ้นอยู่กับจำนวน concurrent builds ที่ตั้งไว้ (DRONE_RUNNER_CAPACITY) แต่ละ build จะกิน resource ตาม Docker container ที่ใช้ผมแนะนำ server ที่มี RAM อย่างน้อย 4 GB สำหรับ Runner ที่รัน 4 builds พร้อมกัน
ใช้ Drone CI กับ private Docker registry ได้ไหม?
ได้ครับตั้งค่า registry credentials ใน Drone settings หรือใช้ image_pull_secrets ใน pipeline ผมใช้กับ Harbor registry เป็นประจำทำงานได้ดีมาก
Drone CI รองรับ monorepo ไหม?
รองรับครับใช้ trigger กับ paths condition ได้เช่น trigger pipeline เฉพาะเมื่อไฟล์ใน directory ที่กำหนดเปลี่ยนทำให้ไม่ต้อง build ทุกอย่างทุกครั้งที่ push code
trigger:
paths:
include:
- backend/**
- shared/**
สรุป
Drone CI เป็น CI/CD platform ที่เหมาะมากสำหรับทีมที่ต้องการระบบ CI/CD ที่เบาเร็วและจัดการง่ายโดยเฉพาะทีมที่ใช้ Docker อยู่แล้ว Configuration ผ่าน YAML file เดียวทำให้เรียนรู้ได้เร็ว Container-native architecture ทำให้ทุก build สะอาดและ reproducible
ถ้าคุณกำลังมองหา CI/CD สำหรับ self-hosted Git (Gitea, GitLab) และต้องการทางเลือกที่ไม่ใช่ Jenkins ผมแนะนำให้ลอง Drone CI หรือ Woodpecker CI ครับใช้ร่วมกับ Docker Compose สำหรับ deployment ได้ดีมาก
อ่านเพิ่มเติม: สอนเทรด Forex | XM Signal | IT Hardware | อาชีพ IT