We are not waiting for future, We create the future

Tags


การทำ CI/CD ให้กับ Microservice บน Gitlab-ci

4th July 2019

หลังจากที่ได้รู้วิธีการเขียน gitlab-ci กับของ golang แล้วก็ nodejs กันมาแล้ว คราวนี้เราจะมาลองเพิ่มระดับความยากอีกระดับ นั้นก็คือการเขียน gitlab-ci ให้ใช้งานกับ Microservice กัน

โดยผมเลือกใช้ mono-repo ในการจัดการกับ Microservice เพื่อเป็นการง่ายในการจัดการแต่ละ service ที่จะเกิดขึ้นให้อยู่ใน Repository เดียวไปเลย

Multiple repo & Mono repo

ตัวอย่างจากรูปบนให้สังเกตุรูปด้านขวาจะเป็นการสร้างมา 1 repository จากนั้นข้างในจะแยกโฟลเดอร์เป็นแต่ละ service เพื่อให้เราจัดการไฟล์ต่างๆ ได้ง่ายขึ้น

เตรียมตัว

ก่อนจะมาลุยกันถ้าใครยังไม่เคยใช้ gitlab-ci ให้ไปศึกษาพื้นฐานมาก่อนจาก https://blog.twinsynergy.co.th/tag/gitlab/ ซึ่งเป็นบทความที่ผมเคยเขียนมาแล้ว เพราะในบทความนี้ผมจะไม่อธิบายโค็ดทั้งหมด จะอธิบายในส่วนแค่เพิ่มเติมของการทำ Micro service เท่านั้น ซึ่งหลังจากข้อความนี้ไปผมถือว่าทุกคนที่อ่านเคยเขียน gitlab-ci มาแล้ว

ผมได้ทำโค็ดตัวอย่างมาแล้วสามารถ clone ได้เลยจาก https://gitlab.com/twin-opensource/microservice-cicd  ซึ่ง repo อันนี้จะมี 2 services ได้แก่ nodejs และ golang จะเป็นการเขียนที่ต่างภาษากันจะเห็นภาพชัดเจนขึ้น ซึ่งโครงสร้างภายในจะเป็นดังนี้

microservice-cicd/
├── .gitignore
├── .gitlab-ci.yml
├── golang
│   ├── Dockerfile
│   ├── .gci.yml
│   ├── .gitignore
│   ├── Gopkg.lock
│   ├── Gopkg.toml
│   ├── main.go
│   └── README.md
├── nodejs
│   ├── Dockerfile
│   ├── .dockerignore
│   ├── .gci.yml
│   ├── .gitignore
│   ├── package.json
│   ├── README.md
│   └── server.js
└── readme.md
  • golang/ และ nodejs/ ทั้งสองโฟลเดอร์นี้จะเป็น service ที่เราจะทำ ซึ่งเราควรตั้งชื่อตาม service ที่จะใช้งานจริง
  • .gitignore เอาไว้บังคับไม่ให้เอาไฟล์บ้างไฟล์ขึ้นบน Git โดยผมใช้ gitignore.io ช่วยสร้างขึ้นมา
  • .gitlab-ci.yml เป็นไฟล์ไว้ทำ CI/CD ของ gitlab

อธิบาย .gitlab-ci.yml

stages:
  - test
  - dep
  - build
  - release
  - deploy

include:
  - '/nodejs/.gci.yml'
  - '/golang/.gci.yml'

จะเห็นว่าในไฟล์นี้ผมจะกำหนดแค่สองค่าเท่านั้นคือ

  • stages: เพื่อบอกว่าใน pipeline มี stage อะไรบ้าง
  • include: เป็นการนำไฟล์ gitlab-ci จากที่อื่นเข้ามาได้ โดยผมนำมาประยุกต์ใช้เพื่อให้สามารถเขียน pipeline แยกใส่แต่ละ service ไปเลยจะได้จัดการง่ายขึ้น สามารถอ่านเพิ่มเติมการใช้งาน include ได้จาก https://docs.gitlab.com/ee/ci/yaml/#include

อธิบาย .gci.yml แต่ละ service

คราวนี้เราลองมาดูไฟล์ .gci.yml ที่ผมทำการ include เข้ามา ซึ่งวิธีการเขียนมันก็คือการเขียนไฟล์แบบ .gitlab-ci.yml แต่ผมแค่เปลี่ยนชื่อไฟล์มันเฉยๆ

Nodejs service

โฟลเดอร์ nodejs ไฟล์ .gci.yml จะเป็นดังนี้

variables:
  NODEJS_PATH: "nodejs"
  DEV_NODEJS_BRANCH: "dev-release-nodejs"

.dev_only: &dev_only
  only:
    - dev-release-nodejs
  • variable: เป็นการกำหนดค่าต่างๆ เพื่อนำมาใช้เฉพาะในนี้
  • .dev_only ผมทำเป็น anchor ไว้ แล้วใช้ only: เพื่อกำหนดให้ pipeline นี้ทำงานเฉพาะแค่ dev-release-nodejs branch เท่านั้น
nodejs-npm:
  stage: build
  image: node:10-alpine
  script:
    - cd $NODEJS_PATH
    - '[ -f package-lock.json ] && rm package-lock.json'
    - npm i
  cache:
    key: npm-cache
    paths:
      - $NODEJS_PATH/node_modules
  <<: *dev_only

nodejs-npm job นั้นผมจะให้มัน install node_modules แล้วก็ caching เก็บไว้ โดยจะเฉพาะ  dev-release-nodejs branch เท่านั้น สังเกตุจาก <<: *dev_only ที่ผมใส่เข้ามา ซึ่งมันจะไปดึงค่าจาก anchor ข้างบนมาใช้ โดยเวลามันอ่านจริงจะเป็นแบบนี้

nodejs-npm:
  stage: build
  image: node:10-alpine
  script:
    - cd nodejs
    - '[ -f package-lock.json ] && rm package-lock.json'
    - npm i
  cache:
    key: npm-cache
    paths:
      - nodejs/node_modules
  only:
    - dev-release-nodejs

ส่วน job อื่นก็จะถูกกำหนดจาก <<: *dev_only เหมือนกัน

Golang service

หลักการเขียนเหมือนกับของ nodejs service ข้างต้นเลย คือผมจะทำ archor

.dev_only: &dev_only
  only:
    - dev-release-golang

กำหนดไว้แล้วนำไปใช้กับทุก job เพื่อให้แต่ละ job นั้นทำงานเฉพาะ dev-release-golang เท่านั้น

วิธีเรียกให้ CI/CD ทำงานแต่ละ service

โดยปกติผมจะสร้าง dev branch ขึ้นมาก่อนเป็นตัวหลัก แล้วให้ developer แต่ละคน แตก branch ตาม issue ที่ตัวเองได้ไปจาก dev branch นี้ แล้วไปทำงานของตัวเองกัน จากนั้นทำการสร้าง Merge request จากหน้าเว็บ gitlab เข้ามายัง dev branch นี้ แล้วผมจะตรวจสอบ code ต่างๆ ถ้าโอเค ก็จะกดปุ่มให้มัน Merge เข้า dev branch

git flow

หลังจากที่ merge เข้า dev branch แล้วตัว pipeline จะยังไม่ทำงาน เพราะเราได้กำหนดไปแล้วว่าให้ทำงานเฉพาะ dev-release-nodejs หรือ dev-release-golang

เราก็แค่สร้าง merge request จาก dev มายัง dev-release-nodejs ถ้าอยากให้ nodejs service ทำงาน

Master to dev-release-nodejs

และสร้าง merge request จาก dev มายัง dev-release-golang ถ้าอยากให้ golang service ทำงาน

Master to dev-release-golang

เพียงเท่านั้นเราก็จะสามารถสั่งการทำงาน CI/CD ให้แต่ละ service ได้แล้ว

ขอให้สนุกกับการเขียน gitlab-ci นะครับ :)

IT manager & DevOps @Twin Synergy Co.,Ltd

View Comments