นำ Docker image จาก non-production ขึ้น production cluster บน OpenShift
วันนี้จะมาแบ่งปันเรื่องการนำ docker image ขึ้นงานบน production หลังจากผ่านการ build ในระบบ Continuous integration จาก non-production มาแล้ว งานที่ทำอยู่ใช้ OpenShift เป็น container platform deploy ใช้เองในบริษัท (เป็น on-premise อ่ะนะ)
blog นี้ต่อยอดมาจาก blog ใน OpenShift อีกที Promoting container images between registries with skopeo
อธิบายคร่าวๆ ว่าเราจะทำยังไง
เราจะให้ pipeline ใน non-production ไป trigger เจ้า pipeline ใน production พร้อมกับส่งข้อมูลที่จำเป็น (เช่น ชื่อ image, tag) จากนั้น pipeline ก็จะมี Stage ในการ copy image โดยใช้ Skopeo ซึ่งมาในรูปแบบของ Jenkins slave วาดรูปคร่าวๆ ก็จะได้ประมาณนี้
สิ่งที่ต้องมีก่อนเริ่ม
- OpenShift 2 clusters (non-production กับ production) หรือจะใช้ cluster เดียวแต่แยก 2 projects ก็ได้เหมือนกัน
- OpenShift CLI หา download ได้ใน Homebrew สำหรับคนใช้ macOS
- Docker image ที่ถูก build บน non-production cluster มี tag (อาจจะเป็น git commit hash ก็ได้) เพื่อให้ production refer ถึง
- Jenkins ซึ่งมากับ OpenShift อยู่ละ แต่ต้องลง Docker slave plugin เพิ่ม
1. ใน Non-production cluster สร้าง ServiceAccount และ assign RoleBinding สำหรับการ pull image ข้าม cluster หรือ project
OpenShift จริงๆ มันถูกสร้างต่อยอดจาก Kubernetes ดังนั้น concept เรื่อง resources แทบไม่ต่างจาก Kubernetes เลย
oc process -f across-project-image-puller.yaml | oc apply -f -
2. สร้าง Secret ที่เก็บ Bearer token ของ ServiceAccount เพื่อให้ production มา authenticate ได้
ใส่ flag --dry-run=true
เพราะไม่ต้องการ create ใน non-production cluster แต่ให้ผลลัพธ์ออกมาเป็น YAML file แล้วค่อยไป apply ใน production cluster แทน
oc create secret generic non-production-cluster-token --dry-run=true -o yaml \
--from-literal=token=$(oc serviceaccounts get-token across-project-image-puller) \
> non-production-cluster-token.yaml
จะได้ file ออกมาหน้าตาประมาณนี้
เอา token ไปแกะดูเล่นๆ ใน jwt.io จะได้หน้าตา payload ประมาณนี้
เสร็จแล้วก็ apply ใน production cluster
oc apply -f non-production-cluster-token.yaml
3. ใน Non-production cluster สร้าง Secret ที่จะ trigger production pipeline ผ่าน webhook
OpenShift จะรับ Secret text ที่เรากำหนดเองเป็น base64 ฉะนั้นต้อง encode ก่อน
oc apply -f production-pipeline-webhook-secret-text.yaml
คำอธิบาย
- การใส่ label
credential.sync.jenkins.openshift.io: "true"
ทำให้ OpenShift secret sync ขึ้นไปบน Jenkins credentials จะได้ maintain แค่ที่เดียว - สามารถแก้ไขชื่อ credentials ที่จะปรากฎบน Jenkins ผ่าน annotations
jenkins.openshift.io/secret.name: <your-custom-credentials-name-here>
4. สร้าง Pipeline ใน Non-production cluster
oc apply -f non-production-pipeline.yaml
คำอธิบาย
เราจะ trigger OpenShift production pipeline ผ่าน webhook โดยส่ง parameter ที่ใช้ในการ copy image ผ่าน request body และ refer webhook จาก secret ที่สร้างในข้อ 3
5. สร้าง Pipeline ใน Production cluster
oc apply -f production-pipeline.yaml
คำอธิบาย
- รับ parameters จาก non-production pipeline และ refer webhook จาก secret ที่เราสร้างในขั้นตอนที่ 3
- อ่าน non-production token (secret ที่เราสร้างในขั้นตอนที่ 2) และ production token
- นำ parameters มาประกอบเป็น location ของ docker image
- ใช้
set +x
เพื่อ print result ออกมาใน Jenkins console output
6. สร้าง Skopeo ในรูปแบบของ Jenkins Slave ด้วย Dockerfile
oc process -f skopeo-slave-build-config.yaml -p PROJECT_NAME=<your-production-project-here> | oc apply -f -
คำอธิบาย
Jenkins slave จะรันเป็น Docker container ซึ่งมี configuration เช่น
- การผูก secret ที่เราสร้างในขั้นตอนที่ 2
- Refer ไปหา image ที่เรา build จาก Dockerfile
- CPU และ memory
- Proxy
มาถึงตรงนี้แล้ว ก็น่าจะเห็นภาพว่ามีขั้นตอนอะไรบ้าง ก็ขอสรุปเป็นเหตุการณ์ที่เกิดขึ้นแบบคร่าวๆ ตาม diagram นี้เลยละกัน
- เริ่มจาก generate token จาก ServiceAccount ที่มี permission ในการ pull image จาก non-production ไปไว้ใน production
- Non-production pipeline ไป trigger production pipeline พร้อมกับส่ง parameters ในการ copy image ไป
- Skopeo Jenkins slave ใน production ไปอ่าน token เพื่อทำการ authenticate ไปยัง non-production และดึง parameters เพื่อปั้น docker image location
- รันคำสั่ง
skopeo copy
เป็นอันจบงาน
ดูตัวอย่างโค้ดได้ที่นี่เลยครับ openshift-docker-image-promotion