Глава 3. Тонкая настройка нашего образа Rail
Содержание
В предыдущей главе мы рассмотрели множество вопросов. Мы рассмотрели свой первый Dockerfile
,
который мы применили для создания собственного образа, специально изготавливаемого для запуска нашего прикладного
приложения Rails.
Однако, как вы могли запомнить, мы сказали что этот Dockerfile
был
"достаточно хорош", но "не прекрасен"
(Определение нашего первого пользовательского образа).
Правда состоит в том, что для упрощения мы срезали пару углов. Теперь, когда у вас имеются за поясом некоторые основы
Docker, мы можем вернуться к решению этих проблем.
К окончанию данной главы мы будем иметь свой Dockerfile
аккуратно заправленным
и готовым для нашего глубокого погружения в окончательные фрагменты нашей головоломной разработки - Docker Compose -
но я забегаю вперёд.
Итак, одевайте некий комбинезон, берите в руки надёжный гаечный ключ и много аэрозольной полировки - в метафорическом смысле именно это вам и понадобится.
Когда мы запускали свой сервер Rails при помощи этой команды:
$ docker run -p 3000:3000 a1df0eddba18 \
bin/rails s -b 0.0.0.0
мы ссылались на свой персональный образ по его идентификатору, a1df0eddba18
(у вас должно быть нечто иное). Не существует способа как это запомнить. В точности как вы не будете в здравом уме
ссылаться на некую ветвь Git, применяющую SHA-1 хэширование своей последней фиксации, то же самое справедливо и для
образов. Вместо этого мы даём своим образам дружественные людям названия, выполняя их
маркировку (tagging). Допустим, мы желаем назвать свой образ
railsapp
. Мы можем сделать это при помощи:
$ docker tag a1df0eddba18 railsapp
что инструктирует, "Пометьте мой образ с идентификатором 'a1df0eddba18
'
как эrailsapp
'". Чтобы проверить что это сработало, давайте перечислим свои
образы с помощью:
$ docker images
Наш вывод подтверждает, что имеющееся название этого образа (также именуемое как
репозиторий - repository) было установлено в
railsapp
:
REPOSITORY TAG IMAGE ID CREATED SIZE
railsapp latest a1df0eddba18 8 minutes ago 1.01GB
...
Обратите внимание, что поле "tag" перечисляется как latest
. Это
происходит по той причине, что команда docker tag
на самом деле по некоторой
ссылке образа (image reference), которая составляется из двух частей: самого
названия (repo) образа и не обязательного тега:
<image_name>[:<tag>]
Вы можете установить значением тега любую допустимую строку, составляемую из букв, цифр, подчёркиваний, точек и
дефисов (с некоторыми оговорками). Если ничего этого не предоставлено, тегом по умолчанию будет выступать
latest
.
К несчатью понятие tag
слишком перегружено. Я предлагаю представлять сеье команду
docker tag
как помечающую (tagging) сразу
обоими, как названием образа/ репозитория (в нашем случае railsapp
),
так и
неким тегом (в нашем случае значением по умолчанию,
latest
).
Мы можем предоставлять некому образу столько различных пометок, сколько пожелаем. Например, давайте также зададим
своему образу номер его версии 1.0
, выполнив:
$ docker tag railsapp railsapp:1.0
Здесь мы ссылаемся на свой образ как railsapp
, так как мы уже пометили его
этим названием (railsapp:latest
также сработало бы). Наш новый тег
railsapp:1.0
создаёт соответствующее название образа
railsapp
и версию 1.0
. Быстрое перечисление
показывает как это работает:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
railsapp 1.0 a1df0eddba18 8 minutes ago 1.01GB
railsapp latest a1df0eddba18 8 minutes ago 1.01GB
...
Хотя имеются две различные строки, которые отображают наш образ railsapp
и как
latest
, и как 1.0
, основное поле
"IMAGE ID" подтверждает что оба они по сути один и тот же образ.
Вместо того чтобы помечать образы после их построения, мы можем осуществлять это при самом построении такого образа
при помощи параметра -t
. Множество пометок может быть предоставлено определением
дополнительных параметров -t
, тем самым мы могли бы достичь того же самого результата
что и две наши предыдущие команды docker tag
если бы построили свой образ
при помощи команды:
$ docker build -t railsapp -t railsapp:1.0 .
Получив название своего образа мы теперь способны запускать свой сервере Rails применяя название образа подобно такому:
$ docker run -p 3000:3000 railsapp \
bin/rails s -b 0.0.0.0
Ах. Намного лучше.
Запуск конкретной версии некого образа в точности тот что мы и ожидали увидеть: при помощи той же самой нотации
с двоеточием, которую мы применяли ранее. Например, для определения в явном виде номера версии
1.0
для нашего образа мы бы осуществили запуск:
$ docker run -p 3000:3000 railsapp:1.0 \
bin/rails s -b 0.0.0.0
На данный момент, всякий раз когда мы желаемм запустить некий сервер Rails в контейнере, нам приходится в явном виде
определять соответствующую команду bin/rails s -b 0.0.0.0
как часть своей
команды docker run
:
$ docker run -p 3000:3000 railsapp \
bin/rails s -b 0.0.0.0
Это полная стыдоба, потому как самая основная цель нашего персонального образа состоит в том чтобы запускать некий сервер Rails. Было бы намного лучше если бы мы могли встроить своё знание того как запускать конкретный сервер Rails в сам имеющийся образ.
Мы можем сделать это добавляя некую новую инструкцию в свойDockerfile
.
Именно инструкция CMD
, произносимая как "команда", определяет ту
команду по умолчанию, которую надлежит исполнить при запуске некого контейнера
из данного образа. Давайте воспользуемся ею в своём Dockerfile
для запуска
требуемого сервера Rails по умолчанию:
FROM ruby:2.6
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY . /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
» CMD ["bin/rails", "s", "-b", "0.0.0.0"]
рассматривая эту вновь добавленную строку вы можете обратить внимание на наличие странной нотации массива в определении данной команды. Эта форма - именуемая как исполнительная (Exec) форма - необходима для того, чтобы наш сервер Rails запускался как самый первый процесс в этом контейнере (PID 1) и правильно получал бы сигналы Unix, такие как сигнал прекращения. Это рекомендуемая и наиболее часто применяемая форма.
Другая форма данной инструкции CMD
, которая применяется реже, опускает
такую нотацию массива в пользу непосредственной записи данной команды:
CMD bin/rails s -b 0.0.0.0
Она именуется формой оболочки (shell), потому что Docker исполняет такую
команду через некую оболочку команд, с префиксом
/bin/sh -c
- поэтому в нашем случае он запустит
bin/rails s -b 0.0.0.0
. Основная проблема состоит в том, что именно
/bin/sh -c
вместо самого сервера Rails является самым первым процессом внутри
данного контейнера; следовательно /bin/sh -c
не передаст сигналы в свой
подпроцесс, а это может вызывать проблемы при попытке прекращения данного сервера. Говоря в целом, вам следует вовсе
избегать такой формы запуска.
Ладно, давайте построим свой образ с помощью новой
инструкции CMD
, помня про пометку своей версии railsapp
в качестве latest
:
$ docker build -t railsapp .
Sending build context to Docker daemon 138.8kB
...
Successfully built f87ad761cd0f
Successfully tagged railsapp:latest
При помощи своего вновь построенного образа мы способны запустить этот новый сервер Rails - опуская
bin/rails s -b 0.0.0.0
- просто как:
$ docker run -p 3000:3000 railsapp
Важно отметить, что наша инструкция CMD
просто предоставляется как некая команда
по умолчанию - вы можете определить некую другую при вызове своей команды
docker run
. Например, чтобы перечислить свои задачи Rake, мы бы выполнили:
$ docker run --rm railsapp bin/rails -T
Обратите внимание, что мы применяем --rm
для удаления этого контейнера после его исполнения.
Мы применяем это здесь, а не когда запускаем сам сервер Rails, в то время как контейнер для запуска сервера Rails
можно применять повторно.
Вы должно быть помните, что имеется различие в CLI Docker, который мы применяем для запуска команд, а также что имеющийся демон Docker выполняет основную часть реальной работы (как мы это уже видели в своих схемах архитектуры для Схемы архитектуры Dockere для Linux и Схемы архитектуры Dockere для Mac/Windows. Построение образа ничем не отличается - именно наш демон Docker в реальности выполняет построение необходимого образа.
Как это работает на практике?
Когда запускается команда docker build
, имеющийся инструментарий CLI
получает все те файлы, которые определены в нашем каталоге сборки - которые все вместе именуются
контекстом сборки (build context) - и отправляет их своему демону Docker.
Затем этот демон имеет возможность обработать соответствующий Dockerfile
и позаботиться обо всех присутствующих там инструкциях для выработки необходимого образа.
Нам требуется ограничивать какие файлы отправлять в качестве части данного контекста сборки, так как отправка большего числа файлов замедляет наше построение (что в особенности верно в отношении Docker для Mac или Windows, когда демон запущен в неком виртуальном хосте). К тому же мы можем пожелать предотвращать от включения в свой образ чувствительных файлов, которые содержат секретные коды - в особенности если вы планируете разделять этот образ в общем доступе.
Для исключения файлов и каталогов от их отправки в качестве части такого контекста сборки, мы перечисляем их в неком файле
.dockerignore
в своём каталоге сборки. Этот файл .dockerignore
работает на той же основе, что и файл .gitignore
, с которым вы скорее всего знакомы,
хотя сам синтаксис их шаблонов соответствия слегка разнится.
Давайте создадим некий базовый файл .dockerignore
для своего проекта:
1: # Git
- .git
- .gitignore
-
5: # Logs
- log/*
-
- # Temp files
- tmp/*
10:
- # Editor temp files
- *.swp
- *.swo
Мы исключаем свой каталог .git
(строка 2), который содержит всю историю Git и
все настройки, так как наш образ нуждается только в самых последних версиях этих файлов. За исключением одной мелочи, пока
мы этим занимаемся, мы также исключили сам файл .gitignore
(строка 3).
Аналогично мы иключаем все журналы (строка 6) или временные файлы (9), поскольку они вырабатываются и с целью безопасности
их можно игнорировать. Наконец, я исключаю временные файлы Vim .swp
и
.swo
(строки 12 и 13) - не стесняйте себя делать то же самое и для своего
любимого редактора.
Этот файл .dockerignore
является достойной отправной точкой, но вы действительно
можете отправиться дальше в лес и игнорироовать все кэшируемые или вырабатываемые файлы.
Давайте повторно построим свой образ вооружившись данным файлом .dockerignore
.
$ docker build -t railsapp .
Sending build context to Docker daemon 102.9kB
...
Successfully built 577a1a5a2d2c
Successfully tagged railsapp:latest
В полученном выводе мы получаем отчёт о размере контекста сборки - 102.9 кБ - что меньще чем ранее до добавления вашего
.dockerignore
Docker (138.8 кБ). Такое сбережение увеличивается со временем, в
особенности по мере роста истории Git.
В течении разработки мы достточно часто перестраиваем свой образ, либо устанавливая новые gem
(bundle install
является одним из необходимых этапов нашего
Dockerfile
), либо обновляя свои зависимости, такие как Node.js.
В точности также как комплект быстрых проверок помогает сокращать цикл с обратной связью, также важно м максимально
возможно ускорять сборку наших образов. Один из способов которым Docker помогает нам это кэширование каждого нашего
шага при выполнении нами сборки, что означает что нам требуется выполнять повтроное построение только с самой
первой инструкции Dockerfile
в которой произошло изменение. Изменением может
быть либо буквалбное удаление или модификация соответствующей инструкции Dockerfile
,
либо оно может быть связано с изменениями в файловой системе, как мы это вскорости обнаружим.
Поскольку с нашей последней сборки в нашем Dockerfile
или файлах не было
никаких изменений, будет чрезвычайно быстрым теперь построить новый образ. Все шаги уже были отстроены и кэшированы,
следовательно Docker будет вынужден сделать это очень быстро.
Давайте пересоберём свой образ прямо сейчас:
$ docker build -t railsapp .
Sending build context to Docker daemon 102.9kB
Step 1/7 : FROM ruby:2.6
---> f28a9e1d0449
Step 2/7 : RUN apt-get update -yqq
---> Using cache
---> 761da319d69a
Step 3/7 : RUN apt-get install -yqq --no-install-recommends nodejs
---> Using cache
---> 145b025f550c
Step 4/7 : COPY . /usr/src/app/
---> Using cache
---> 045a92afdc82
Step 5/7 : WORKDIR /usr/src/app
---> Using cache
---> 1d89cb7f0720
Step 6/7 : RUN bundle install
---> Using cache
---> 81ad2d531548
Step 7/7 : CMD ["bin/rails", "s", "-b", "0.0.0.0"]
---> Using cache
---> 577a1a5a2d2c
Successfully built 577a1a5a2d2c
Successfully tagged railsapp:latest
Этот образ должен быть собран очень быстро. Если вы взглянете на полученный вывод, вы увидите, что все шаги (отличающиеся от
инструкции FROM
) в точности сообщают Using cache
.
Это указывает на то, что Docker не требуется создавать некий новый образ для каждого шага: он просто повторно применяет
некий кэшированный с предыдущей сборки промежуточный образ.
Значение кэширвание для некого определённого шага является недействительным при изменении вами инструкции своего
Dockerfile
на нечто, что не было построено ранее. Кроме того, инструкции
COPY
могут иметь свои несоответствия кэширования если копируемые файлы
были изменены с момента соответствующего этапа последнего построения. Такое сопоставление выполняется имеющимся демоном
Docker на основе файлов в его контексте сборки - следовательно игнорирование ненужных файлов из вашего файла
.dockerignore
также может предотвращать недействительность кэширования.
Поскольку некий Dockerfile
является последовательным, имея для каждой инструкции
сборку для своего предыдущего (промежуточного) образа, в случае когда ваш кэш приходит в несоответствие на одном из
этапов, Docker обязан повторно выполнять сборку всех последующих этапов.
Следовательно наибольший вред причиняют несоответствия на более ранних шагах, поскольку приходится выполнять перестроение
большего числа этапов.
Понимание данного факта полезно для обеспечения быстрой сборки наших образов по мере их разработки без получения ненужных обращений (hits) из- за аннулирований в имеющемся кэше сборки образа.
На самом деле у нашего Dockerfile
уже имеется небольшая проблема с тем как
работает само кэширование...
На данный момент наш Dockerfile
имеет две такие строки:
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
Хотя это и работает, имеется некая скрытая проблем отслеживания. Допустим, мы переходим к некому более позднему этапу и понимаем что
нам требуется установить некий дополнительный пакет - к примеру, редактор Vim. Мы добавляем соответствующий пакет
vim
в свою инструкцию apt-get update RUN
,
разрушая имеющийся кэш и приводя к возврату в правке этой инструкции:
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs vim
Однако сама инструкция apt-get update
для RUN
остаётся
без изменений и будут использованы все имеющиеся подробности кэшированного репозитория. Вместо того чтобы получить текущую,
самую последнюю версию своего нового только что добавленного пакета, мы полоучим нечто, что было самой последней версией
на тот момент, когда мы строили свой образ в последний раз. Такое поведение почти
никогда не является тем что нам требуется.
По этой причине рекомендуется
всегда сочетать ваши команды apt-get update
и apt-get install
в единую инструкцию RUN
подобную следующей:
RUN apt-get update -yqq && \
apt-get install -yqq --no-install-recommends nodejs vim
Это обеспечит гарантию того что при всяком изменении устанавливаемых вами пакетов вы также получаете в то же самое время и самую последнюю информацию информацию о репозитории.
Наконец, хорошим практическим приёмом является форматировать вашу команду
apt-get install
следующим образом:
RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
nodejs \
vim
Применение одного пакета в строке и соблюдение алфавитного порядка делает более простым просмотр устанавливаемых пакетов и выявления того какие из них следует изменять если приходится устанавливать множество пакетов.
Давайте теперь исправим эту проблему в своём Dockerfile
. В настоящий момент нам
не требуется устанавливать Vim, следовательно наши две инструкции RUN
для
apt-get update
и apt-get install
превращаются в:
RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
nodejs
Давайте повторно соберём свой образ чтобы включить это изменение:
$ docker build -t railsapp .
Sending build context to Docker daemon 102.9kB
Step 1/6 : FROM ruby:2.6
---> f28a9e1d0449
...
Successfully built 621ceaca3298
Successfully tagged railsapp:latest
Допустим, что мы пожелаем внести изменения в свой файл README.md
и замените
имеющееся установленное по умолчанию определение версии Rails на следующее:
# README
This is a sample Rails application from Docker for Rails Developers (PragProg).
It was generated using Docker without Ruby installed on the local machine.
We're using the app to discover the wonderful world of Rails with Docker.
Это образец приложения Rails из книги Docker for Rails Developers (PragProg).
Он был сгенерирован при помощи Docker без установленного в вашей локальной машине Ruby.
Мы применяем данное прикладное приложение для исследования прекрасного мира Rails с использованием Docker.
Давайте попробуем что- нибудь. Что произойдёт если мы повторно соберём свой образ:
$ docker build -t railsapp .
Sending build context to Docker daemon 102.9kB
Step 1/6 : FROM ruby:2.6
---> f28a9e1d0449
Step 2/6 : RUN apt-get update -yqq && apt-get install -yqq --no-install-
recommends nodejs
---> Using cache
---> 29c3dee2b8c7
Step 3/6 : COPY . /usr/src/app/
---> fff98079f6ac
Step 4/6 : WORKDIR /usr/src/app
---> Running in 3e36b19fecbf
Removing intermediate container 3e36b19fecbf
---> 34e46dae43ab
Step 5/6 : RUN bundle install
---> Running in f4528be7eb2b
...
Bundle complete! 15 Gemfile dependencies, 68 gems now installed.
Bundled gems are installed into `/usr/local/bundle`
...
Removing intermediate container f4528be7eb2b
---> 5965a3004093
Step 6/6 : CMD ["bin/rails", "s", "-b", "0.0.0.0"]
---> Running in fe59ed9392a7
Removing intermediate container fe59ed9392a7
---> 1fbb2af53579
Successfully built 1fbb2af53579
Successfully tagged railsapp:latest
Ух ты, это потребовало много времени. Основной причиной этой медленности было то, что все наши gems собирались с нуля,
и всё это произошло потому, что мы изменили свой файл README.md
- что произошло?
Если вы рассмотрите полученный вывод, вы обнаружите, что все шаги с 1 по 3 сообщили
Using cache
. Docker не приходится собирать по новой эти уровни, поскольку он
сопоставил инструкции вашего Dockerfile
с кэшированными промежуточными уровнями
для этих шагов и увидел их неизменность.
Однако это не так для шага 4 (COPY . /usr/src/app
) - этот шаг не использует
имеющийся кэш. Хотя сама инструкция Dockerfile
осталось той же самой,
поскольку данная инструкция является инструкцией COPY
, Docker выполняет проверку
всех подлежащих копированию файлов (за исключением файлов .dockerignore
) и
сравнивает их с теми, что копировались ранее. Он понимает, что README.md
был
изменён, следовательно он знает о необходимости повторной сборки на данном шаге.
Нельзя обойти вниманием тот факт, что если файлы изменены, необходимо создать некий новый образ, содержащий эти файлы.
Однако в данном случае, к сожалению, наше изменение README.md
вызывает
повторное исполнение bundle install
. Это одновременно и длительно, и совершенно
не является необходимым: наше изменение README.md
не оказало воздействия на
зависимости имеющихся gem. Единственная причина, по которой он запускается состоит в том, был изменён предыдущий шаг в
нашем Dockerfile
.
Давайте посмотрим имеется ли у нас нечто для решения этой задачи.
Оказывается, существует некий действенный способ предотвращения изменений в несвязанных файлах, разрушающих наш кэш и приводящих к повторной сборке всех наших gems с нуля. Фокус состоит в том, чтобы обособленно копировать файлы, которые приводят к необходимости повторной сборки наших gem от тех, которые не вызывают этого.
Давайте обновим свой Dockerfile
чтобы он делал это:
1: FROM ruby:2.6
-
- RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
- nodejs
5:
- COPY Gemfile* /usr/src/app/
- WORKDIR /usr/src/app
- RUN bundle install
-
10: COPY . /usr/src/app/
-
- CMD ["bin/rails", "s", "-b", "0.0.0.0"]
Первые три инструкции остаются прежними, однако строка 6 новая. Она копирует наши Gemfile
и Gemfile.lock
в наш образ до всего остального
нашего кода.
COPY Gemfile* /usr/src/app/
Это создаёт некий обособленный, независимый уровень. Кэширование Docker для этого уровня будет аннулирован только если подвергся изменению один из этих файлов.
Имея теперь скопированными в наш образ свои Gemfile
и
Gemfile.lock
, мы теперь можем изменить тот каталог, в которм мы находимся и где мы
устанавливаем свои gems:
WORKDIR /usr/src/app
RUN bundle install
Наконец, имея установленными свои gems, мы можем скопировать все оставшиеся исходные файлы в этот образ:
COPY . /usr/src/app/
Теперь изменения во всех оставшихся скопированных на последнем шаге файлах вызовут аннуляцию значения кэша для этой инструкции, которая расположена после установки наших gems - в точности что мы и хотели.
Теперь давайте повторно соберём свой образ при помощи данного обновлённого Dockerfile
.
Помните, тем не менее, что мы сейчас изменили всё за исключением первых трёх инструкций в своём
Dockerfile
, поэтому мы ожидаем что наш кэш будет аннулирован после этого.
Это означает, что остающиеся шаги придётся строить с нуля, в том числе и bundle install
,
что потребует определённого времени.
$ docker build -t railsapp .
Имея свой вновь собранный образ, давайте посмотрим что произойдёт когда мы изменим свой файл
README.md
снова. Поойдите далее и внесите какие- нибудь незначительные исправления
в README.md
, сохраните эти изменения и заново соберите свой образ:
$ docker build -t railsapp .
Sending build context to Docker daemon 102.9kB
Step 1/7 : FROM ruby:2.6
---> f28a9e1d0449
Step 2/7 : RUN apt-get update -yqq && apt-get install -yqq --no-install-
recommends nodejs
---> Using cache
---> 29c3dee2b8c7
Step 3/7 : COPY Gemfile* /usr/src/app/
---> Using cache
---> 050a87002be1
Step 4/7 : WORKDIR /usr/src/app
---> Using cache
---> d227daeedb1e
Step 5/7 : RUN bundle install
---> Using cache
---> 616b88058c4b
Step 6/7 : COPY . /usr/src/app/
---> b189758b9ded
Step 7/7 : CMD ["bin/rails", "s", "-b", "0.0.0.0"]
---> Running in fad4be04ab20
Removing intermediate container fad4be04ab20
---> 9be0cf184e64
Successfully built 9be0cf184e64
Successfully tagged railsapp:latest
Это было намного быстрее чем когда мы меняли свой README.md
раньше.
На этот раз это не привело к повторному построению наших gem. Строки с 6 по 7 в нашем Dockerfile
могут применять имеющийся кэш потому что в них ничего не изменено. Docker всего лишь повторно собирает окончательные два
этапа, причём оба они быстрые.
Наш Dockerfile
неотразим, не так ли? Шедевр. Это маленькое дитя станет толчком
к тому что наша разработка приложения Rails на самом деле состоится. Итак, давайте сделаем то, что делают все настоящие
творцы и подпишем свою работу.
В отличии от художника, ставящего свою подпись в правом нижнем углу своего полотна, поклонники Docker обычно утверждают своё авторство на некий образ устанавливая некую метку сопровождающего (maintainer label) в качестве второй инструкции. Некая метка это просто фрагмент метаданных, связанных с неким образом.
Мы установим некую метку при помощи соответствующей инструкции LABEL
, которая
обладает таким форматом:
LABEL <key>=<value>
Она снабжает наш образ некой меткой с названием key
установленной в
value
.
Для указания того кто отвечает за сопровождение данного файла мы изменим свой Dockerfile
чтобы определить его адрес электронной почты подобно следующему (вы можете подставить адрес своей электронной почты вместо
моего):
FROM ruby:2.6
» LABEL maintainer="rob@DockerForRailsDevelopers.com"
RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
nodejs
COPY Gemfile* /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
COPY . /usr/src/app/
CMD ["bin/rails", "s", "-b", "0.0.0.0"]
И на этом наш Dockerfile
завершён.
Стоит отметить, что метки можно использовать для хранения в своих образах любых метаданных, которые вам заблагорассудится. Вы можете использовать столько инструкций LABEL, сколько пожелаете, или же объединить их в одну строку следующим образом:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
Выбор за вами.
Прежде чем завершить, не забудьте окончательно собрать свой образ с этим изменением:
$ docker build -t railsapp .
На этот раз, поскольку мы ввели некую инструкцию в самом начале своего Dockerfile
его сборка обязательно будет медленной, поскольку все gems будут установлены с самого начала.
Наш Dockerfile
отполирован достаточно знатно. Вы можете отложить гаечный
ключ, снять робу с масляными пятнами и закинуть ноги на стол - опять-таки, образно выражаясь. Вы этого заслужили.
Давайте повторим что мы изучили:
-
Мы рассмотрели как именовать и поддерживать версии своего образа задавая в нём теги либо после его построения:
$ docker tag a1df0eddba18 railsapp
либо в момент сборки (здесь устанавливаются два тега):
$ docker build -t railsapp -t railsapp:1.0 .
-
Мы добавили некую команду по умолчанию в свой образ при помощи инструкции
CMD
: CMD ["bin/rails", "s", "-b", "0.0.0.0"]
-
Мы ускорили построение своего образа воспользовавшись
.dockerignore
для предотвращения отправки в демон Docker ненужных файлов в качестве контекста нашей сборки. -
Мы обеспечили гарантию того что мы всегда применяем современную информацию репозитория пакетов при изменении тех пакетов, которые мы устанавливаем скомбинировав
apt-get update
иapt-get install
в единую инструкциюRUN
: RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \ nodejs
-
Мы предотвратили то, что изменения в файлах вызывают повторное построение наших gems скопировав
Gemfiles
раньше в своёмDockerfile
с тем, чтобы они могли кэшироваться отдельно: COPY Gemfile* /usr/src/app/ WORKDIR /usr/src/app RUN bundle install
-
Наконец, мы указали кто отвечает за наш образ, установив значение
maintainer
в соответствующей инструкцииLABEL
: LABEL maintainer="rob@DockerForRailsDevelopers.com"
Неплохо для дня работы.
Если вы предполагали, что использование Docker для разработки не может быть лучше, или, быть может, у вас ещё остались какие- то сомнения, будьте готовы. Далее мы исследуем некий даже ещё более мощный инструментарий который устроит турбонаддув для вашей разработки. Вперёд!