Cache docker-compose run ใน Github Actions
ปรกติทุกครั้งที่เรา build ของด้วย Github actions เราจะไม่ได้ run บนเครื่องเดิม ทำให้ Docker cache ที่เราเคย build ไว้หายหมด ไม่เหมือนกันกับตอนเรา run บนเครื่องตัวเองที่ layer ที่เคยถูก build ไว้จะถูก cache ทำให้ build ครั้งถัด ๆ ไปเร็วขึ้น
ถ้าเป็นการ build image แล้ว push ไปบน registry เราสามารถใช้ action docker/build-push-action@v2
ได้ ซึ่งจะมี option ให้ใส่ cache-from
และ cache-to
อยู่แล้ว ง่ายมาก ไม่มีอะไร จะเลือก cache แบบ local, registry หรือไปเก็บใน Github cache API ก็ได้
มีนิดนึงคือตอนนี้ ถ้าใช้ local cache จะมีปัญหาคือ cache บวมไปเรื่อย ๆ ตอนนี้เค้าแก้โดยการ ลบ cache เก่าเอาเอง
ถ้าเป็น docker-compose run หล่ะ?
ถ้าเป็นคำสั่ง docker-compose การ build มันจะใช้คำสั่ง Docker build ที่อยู่บนเครื่องเอง ไม่ได้ใช้ docker/build-push-action@v2
ซึ่งมัน build ผ่าน Buildx อีกที เราเลยไม่ได้ใช้ประโยชน์จาก cache ที่อยู่ใน docker/build-push-action@v2
ตรง ๆ ได้
ด้านล่างจะเล่า 3 ทางที่ผมลองพยายามทำให้มัน cache ได้ ซึ่ง 2 ทางแรก ทำแล้วไม่ work ถ้าใครอยากดูเฉลยสามารถกระโดดข้ามไปอ่านทางสุดท้ายเลยก็ได้ครับ
Mount node_modules
ออกมาเก็บไว้
ในกรณีของผม สิ่งที่ทำให้การ run e2e test ช้าคือต้องมาลง cypress ใหม่ทุกรอบ ผมเลยคิดว่าถ้าผม mount node_modules folder ออกมาเก็บไว้ได้ พอ run ครั้งหน้า ก็ไม่ต้องลงใหม่แล้ว เพราะ node_modules มี cypress ที่ลงจากรอบที่แล้วเก็บไว้แล้ว
เดิมที compose file ผมหน้าตาเป็นแบบนี้
version: "3.3"
services:
api:
build:
context: ../../api
command: /app/scripts/start_api_with_test_fixture
e2e:
build:
context: ../../web2
dockerfile: Dockerfile.test
command: yarn test:e2e --headless
volumes:
- '../../web/tests/e2e/screenshots:/app/tests/e2e/screenshots'
- '../../web/tests/e2e/videos:/app/tests/e2e/videos'
environment:
- VUE_APP_BASE_API=http://api:3000
depends_on:
- api
สิ่งที่ผมเพิ่มเข้าไปคือ mount volumn เพิ่มเข้าไปตอน run e2e แต่ผลปรากฏว่าไม่ work เพราะว่าขั้นตอนการ install node_modules มันเกิดขึ้นตอน build ไม่ใช่ตอน run พอผม mount volumn เข้าไปตอน run เลยทำให้ node_modules มันกลายเป็น folder เปล่า ก็เลยแตก
สามารถดู commit speed up e2e tests on local poorprogrammer/cfo@2c71e3d
ในส่วนอ้างอิงเพิ่มเติมได้นะครับ
แผนแรกไม่เวิร์ค ผมก็เลยไปแผน 2
ใช้ docker/build-push-action@v2 build cache ก่อน
ผมไปเติมใน file build.yml
ของ Github actions เลย ให้มันใช้ docker/build-push-action@v2
ในการ build image ที่ต้อง test ก่อน เพราะคำสั่งนี้สามารถ cache ของได้ เสร็จแล้วค่อยสั่ง docker-compose run e2e test ตามด้านล่าง
- name: Build docker cache for e2e tests
uses: docker/build-push-action@v2
with:
context: "{{defaultContext}}:web2"
file: "Dockerfile.test"
cache-from: type=gha
cache-to: type=gha,mode=max
- name: run e2e tests
run: docker-compose -f compose/test/docker-compose.yml run e2e
ใครอยากรู้รายละเอียดเพิ่มเติม ดู commit Cache with Github API poorprogrammer/cfo@03bbfd8
ด้านล่างเอานะ
สรุปไม่เวิร์คอยู่ดี เพราะ cached ที่เกิดขึ้นจาก docker/build-push-action@v2
มันไม่ถูก reuse ตอนสั่ง docker-compose
ผมเดาว่ามันใช้ builder คนละตัวกัน เพราะอีกตัวใช้ Buildx
สูงสุดสู่สามัญ
กลับมาวิธีบ้าน ๆ คือสั่ง build บนเครื่องตัวเอง แล้ว push image นี้ไปเก็บไว้ใน registry แล้วค่อยใช้ docker-compose มาดึง image ที่ install cypress เสร็จแล้วไปใช้แทน
ข้อเสียคือทุกครั้งที่มีการเปลี่ยนแปลง package ที่ต้องใช้ ต้องมา build cache ใหม่แล้ว push ขึ้น registry เอง
แต่มันเวิร์คนะ ใครสนใจไปดู commit try to optimize build time on github actions poorprogrammer/cfo@a685773
ด้านล่างเพิ่มได้
ทำเสร็จแล้วเร็วขึ้นแค่ไหน?
เกือบนาทีนึง 555 แต่ หลาย ๆ build ก็เยอะอยู่นะ
หวังว่าจะเป็นประโยชน์ครับ