We are not waiting for future, We create the future

Tags


แก้ปัญหาการ cache ไฟล์ใน Gitlab-ci

16th August 2019

ในการทำระบบ CI/CD ให้กับแอพพลิเคชั่นของภาษาที่ต้องมีการติดตั้ง Dependencies ต่างๆ เช่น Nodejs (node_module) หรือ PHP (vender) เป็นต้น ส่วนใหญ่ผมจะแยกเป็น 2 Job คือ job สำหรับติดตั้ง dependencies และ job ที่จะนำ dependencies นั้นไปใช้ เช่น

stages:
  - build
  - release

#
# Install node_module
#
npm:
  stage: build
  image: node:10-alpine
  script:
    - '[ -f package-lock.json ] && rm package-lock.json'
    - npm i
  cache:
    key: npm-cache
    paths:
      - node_modules
#
# Create docker image
#
docker-image:
  stage: release
  image: docker:latest
  services:
    - docker:18-dind
  cache:
    key: npm-cache
    paths:
      - node_modules
    policy: pull
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:master .
    - docker push $CI_REGISTRY_IMAGE:master

จากโค็ดด้านบน

  • npm job จะทำการติดตั้ง node_modules แล้วจากนั้นก็ทำการ upload เก็บไว้โดยใช้เป็นชื่อ npm-cache
  • docker-image job ก็จะทำการเอา npm-cahce key จากนั้นด้านโหลดลงมาเป็น node_modules อีกครั้ง แล้วผมก็ทำการ build เป็น docker image เก็บไว้ที่ registry ของ gitlab

เมื่อมีการเรียก pipeline นี้อีกครั้ง

  • npm job ก็จะทำการโหลดไฟล์ npm-cache key มา เราก็จะได้ node_modules แล้วค่อยติดตั้ง npm i อีกครั้ง ซึ่งการติดตั้งครั้งนี้จะเร็วขึ้นเพราะเรามี node_modules ไว้แล้ว เมื่อจบก็จะทำการ upload เก็บไว้โดยใช้เป็นชื่อ npm-cache อีกครั้ง
  • docker-image job ก็จะทำการเอา npm-cahce key โหลดลงมาเป็น node_modules อีกครั้ง แล้วก็ทำงานตาม script ไปเรื่อยๆ

การทำ caching แบบนี้จะทำให้ pipeline เราทำงานเร็วขึ้นมา เพราะไม่จำเป็นต้องติดตั้ง node_modules ทุกครั้ง

ปัญหาของ cache ใน gitlab-ci.yml

แต่เดียวก่อน!!! จากที่ผมใช้งานในบ้างครั้ง สมมติใน package.json เรามี dependencies 2 ตัว pipeline เราก็ทำงานปกติไปตาม Step คือ

  • ติดตั้ง node_modules
  • อัพโหลดเก็บไว้
  • job ต่อมาโหลดมาใช้งาน

คราวนี้เรามีการเพิ่ม dependencies เป็น 4 ตัว pipeline ในขั้นตอน npm i ก็จะติดตั้งเฉพาะ dependencies ที่เพิ่มเข้ามา แล้วอัพโหลด node_modules เก็บไว้เหมือนเดิม

ปัญหามันอยู่ช่วงนี้ กล่าวคือ job ต่อมามันดันไปโหลด node_modules ของเก่าที่มี dependencies 2 ตัว มาใช้ แล้วพอเราเอาแอพพลิเคชั่นไปใช้งานจริงขึ้น Server ก็จะเจอ error ว่า dependencies ไม่ครบทันที

ซึ่งการเรียก cache ไฟล์ผิดนี้เกิดขึ้นบ่อยมาก ถ้ามันเกิดแบบนี้ผมก็จะต้องเรียก pipeline ตัวนี้ซ้ำๆ สักสองถึงสามรอบถึงจะโอเค

วิธีแก้ปัญหา cache ใน gitlab-ci

ผมจะใช้ artifacts มาช่วยในการเก็บไฟล์ dependencies ต่างๆ แล้วให้ Job ที่ต้องการไปเรียกใช้ เช่น

stages:
  - build
  - release

#
# Install node_module
#
npm:
  stage: build
  image: node:10-alpine
  script:
    - '[ -f package-lock.json ] && rm package-lock.json'
    - npm i
  cache:
    key: npm-cache
    paths:
      - node_modules
  artifacts:
    paths:
      - node_modules
    expire_in: 1 days
    when: always
#
# Create docker image
#
docker-image:
  stage: release
  image: docker:latest
  services:
    - docker:18-dind
  dependencies:
    - npm
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:master .
    - docker push $CI_REGISTRY_IMAGE:master

ใน npm job ผมจะเพิ่ม artifacts เข้ามาเก็บ node_modules ไว้ด้วย และก็ให้มัน cache เก็บไว้แบบเดิม

...
...
artifacts:
  paths:
    - node_modules
  expire_in: 1 days
  when: always
...
...

ต่อมา docker-image job จากแต่ก่อนจะโหลด cache มาใช้ คราวนี้ก็ให้โหลด artifacts มาใช้เลย

...
...
dependencies:
  - npm
...
...

เพียงเท่านี้ก็จะจบปัญหาเรื่องการนำ dependencies มาไม่ครบแล้ว ส่วนใครมีวิธีอื่นที่ดีกว่านี้ก็แนะนำมาได้นะครับ

IT manager & DevOps @Twin Synergy Co.,Ltd

View Comments