วันนี้จะมาแบ่งปันเรื่องการนำ 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 วาดรูปคร่าวๆ ก็จะได้ประมาณนี้ Overview diagram

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

  • 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

After applying Secret

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

After applying pipeline & WebhookKey

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 นี้เลยละกัน Final results

  • เริ่มจาก 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