Có một loạt các kỹ thuật liên quan, không có giải pháp duy nhất. Bạn có thể muốn thực hiện một số điều sau đây:
Đầu tiên, tối ưu hóa các lớp hình ảnh của bạn để tái sử dụng. Đặt các bước thay đổi thường xuyên sau này trong Dockerfile để tăng cơ hội các lớp đầu được lưu vào bộ đệm từ các bản dựng trước. Một lớp được sử dụng lại sẽ hiển thị nhiều không gian đĩa hơn trong một docker image ls
, nhưng nếu bạn kiểm tra hệ thống tập tin cơ bản, chỉ có một bản sao của mỗi lớp được lưu trữ trên đĩa. Điều đó có nghĩa là 3 hình ảnh mỗi tệp 2 GB, nhưng chỉ có 50 MB khác nhau trong một vài lớp cuối cùng, sẽ chỉ chiếm 2,1 GB dung lượng đĩa, mặc dù danh sách cho thấy họ đang sử dụng 6 GB kể từ khi bạn đếm gấp đôi mỗi lớp được sử dụng lại.
Tái sử dụng lớp là lý do tại sao bạn thấy hình ảnh với các phụ thuộc xây dựng thay đổi không thường xuyên cài đặt những cái đầu tiên trước khi sao chép mã. Xem bất kỳ ví dụ python có mẫu như:
FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]
Chọn một hình ảnh cơ sở tối thiểu. Đây là lý do tại sao bạn thấy mọi người đi từ ubuntu
đến debian:slim
(các biến thể mỏng có kích thước nhỏ, vận chuyển với các công cụ ít hơn), hoặc thậm chí alpine
. Điều này làm giảm kích thước điểm bắt đầu của bạn và rất hữu ích nếu bạn liên tục kéo các phiên bản mới của hình ảnh cơ sở. Tuy nhiên, nếu hình ảnh cơ sở của bạn hiếm khi thay đổi, việc sử dụng lại lớp sẽ loại bỏ phần lớn lợi thế của hình ảnh cơ sở tối thiểu.
Hình ảnh cơ sở nhỏ nhất bạn có thể chọn là scratch
, không có gì, không có shell hoặc thư viện và chỉ hữu ích với các nhị phân được biên dịch tĩnh. Mặt khác, chọn một hình ảnh cơ bản bao gồm các công cụ bạn cần mà không có nhiều công cụ bạn không cần.
Tiếp theo, bất kỳ bước nào thay đổi hoặc xóa tệp nên được kết hợp với các bước trước đó tạo tệp đó. Mặt khác, hệ thống tệp lớp, sử dụng sao chép trên ghi ngay cả trên những thứ như thay đổi quyền truy cập tệp, sẽ có tệp gốc ở lớp trước và kích thước hình ảnh sẽ không co lại khi bạn xóa tệp. Đây là lý do tại sao các rm
lệnh của bạn không có ảnh hưởng đến không gian đĩa kết quả. Thay vào đó, bạn có thể xâu chuỗi các lệnh, như:
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
&& ... \
&& apt-get purge -y wget \
&& rm -r a-build-dir \
&& apt-get purge -y a-package
Lưu ý rằng việc lạm dụng chuỗi lệnh có thể làm chậm các bản dựng của bạn vì bạn cần cài đặt lại bộ công cụ tương tự bất cứ khi nào một điều kiện tiên quyết thay đổi (ví dụ: mã được kéo bằng wget). Xem nhiều giai đoạn dưới đây để thay thế tốt hơn.
Bất kỳ tệp nào bạn tạo mà bạn không cần trong ảnh kết quả sẽ bị xóa, trong bước tạo tệp đó. Điều này bao gồm bộ đệm gói, nhật ký, trang man, v.v. trên máy chủ của bạn) hoặc bạn có thể xây dựng hình ảnh docker của mình mà không cần cắt các container trung gian và sau đó xem diff với:
# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name .
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a
# examine any of those containers
docker container diff ${container_id}
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune
Với mỗi người trong số những container trung gian, các diff sẽ hiển thị những tập tin được thêm vào, thay đổi, hoặc xóa trong bước đó (đây là những chỉ báo bằng một A
, C
hoặc D
trước mỗi tên tập tin). Điều khác biệt đang hiển thị là hệ thống tập tin đọc / ghi cụ thể của bộ chứa, đây là bất kỳ tập tin nào được bộ chứa thay đổi từ trạng thái hình ảnh bằng cách sử dụng bản sao ghi.
Cách tốt nhất để giảm kích thước hình ảnh là loại bỏ mọi thành phần không cần thiết, như trình biên dịch, khỏi hình ảnh vận chuyển của bạn. Do đó, các bản dựng nhiều giai đoạn cho phép bạn biên dịch trong một giai đoạn và sau đó chỉ sao chép các tạo phẩm kết quả từ giai đoạn xây dựng sang hình ảnh thời gian chạy chỉ có mức tối thiểu cần thiết để chạy ứng dụng. Điều này tránh sự cần thiết phải tối ưu hóa bất kỳ bước xây dựng nào vì chúng không được gửi cùng với hình ảnh kết quả.
FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
RUN ... # perform any download/compile steps
FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]
Nhiều giai đoạn là lý tưởng với các nhị phân được biên dịch tĩnh mà bạn có thể chạy bằng đầu như hình ảnh cơ sở của mình hoặc chuyển từ môi trường biên dịch như JDK sang thời gian chạy như JRE. Đây là cách dễ nhất để giảm đáng kể kích thước hình ảnh của bạn trong khi vẫn có các bản dựng nhanh. Bạn vẫn có thể thực hiện chuỗi các bước trong giai đoạn phát hành nếu bạn có các bước thay đổi hoặc xóa các tệp được tạo ở các bước trước, nhưng đối với hầu hết các phần, COPY
giai đoạn khác tách biệt giai đoạn phát hành với bất kỳ sự phình to nào trong giai đoạn xây dựng trước đó.
Lưu ý, tôi không khuyên bạn nên xóa hình ảnh vì điều này làm giảm kích thước của một hình ảnh với chi phí loại bỏ việc tái sử dụng lớp. Điều đó có nghĩa là các bản dựng tương lai của cùng một hình ảnh sẽ yêu cầu nhiều lưu lượng đĩa và mạng hơn để gửi các bản cập nhật. Để quay lại ví dụ đầu tiên, squash có thể giảm hình ảnh của bạn từ 2 GB xuống còn 1 GB, nhưng không phải 3 hình ảnh có thể chiếm 3 GB thay vì 2,1 GB.
2.37
so với1.47 GB