Hiểu cơ chế layer caching khi build docker image để viết Dockerfile tốt hơn

Hiểu cơ chế layer caching khi build docker image để viết Dockerfile tốt hơn

Vấn đề

Docker gần đây đang nổi đình đám trong cộng đồng IT nên ngày càng phổ biến, được nhiều người dùng hơn. Bằng chứng là tần suất từ Docker xuất hiện trong JD của nhà tuyển dụng ngày càng nhiều. Công ty của tôi sử dụng Docker, dự án của tôi cũng dùng Docker, dự án làm cho người khác cũng dùng nó… Docker xuất hiện như một giải pháp "đóng gói" quá thuận lợi cho cuộc cách mạng tự động hóa.

Nhưng có một điều đã tồn tại song song với nó từ xưa đến này là vấn đề build docker image khá tốn thời gian. Dung lượng của một "hình ảnh" docker nhiều khi lên đến cả hàng GB. Docker bổng nhiên trở thành một "sát thủ ổ cứng". Nhiều câu nói đùa rằng, ông bạn có đủ ổ cứng không mà dám CI/CD với Docker? Nhưng trong bài viết này, tôi không nói về vấn đề nó ngốn dung lượng như thế nào, mà tập trung vào cách làm sao để giảm được tốc độ build docker image.

Có một vài cách để tăng tốc độ build cũng như làm giảm kích thước của docker image như chỉ cài đặt các gói cần thiết, sử dụng các hình ảnh cơ bản nhẹ (alpine), sử dụng ít layer nhất có thể… Chúng đều xoay quanh vấn đề là giữ cho docker tải xuống các tệp cần thiết ít nhất và nhẹ nhất.

Ngoài ra, còn một cách để tăng tốc là tận dụng layer caching của Docker. Vậy nó là gì thì xin mời bạn đọc tiếp bài viết dưới đây.

Sử dụng thứ tự lớp hình ảnh để có lợi cho bạn

Docker image được tạo thành từ các lớp (layer) xếp chồng lên nhau. Mỗi layer đại diện cho một hướng dẫn trong Dockerfile của image. Ví dụ một file Dockerfile như sau:

FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="[email protected]"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py

Mỗi dòng đại diện cho một layer, chúng có kích thước khác nhau và phụ thuộc vào lượng công việc mà chúng làm. Tổng dung lượng của các layer tạo thành dung lượng của image. Chính vì thế, layer càng nhiều và càng nặng thì image càng to. Để hiểu rõ hơn, hãy sử dụng lệnh docker history <image> để biết chi tiết về các lớp tạo thành image.

Ví dụ dưới đây là các lớp và dung lượng của một redislabs/redisearch image:

$ docker history redislabs/redisearch

Kết quả giống như sau:

docker history redislabs/redisearch

Mỗi lần sử dụng lệnh docker build image, docker sẽ phải chạy qua lần lượt từng layer. Nhưng nếu tận dụng layer caching, docker chỉ thực sự tạo lại các lớp bắt đầu từ lớp có sự thay đổi trở về sau. Điều này đồng nghĩa với việc các layer không bị thay đổi đổ về trước có thời gian thực hiện gần như ngay lập tức. Nghĩa là bạn chỉ tốn thời gian cho lần chạy đầu tiên, ở các lần chạy sau đó docker sẽ tận dụng cache để build image.

Ví dụ dưới đây là một Dockerfile của ứng dụng viết bằng Node.js.

FROM node:18-alpine

WORKDIR /app

COPY . .

RUN npm install

Các gói phụ thuộc (dependencies) là rất ít khi bị thay đổi (thêm/sửa/xóa), cho nên khả năng sử dụng lệnh npm install là rất hiếm. Nhưng trong ví dụ trên, rõ ràng dòng lệnh COPY đã làm xáo trộn, gây ra sự thay đổi của layer nên theo lẽ thường, tất cả layer phía sau nó phải được thực hiện mà không có bộ đệm. Bạn sẽ tốn thời gian lẫn băng thông mạng để chạy lệnh npm install sau đó. Đây quả thực là cơn "ác mộng" trong mùa đứt cáp này.

Để tận dụng được cơ chế layer caching, hãy sửa và sắp xếp lại thứ tự layer một cách hợp lý hơn như sau.

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

Có thể thấy nếu package hoặc package-lock.json thay đổi, npm ci sẽ được thực hiện. Còn nếu không thì 2 lệnh trên có thời gian thực hiện gần như là ngay lập tức.

Tổng kết

Có một vài cách để tăng tốc độ build docker image cũng như làm giảm kích thước của docker image. Trong số đó là tận dụng cơ chế layer caching mà docker cung cấp để sắp xếp thứ tự các layer sao cho đạt được ít nhất sự thay đổi, từ đó tăng tốc độ xây dựng các hình ảnh của bạn.

Tham khảo:

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (0)