Глава 2. Исполнение прикладного приложения Rail в контейнере
Содержание
- Глава 2. Исполнение прикладного приложения Rail в контейнере
Теперь вы должны начать знакомиться с понятиями Docker, такими как образы и исполняемые на основе этих образов контейнеры. Не беспокойтесь если вы не запомнили все команды и их разнообразные параметры. Самый важный момент состоит в том что вы начинаете осваивать все понятия на верхнем уровне - всё остальное придёт когда вы начнёте применять Docker снова и снова.
В своей последней главе мы создали наше блестящее новок прикладное приложение Rails. После того как начало проходить наше изумление от того как круто было вырабатывать некое прикладное приложение при помощи Ruby, поставляемого Docker, вам вероятно осталось задуматься над важным вопросом: на кой чёрт я на самом деле запускаю его?
В этой главе мы собираемся подхватить с того места где мы остановились чтобы запустить своё новое приложение. Итак, вы жарили, перемалывали, варили и иным образом готовили домашний напиток по своему выбору? (Мне только воду, спасибо.) Ну ладно, давай натрескаемся ...
К сожалению мы не можем запустить некий сервер Rails просто своим образом ruby:2.6
- Rails имеет некоторые дополнительные зависимости. Например, нам потребуется интерпретатор JavaScript (скадем,
Node.js) в помощь нашим конвейерам ресурсов, плюс нам потребуется установить свои зависимости gem. Как нам запустить некий
сервер Rails в контейнере и при этом гарантировать соблюдение этих требований?
Существует несколько подходов, которые мы можем предпринять. Мы можем сделать то,
что мы делали в своей предыдущей главе: запустить bash
внутри контейнера на основе
уже применявшегося образа ruby:2.6
и установить оттуда то что нам требуется.
Однако исполнение всех команд вручную не самый простой способ для повторяемых
действий. Мы бы желали повторяемый способ раскрутки серверов влево, направо и по центру. Необходимость запускать различные команды
вручную каждый раз когда мы пожелаем запускать некий сервер Rails никак не сокращает работу.
Другой способ, которым мы можем получить контейнер исполняющим Rails состоит в
получении того же самого набора команд, требуемых для установки требований Rails и соединения их воедино в некую длинную
составную команду docker run
. Однако не просто эта команда будет гигантской, неуклюжей
и сложной для запоминания, но и, что хуже всего, она была бы медленной. Эти
инструкции установки приходилось бы выполнять с нуля всякий раз, в том числе установку Node.js или наших зависимостей gem/
Мы бы не хотели ожидать минуты просто чтобы запустить некий сервер Rails.
Компоновка команд docker run | |
---|---|
Вы может быть любопытным узнать как бы вы могли запускать множество команд в неком контейнере при помощи
Основной трюк при обходе данного ограничения состоит в использовании параметра
Старый добрый |
Итак, каково же настоящее решение?
Ладно, мы хотим иметь возможность запускать контейнеры на основе некого предварительно настроенного состояния, которое имеет всё что необходимо для запуска Rails. Всё что нам понадобится, так это фабрика - подсказка, подсказка - для создания таких исключительных контейнеров сервера Rails. Вы уловили тонкий намёк? В своей предыдущей главе мы уже говорили, что некий образ это "фабрика для создания конкретных контейнеров". Похоже, это именно то что нам требуется.
В реальной жизни фабрика не берётся из ниоткуда. Она должна быть построена в соответствии с чертежами: подробными
планами и инструкциями, которые в точности описывают как именно она должна выглядеть. Фабрики контейнеров Docker -
иначе говоря, образы - ничем не отличаются. Они требуют особого файла кальки, так и именуемого,
Dockerfile
. Некий Dockerfile
использует
специальный синтаксис для описания в точности как следует собирать соответствующий образ. Если вы уже знакомы с
выражением инфраструктуры в качестве кода (IaaC), это именно её пример:
Dockerfile
описывает как настраивается некий образ машины, как это показано на
схеме ниже.
Некий Dockerfile
создаётся из различных инструкций
- таких как FROM
, RUN
,
COPY
и WORKDIR
- по соглашению всё заглавными.
Вместо того чтобы абстрактно рассуждать обо всём этом, давайте рассмотрим конкретный пример.
Вот некий базовый Dockerfile
для исполнения нашего прикладного приложения Rails.
Оно пока не совершенно - мы сделаем некие улучшения в Главе 3,
Тонкая настройка нашего образа Rail - но пока нам хватит и этого. Пока нет необходимости создfвать этот файл;
пока мы просто поговорим.
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
Всякий образ должен с чего- то начинаться: с другого, предварительно имевшегося образа. По этой причине всякий
Dockerfile
начинается с некой инструкции FROM
,
которая и определяет тот образ, который применять в качестве его отправной точки. Обычно мы ищем для некого стартового
момента то что больше всего подходит. Таким образом мы можем расширять его и настраивать под свои потребности.
Самой первой строкой нашего Dockerfile
является:
FROM ruby:2.6
Она сообщает, что наш образ будет основываться на образе ruby:2.6
, который,
как вы вероятно догадались, имел предварительно установленным Ruby 2.6. Мы выбрали старт с этого образа потому как самым
основным нашим требованием является наличие установленным Ruby, тем самым, данный образ уже проделал большую часть нашего
пути.
Справа вверху: базовые образы | |
---|---|
Существует несколько особых образов без каких бы то ни было образов родителей - они именуются как некий базовый образ - именно на них основаны все образы. Они содержат минимальную файловую систему пользователя для некой операционной системы. Если вы пожелаете построить свой собственный урезанный до минимума образ, вы можете строить свой образ
Даже имеется возможность создавать ваши собственные базовые образы, хотя это и несколько более продвинутая тема. Мы не намерены обсуждать её, так как имеется вероятность что вам это никогда не понадобится. |
Следующими двумя строками в Dockerfile
являются инструкции
RUN
, которые указывают Docker на необходимость выполнения неких команд:
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
Здесь мы сообщаем Docker о необходимости исполнить apt-get update -yqq
с последующим apt-get install -yqq --no-install-recommends nodejs
- но чего
достигают для нас эти две команды?
Как мы уже могли знать, apt-get
это команда, применяемая для установки
программного обеспечения в Debian (и неких прочих) дистрибутивах Linux. Мы применяем её в своём Dockerfile
по той причине, что наш официальный образ Ruby, поверх которого мы строим совй собственный образ, основан на Debian -
в частности на версии с названием Stretch.
Следующая команда apt-get update
сообщает имеющемуся диспетчеру пакетов выгрузить самую
последнюю информацию этого пакета. Многие Dockerfile
будут иметь аналогичную строку,
так как без неё apt
вовсе не имеет никакой информации о пакете, а следовательно не будет
иметь возможности установить что бы то ни было. Её параметр -yqq
является сочетанием
параметра -y
, который указывает на необходимость отвечать "yes" во всех
приглашениях и параметр -qq
, который включает "quiet" (тихий) режим
для снижения вывода на печать.
Идущая следующей, команда apt-get install
устанавливает Node.js, предварительно
требующийся для Rails. Соответствующий параметр --no-install-recommends
сообщает о том что не нужно устанавливать прочие рекомендуемые, но не существенные пакеты - они нам не нужны, и мы желаем
поддерживать размер своего образа настолько маленьким, насколько это возможно не устанавливая не являющиеся необходимыми
файлы.
Если вы знакомы с apt-get
в Linux, вы могли бы удивиться что мы не запускаем
свои команды от имени root
при помощи sudo
.
Это обусловлено тем, что по умолчанию команды внутри контейнера исполняются самим пользователем root
,
поэтому sudo
не требуется (хотя, как
мы обсудим, это имеет последствия для промышленных приложений).
Давайте слегка переключимся перед тем как обсуждать следующую строку своего Dockerfile
.
Помните, что образы и порождаемые ими контейнеры являются обособленными от нашей локальной машины - они являются изолированными средами песочницы. Таким образом, нам требуется некий способ заключать часть своих локальных файлов внутри тех контейнеров, которые мы будем запускать.
Мы уже наблюдали в Генерации нового прикладного приложения Rails без установленного Ruby, что мы имеем возможность монтировать некий локальный каталог в своём исполняемом контейнере. Некий монтируемый том действует как какой- то совместный для самого контейнера и его хоста каталог и это один из способов, которым мы можем выполнять доступ к локальным файлам внутри своего контейнера.
Тем не менее, монтирование некого тома имеет существенную тёмную сторону если это единственный способ, коим вы получаете доступ внутри некого контейнера. Файлы в неком томе не являются частью самого этого образа; они вкладываются в этот образ поверх во время исполнения (runtime, когда вы запускаете свой контейнер). Если такие монтируемые файлы являются существенными, данный образ не будет без них работать, но основным моментом образа является задача упаковать всё что ему требуется для исполнения. Таким образом, хорошим практическим приёмом будет снабдить все необходимые файлы вовпутрь самого образа.
Следующая строка в нашем Dockerfile
обслуживает именно эту цель:
FROM ruby:2.6
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY . /usr/src/app/
Это сообщает Docker о необходимости скопировать все файлы и нашего локального, текущего каталога
(.
) в /usr/src/app
в файловую систему
нашего нового образа. Так как нашим локальным текущим каталогом является корень нашего Rails, на самом деле мы просим:
"Скопируй наше приложение Rails в папку /usr/src/app
этого контейнера."
Значение нашего пути источника всегда относительное к тому где расположен
используемый Dockerfile
.
Добавив наши файлы Rails в /usr/src/app
своего образа мы хотим исполнить
различные команды, которые требуется отработать в том каталоге гди и расположены эти файлы. Например, вскорости мы
пожелаем запустить своё приложение сервера Rails в неком контейнере при помощи команды, подобной следующей:
$ docker run [OPTIONS] <our custom image>> bin/rails server
К сожалению, эта команда завершится неудачно ибо, по умолчанию, рабочим каталогом контейнера является
/
, который не содержит файлов нашего приложения Rails - мы скопировали их в
/usr/src/app
.
Тем не менее, нам может помочь с исправлением данного положения вещей соответствующая инструкция
WORKDIR
. На самом деле она выполняет команду смены
каталога (cd
), изменяя то, что наш образ рассматривает своим текущим
каталогом. Следующая строка в нашем Dockerfile
применяет её для установки в
качестве своего рабочего каталога /usr/src/app
:
WORKDIR /usr/src/app
Теперь, запускаемые команды bin/rails server
(и аналогичные) отработают, так как
они будут исполнены в правильном каталоге.
Вы можете применять в своём Dockerfile
множество инструкций
WORKDIR
, причём каждая из них будет оставаться действующей вплоть до появления
вызова следующей. Самая последняя WORKDIR
будет самым начальным рабочим каталогом
для создаваемых из данного образа контейнеров.
Наконец, мы достигаем самой последней строки в своём Dockerfile
:
RUN bundle install
Эта команда исполняется в текущем рабочем каталоге, который предыдущей командой был установлен в
/usr/src/app
. Таким образом это установит необходимые gem, определяемые
Gemfile
нашего проекта Rails, которые необходимы для запуска данного
приложения.
Вооружившись этими знаниями, наш Dockerfile
должен быть теперь намного более
понятным. Давайте взглянем на него ещё разок:
1: FROM ruby:2.6
2:
3: RUN apt-get update -yqq
4: RUN apt-get install -yqq --no-install-recommends nodejs
5:
6: COPY . /usr/src/app/
7:
8: WORKDIR /usr/src/app
9: RUN bundle install
Во- первых, в строке 1 мы сообщаем своему персональному образу о необходимости применять общий образ
ruby:2.6
в качестве его отправной точки. Затем обновляем информацию о пакетах
в своём диспетчере пакетов apt
(строка 3) с тем, чтобы знать чо устанавливать.
Затем мы применяем его для установки nodejs
(строка 4), который нам требуется для
конвейера ресурсов Rails.
Позаботившись о предварительных требованиях для Rails, мы затем скопировали файлы своего приложения из нашего текущего
каталога в /usr/src/app
(строка 6) с тем чтобы они были выпечены в самом образе.
Мы делаем его текущим рабочим каталогом для своего образа (строка 8), с тем чтобы мы могли исполнять команды Rails
для своего образа из верного каталога.
Наконец, мы bundle install
(строка 9) для установки тех gem, которые
требуются нашему проекту Rails.
Теперь, когда в этом больше смысла, давайте продолжим и создадим этот Dockerfile
.
Вначале мы убедимся что мы находимся в самом верхнем уровне (в корне) каталога своего приложения Rails:
$ ls
Gemfile Rakefile bin config.ru lib package.json storage vendor
README.md app config db log public tmp
Затем вскройте свой любимый редактор и создайте некий файл с названием Dockerfile
с показанным нами содержанием. Я настоятельно рекомендую набрать его вручную вместо копирования и вставки - при
обучении новым навыкам физический набор изучаемого помогает зацементировать это в вашем сознании и построить вам память
на кончиках пальцев.
Имея в своих руках роскошный Dockerfile
, давайте переключим своё внимание на
то мы применим его для создания некого реального образа.
Процесс выработки некого образа по Dockerfile
именуется
построением образа. Мы выполняем его при помощи команды
docker build
, которая имеет следующий формат:
$ docker build [options] path/to/build/directory
В нашем случае вы всё ещё должны пребывать в своём каталоге, содержащим наш Dockerfile
и файлы проекта поэтому мы можем воспользоваться одинарной точкой для указания на текущий каталог. Давайте пройдём через
это:
$ docker build .
Sending build context to Docker daemon 138.8kB
Step 1/6 : FROM ruby:2.6
---> f28a9e1d0449
Step 2/6 : RUN apt-get update -yqq
---> Running in 29677ed71d2b
Removing intermediate container 29677ed71d2b
---> 761da319d69a
...
Step 6/6 : RUN bundle install
---> Running in 4550030ac412
...
Bundle complete! 15 Gemfile dependencies, 68 gems now installed.
Bundled gems are installed into `/usr/local/bundle`
Ух ты, достаточно большой вывод. Что же произошло на самом деле?
Docker обрабатывает наш файл Dockerfile
по одной инструкции за раз. Самая первая
инструкция - FROM
- трактуется иным образом нежели все остальные. Docker проверяет
имеется ли уже определяемый образ в нашей локальной системе. Если данный образ не доступен, Docker выгружает этот образ, в
точности как это имело место в Исполнение некого сценария Rails без установленного Ruby,
когда мы исполнили docker run
с указанием ruby:2.6
в самый первый раз.
Все прочие инструкции в данном Dockerfile
обрабатываются тем же самым манером.
Docker запускает одноразовый контейнер на основе тог образа, который был создае на предыдущем шаге, и исполняет текущую
инструкцию Dockerfile
внутри него. Затем Docker
фиксирует (commit) все только что сделанные в результате исполнения данной инструкции
изменения, создавая некий промежуточный образ для данного шага.
Вы можете всё что происходит в получаемом выводе, который разделяется на секции: по одной секции для каждой инструкции из
Dockerfile
. Получаемый вывод для каждого этапа имеет достаточно упорядоченный
формат:
1: Step <current step>/<total steps> : <Dockerfile instruction>
2: ---> Running in <container ID>
3: [Any output from running the instruction]
4: Removing intermediate container <container ID>
5: ---> <image ID>
Для указания на контекст нам выдаётся сама инструкция Dockerfile
, а также какой этап
выполняется в данном процессе сборки (строка 1). Затем мы видим значение идентификатора того одноразового контейнера, который
применяется для исполнения текущей инструкции Dockerfile
(строка 2), за которой
следует весь вывод от исполнения данной инструкции (строка 3).
Всякий создаваемый образ - даже промежуточный - получает некий уникальный, случайно вырабатываемый идентификатор образа. Именно им Docker идентифицирует образы внутри себя, причём он предоставляет нам некий способ ссылаться на него. Само значение создаваемого на данном этапе образа отображено в строке 5.
Наконец, в строке 4 Docker сообщает нам об удалении им того одноразового контейнера, который он применял на данном этапе.
При построении некого индивидуального образа мы в действительности интересуемся самим окончательным образом. Он представлен на
самом последнем этапе после окончания всех инструкций по окончанию исполнения данного Dockerfile
.
Именно по этой причине весь вывод завершается выдачей нам самого последнего идентификатора образа (если вы следуете за нами, ваш
идентификатор образа будет иным):
Successfully built a1df0eddba18
Всё это кажется достаточно разумным, но где находится сам только что собранный нами образ?
Сама команда docker build
не выполняет вывод некого файла; она всего лишь делает
доступным такой новый образ, добавляя его в имеющийся перечень образов, о которых известно Docker. Docker управляет тем
где и как сохраняются образы в вашей файловой системе. Приводимой ниже командой мы перечисляем имеющиеся в нашей системе
образы:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> a1df0eddba18 1 second ago 1.01GB
ruby 2.6 f28a9e1d0449 6 days ago 868MB
Самый первый элемент представляет наш персональный образ, который мы только что создали - его идентификатор образа
совпадает с тем, что определён по окончанию выполненной нами команды docker build
.
Теперь, когда мы создали свой собственный сделанный на заказ образ, мы должны иметь возможность запустить некий сервер Rails для исполнения нашего приложения.
Давайте попробуем сделать это сейчас.
Мы можем ссылаться на свой образ по его идентификатору. Тем не менее, идентификаторы образа достаточно длинные и трудные для запоминания, поэтому обычным делом является назначение некому образу осмысленного названия. Позднее в Именовании и сопровождении версий для нашего образа мы увидим как это делается. На данном этапе, однако будем ссылаться на свой образ по его идентификатору, чего нам вполне хватит для старта при помощи данного образа. Давайте вскроем и сделаем это прямо сейчас.
Имея на руках идентификатор образа, мы можем запустить своё приложение Rails внутри некого контейнера на основе своего персонального образа при помощи приводимой далее команды. Давайте сделаем это:
$ docker run -p 3000:3000 a1df0eddba18 \
bin/rails s -b 0.0.0.0
Помимо отображённого нового параметра -p 3000:3000
, который мы вкратце обсудим в
разделе Добираемся до прикладного приложения: публикация портов,
это обычная старая команда docker run
. Она сообщает: "Запусти некий котейнер
на основе нашего персонального образа (a1df0eddba18
) и выполни внутри него
bin/rails s -b 0.0.0.0
." Если вы никогда ранее не видели параметр
-b
, мы поясняем зачем он требуется в разделе
Связывание сервера Rails с IP адресом.
Мы должны обнаружить что Rails запустился должным образом:
=> Booting Puma
=> Rails 5.2.2 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Дело сделано! Полёт идёт нормально.
Теперь давайте двинемся далее и посетим в вашем браузере http://localhost:3000
.
Вы должны увидеть знакомую страницу приветствия Rails.
Дай пять! Мы достигли своего приложения.
В своём терминале вы обнаружите обновление вывода журнала Rails показом нашего запроса:
Started GET "/" for 172.17.0.1 at 2019-01-15 09:49:45 +0000
...
Rendering /usr/local/bundle/gems/railties-5.2.2/lib/rails/templates/rails/
welcome/index.html.erb
Rendered /usr/local/bundle/gems/railties-5.2.2/lib/rails/templates/rails/
welcome/index.html.erb (2.7ms)
Completed 200 OK in 17ms (Views: 10.0ms | ActiveRecord: 0.0ms)
Мы в деле. Теперь вы можете остановить свой сервер Rails нажав Ctrl - C
.
Хорошо, я достаточно долго отмахивался от вас. Настало время обсудить что же на самом деле делают различные применявшиеся нами команды запуска Docker. Вы готовы поразмышлять? Тогда давайте перейдём к этому.
Насколько нам известно,контейнеры изолированы в песочницах. Как так произошло, что мы оказались способными достичь
свой контейнер посетив http://localhost:3000
в своей локальной машине?
Правда состоит в том, что контейнеры не будут очень полезными если нет никакого способа их достижения извне Docker. Например, весь смысл веб сервера состоит в том, чтобы он был доступен персоналу, который выполняет запросы к нему.
Однако по умолчанию некий контейнер может быть доступен только изнутри сетевой среды Docker, к которой он подключён
(подробнее об этом в Как контейнеры общаются друг с другом),
мы же можем сделать его доступным извне опубликовав один или более портов
при помощи параметра -p
в docker run
.
В своей команде мы определили -p 3000:3000
; это опубликовало соответствующий порт
контейнера 3000 (второе значение) по порту 3000 в нашей локальной машине. Именно таким образом запрос к
http://localhost:3000
и достигает наш сервер Rails, запущенный в имеющемся
контейнере с портом 3000.
Как это работает на практике?
Как мы уже видели в Схеме архитектуры Dockere для
Linux, в Linux наш демон Docker запускается напрямую в вашей локальной машине. В этом случае публикация
порта просто устанавливает соответствие (через некое правило iptables
), что и
переправляет запросы к http://localhost:3000
в имеющийся Механизм Docker, который
знает как выполнять маршрутизацию соответствующего запроса в той сетевой среде, к которой подключён ваш контейнер (как
это показано на следующей схеме).
Docker для Mac/Windows имеет некую дополнительную сложность. Помните, здесь демон Docker запускается внутри некоторой
ВМ Linux с малым весом, как мы это видели на Схеме архитектуры Dockere
для Mac/Windows. Внутри такой ВМ всё работает в точности как для Docker в Linux - имеющееся соответствие портов будет
выполнять маршрутизацию в ваш контейнер. Однако требуется ещё немного магии для направления запросов от
http://localhost:3000
в сам порт 3000 ВМ; Docker для Mac/Windows настраивает
для достижения этого пересылку порта, которая отображена на следующей схеме.
При публикации некого порта вы не обязаны использовать тот же самый внешний порт, который ваша служба применяет внутри самого
контейнера. Если бы мы определили -p 80:3000
, это бы выполнило установку соответствия
порта 80 в вашей локальной машине тому серверу Rails, который осуществляет ожидание по порту 3000 внутри вашего контейнера.
Это предоставляет нам гибкость в терминах того как выставлять службы во внешний мир.
Обычно для запуска некого сервера Rails мы просто исполняем bin/rails
, всё же
когда мы запускаем сервер Rails при помощи docker run
, мы применяем
bin/rails s -b 0.0.0.0
. Зачем мы так поступаем?
Когда мы запускаем сервер Rails с помощью bin/rails s
, по умолчанию, он
выполняет ожидание запросов только в localhost
( или в
127.0.0.1
) на каждой машине, в которой он запущен. Это предоставляет некую
безопасность по умолчанию, предотвращая доступ извне к серверу вашего приложения Rails. Однако в нашем случае этот сервер
работает внутри некого контейнера, а запросы поступают извне.
Когда мы делаем запрос http://localhost:3000
в своей локальной машине, как мы
это уже видели в Добираемся до прикладного приложения: публикация портов,
такой запрос перенаправляется в имеющийся Механизм Docker. Тот в свою очередь выполняет маршрутизацию в тот контейнер,
в котором запущен наш сервер Rails, выполняя транслюцию запроса в [IP address of container]:3000
.
Однако поскольку наш сервер Rails выполняет ожидание только запросов от localhost
,
ничто не выдаст ответ на такие запросы, поступающие с иного IP адреса.
Для исправления этого нам придётся сообщить своему серверу Rails выполнить привязку
ко всем IP адресам, а не только к localhost
,
воспользовавшись параметром -b 0.0.0.0
. Значение IP адреса
0.0.0.0
является особым адресом, который означает "все IPv4 адреса в данной
машине."
Обнаружение IP адреса запущенного контейнера | |
---|---|
Если вас интересует как отыскать значение реального адреса IP некого исполняемого контейнера, вы можете проделать следующее:
|
Уф! Это была насыщенная действиями глава! Давайте повторим основное:
-
Мы рассмотрели свой первый, сшитый на скорую руку
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
-
Мы построили свой персональный образ из
Dockerfile
при помощи: $ docker build .
-
Мы перечислили все образы в своей системе вызвав:
$ docker images
-
Мы запустили некий сервер Rails для исполнения нашего приложения с помощью:
$ docker run -p 3000:3000 a1df0eddba18 \ bin/rails s -b 0.0.0.0
А также мы увидели его исполняющимся из своего браузера по http://localhost:3000
.
В своей следующей главе мы начнём делать некие уточнения в своём Dockerfile
.
В процессе этого мы изучим как предоставлять своим образам дружественные названия, а также как ускорять построение
образов получая преимущества от встроенного механизма кэщирования.