Kiến Thức Linux Docker

Tối ưu image docker

dockertwo 0

Mục Lục

Khi chúng ta build 1 image docker,  dung lượng của image ảnh hưởng khá nhiều đến việc vận hành. Đặc biệt là khi chúng ta muốn scale service với Kubernetes ( k8s ), Docker Swarm, … Image càng nhỏ gọn thì deploy và scale càng nhanh.

Vậy làm sao để tối ưu image docker
Để làm được điều này, chúng ta cần làm những việc sau đây:

1/ Thay đổi base image

How to create docker base image for cents7,debian,ubuntu,redhat,alpine

Đầu tiên, chúng ta cần chọn 1 base image có dung lượng nhỏ, điển hình là images “alpine”.  Đây là những base image có kích thước nhỏ gọn, tối ưu cho việc lưu trữ mà vẫn đủ điều kiện để service chạy mượt mà.

ví dụ:
Thay vì sử dụng FROM node:10, chúng ta có thể chuyển qua sử dụng FROM node:10-alpine.
Các image dựng trên alpine có dung lượng rất nhẹ, với nodejs là giảm từ 900MB của bản mặc định xuống chỉ còn 70MB của alpine.

2/ Tận dụng layer caching

caching

Layer caching là một tính năng rất quan trọng giúp giảm thời gian của quá trình build bằng cách tận dụng những layer đã được build từ lần trước đó . Để có thể tận dụng tối đa tính năng này, ta cần sắp xếp lại và tách lệnh build sao cho phần lệnh ít thay đổi sẽ ở trên, phần thay đổi thường xuyên sẽ ở dưới. Để hiểu rõ hơn về việc này, chúng ta cần xét ví dụ dưới đây.

TRƯỜNG HỢP 1 

1 FROM alpine
2 WORKDIR /app
3 RUN apt-get update
4 RUN apt-get install -y git
5 RUN yarn global add node-gyp
5 ADD . /app
6 RUN yarn --pure-lockfile
7 RUN yarn build
8 EXPOSE 3000

TRƯỜNG HỢP 2

10 FROM alpine
11 EXPOSE 3000
12 WORKDIR /app
13 RUN apt-get update
14 RUN apt-get install -y git
15 RUN yarn global add node-gyp
16 ADD package.json yarn.lock /app/
17 RUN yarn --pure-lockfile
18 ADD . /app
19 RUN yarn build

Như bạn thấy, 2 trường hợp mà chúng tôi đã minh họa phía trên, trường hợp 2 đã sắp xếp lại các câu lệnh sao cho, những câu lệnh nào thường xuyên thay đổi thì sẽ được để phía dưới, ít thay thay đổi được xếp lên trên. Vì sao lại vậy ?.

Như chúng ta đã biết, mỗi câu lệnh chúng ta build sẽ tương ứng với 1 lớp ( layer), khi chúng ta build lại image, docker sẽ kiểm tra xem đã có những lớp đã được build trước hay chưa, nếu có thì chúng sẽ tận dụng lại những lớp này mà không cần phải build lại, điều này sẽ tiết kiệm được thời gian build. Tuy nhiên, những lớp phía sau từ lớp được thay đổi sẽ phải build lại.

ví dụ, ở trường hợp thứ 2, chúng ta thay đổi câu lệnh tại dòng số 14 , tôi bổ sung thêm gói cài đặt “vim” :
điều này nghĩa là từ lớp 10 đến 13, docker sẽ dùng cache, không cần build lại. Tuy nhiên, từ lớp 14 đến 19, docker sẽ build lại mới. Đó là lý do vì sao chúng ta cần phải sắp xếp hợp lý thứ tự các câu lênh.

10 FROM alpine
11 EXPOSE 3000
12 WORKDIR /app
13 RUN apt-get update
14 RUN apt-get install -y git vim
15 RUN yarn global add node-gyp
16 ADD package.json yarn.lock /app/
17 RUN yarn --pure-lockfile
18 ADD . /app
19 RUN yarn build

3/ Giảm bớt số lượng layer

Như đã đề cập bên trên, Docker được build dựa trên các lớp layer xếp chồng lên nhau. Nếu  có càng nhiều lớp thì image docker sẽ càng có dung lượng lớn, nặng nề. Do đó, chúng ta tận dụng càng ít layer càng lớp.
xét ví dụ sau để hiểu rõ hơn:

FROM alpine
ADD . /app
ADD package.json yarn.lock /app/
ADD entrypoint.sh /entrypoint.sh
WORKDIR /app
RUN apt-get update
RUN apt-get install -y git
RUN yarn global add node-gyp
RUN yarn --pure-lockfile
RUN yarn build
EXPOSE 3000
CMD ["/entrypoint.sh]

Thay vì sử dụng quá nhiều dòng lệnh lặp lại “RUN”, có tới 5 dòng lệnh “RUN” tương ứng với 5 lớp, quá nhiều. Chúng ta sẽ gom lại thành 1 dòng “RUN” như sau.

FROM alpine
ADD . /app
ADD package.json yarn.lock /app/
ADD entrypoint.sh /entrypoint.sh
WORKDIR /app
RUN apt-get update -y \
&& apt-get install -y git \
&& yarn global add node-gyp \
&& yarn --pure-lockfile \
&& yarn build
EXPOSE 3000
CMD ["/entrypoint.sh]

Việc này sẽ làm giảm đáng kể dung lượng images.

4/ Sử dụng multi-stage trong lúc build

Multi-stage build được giới thiệu từ docker v17.05, đây là tính năng khá hữu ích, nó sẽ bỏ hết những thứ linh tinh trong quá trình chúng ta build images, ví dụ đơn giản thế này, khi chúng ta cần build một service từ source, chúng ta tất nhiên cần phải cài đặt những package cần thiết, nhưng vấn đề là images docker của chúng ta không cần phải có những package đó, chúng ta chỉ muốn giữ lại bộ source sao khi đã build xong, còn mấy package linh tinh cần bỏ hết. Chính vì vậy, multi-stage ra đời để giải quyết vấn đề này. Cùng xét ví dụ sau để hiểu rõ hơn.

FROM node:10-alpine AS builder
WORKDIR /app
RUN apk --no-cache add \
g++ make python git \
&& yarn global add node-gyp \
&& rm -rf /var/cache/apk/*
ADD package.json yarn.lock /app/
RUN yarn --pure-lockfile
# Runtime image from here

FROM node:10-alpine
EXPOSE 3000
WORKDIR /app
# Copy node_modules from builder image
COPY --from=builder /app .
ADD . /app
RUN yarn build
CMD ["yarn", "docker:start"]

Trong Dockerfile phía trên, chúng tôi đã tách việc build docker thành 2 phần, phần 1 đóng vai trò là builder, phần 2 mới là service cuối cùng mà chúng ta cần. Kích thước của Images Docker sẽ  là thành phần được build cuối cùng.

Kết luận

để tối ưu image docker, chúng ta cần làm những bước sau:

  • Chọn base image có kích thước nhỏ gọn, alpine là điển hình
  • Sắp xếp Dockerfile để tận dụng layer caching giúp giảm thời gian build
  • Giảm số lượng Layer bằng cách gom lại các câu lệnh “RUN”, “ADD”, “COPY”.
  • Sử dụng multi-stage build để giảm dung lượng image

 

        Người Viết:
   congdonglinux.com

 

 

 

 

close
logo 1024

Đăng Ký Liền Tay

Nhận Ngay Bài Viết

We don’t spam! Read our privacy policy for more info.

Add Comment

Click here to post a comment