Зображення докера - це фактично пов'язаний список шарів файлової системи. Кожна інструкція в Dockerfile створює рівень файлової системи, який описує відмінності у файловій системі до та після виконання відповідної інструкції. docker inspect
Субкоманди може бути використана на Docker зображення , щоб розкрити його природу буття пов'язаного списку файлових шарів.
Кількість шарів, використаних у зображенні, є важливою
- під час натискання або перетягування зображень, оскільки це впливає на кількість одночасних завантажень або завантажень, що виникають.
- при запуску контейнера, так як шари поєднуються разом для отримання файлової системи, що використовується в контейнері; чим більше шарів задіяно, тим гірша продуктивність, але це впливає на різні файлові системи.
Це має кілька наслідків для того, як слід будувати зображення. Перша і найважливіша порада, яку я можу дати:
Порада № 1 Переконайтесь, що етапи збирання, в якому бере участь ваш вихідний код, надходять якнайпізніше в Dockerfile і не прив’язуються до попередніх команд за допомогою a &&
або a ;
.
Причиною цього є те, що всі попередні кроки будуть кешовані і відповідні шари не потрібно буде завантажувати знову і знову. Це означає, що швидше збирає та швидше випускає, що, мабуть, те, що ви хочете. Цікаво, що оптимально використовувати кеш докерів на диво важко.
Моя друга порада менш важлива, але я вважаю це дуже корисним з точки зору обслуговування:
Порада № 2 Не пишіть складні команди в Dockerfile, а скоріше використовуйте сценарії, які потрібно скопіювати та виконати.
Dockerfile слідуючи ця рада буде виглядати
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
COPY install_pacakges.sh /root/
RUN sh -x /root/install_packages.sh
і так далі. Порада зв'язати кілька команд з &&
лише обмеженою сферою застосування. Набагато простіше писати зі сценаріями, де можна використовувати функції тощо, щоб уникнути надмірності або для цілей документації.
Люди, які цікавляться попередніми процесорами та готові уникати невеликих накладних витрат, спричинених COPY
кроками, і насправді створюють Dockerfile під час польоту, де
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
послідовності замінюються на
RUN base64 --decode … | sh -x
де …
- кодована версія base64 apt_setup.sh
.
Моя третя порада - для людей, які хочуть обмежити розмір та кількість шарів при можливій вартості довшого нарощування.
Порада №3 Використовуйте with
-idiom, щоб уникнути файлів, що знаходяться в посередницьких шарах, але не в отриманій файловій системі.
Файл, доданий якоюсь докерською інструкцією та видалений пізнішою інструкцією, відсутній у отриманій файловій системі, але він згадується два рази в шарах докера, що становить зображення докера в процесі побудови. Один раз, із назвою та повним вмістом у шарі, що є результатом додавання інструкції, та один раз як повідомлення про видалення в шарі, що виникає внаслідок видалення інструкції.
Наприклад, припустимо, що нам тимчасово потрібен компілятор C та деяке зображення та розглянемо
# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc
(Більш реалістичним прикладом може бути побудова деякого програмного забезпечення разом із компілятором, а не просто підтвердження його присутності --version
прапором.)
Фрагмент Dockerfile створює три шари, перший містить повний набір gcc, так що навіть якщо його немає в кінцевій файловій системі, відповідні дані все ще є частиною зображення таким же чином, і їх потрібно завантажувати, завантажувати та розпаковувати кожного разу, коли остаточне зображення.
with
-Idiom є поширеною формою в функціональному програмуванні , щоб ізолювати власність ресурсів і ресурсів вивільнення з логіки його використання. Легко перенести цю ідіому в сценарій оболонки, і ми можемо перефразувати попередні команди як наступний сценарій, який буде використовуватися COPY & RUN
як у Раді №2.
# with_c_compiler SIMPLE-COMMAND
# Execute SIMPLE-COMMAND in a sub-shell with gcc being available.
with_c_compiler()
(
set -e
apt-get install -y gcc
"$@"
trap 'apt-get --purge autoremove -y gcc' EXIT
)
with_c_compiler\
gcc --version
Складні команди можна перетворити на функцію, щоб їх можна було подати with_c_compiler
. Можливо також ланцюжок дзвінків кількох with_whatever
функцій, але, можливо, не дуже бажано. (Використовуючи більш езотеричні особливості оболонки, звичайно, можна зробити with_c_compiler
прийняття складних команд, але в усіх аспектах бажано вбудувати ці складні команди у функції.)
Якщо ми хочемо ігнорувати пораду №2, то отриманий фрагмент Dockerfile буде
RUN apt-get install -y gcc\
&& gcc --version\
&& apt-get --purge autoremove -y gcc
що не так просто читати та підтримувати через ом’яку. Подивіться, як варіант сценарію оболонки робить акцент на важливій частині, gcc --version
тоді як ланцюговий &&
варіант закопує цю частину посеред шуму.