Статьи

Использование Docker для разработки Rails

В первые выходные октября более двухсот разработчиков собрались в Генте для ArrrrCamp , серьезной, но пока пиратской тематической конференции по Ruby. Я был рад выступить с докладом об использовании Docker для разработки на Rails. Ниже приведена сжатая версия доклада, в котором рассматриваются введение в контейнеризацию и экосистему Docker, а также некоторые примеры запуска приложений Rails в контейнерах Docker.

Если вы хотите следовать примерам кода, вы можете найти исходный код на GitHub , слайды из моего выступления также доступны, а видео самого выступления — прямо здесь:

контейнаризация

Скорее всего, если вы только начали работать с контейнерами, вы работали с ними через Docker . За последние два года контейнеризация стала более широко использоваться, потому что Docker убрал барьеры и значительно упростил интеграцию контейнеров в рабочий процесс разработки.

Важно помнить, что Docker не равен контейнерам, и на самом деле есть другие способы использования контейнеров, чем с Docker. Но так как Docker делает это так просто, использовать их инструменты практически нетрудно.

Одним из основных преимуществ использования контейнера является то, что он довольно шустрый. Их загрузка не занимает много времени, а затраты времени и пространства относительно невелики. Еще одним преимуществом является их ограниченная сфера применения.

Контейнер — это автономная среда выполнения, означающая, что все зависимости контейнера содержатся внутри самого контейнера. Это дает каждому из ваших сервисов автономию в использовании соответствующего набора инструментов для его роли в вашем приложении, не беспокоясь о конфликте с другим компонентом. Вы спасены от спагетти зависимостей, так как зависимости существуют только внутри контейнера.

Проще говоря, контейнеры — это просто слой виртуализации. Они не заменяют собой виртуальные машины, и вы даже можете использовать виртуальные машины и контейнеры вместе.

Суть не в том, чтобы полностью прекратить использование виртуальных машин, а в том, чтобы повысить плотность обслуживания путем добавления контейнеров в набор. Вместо запуска трех служб на трех виртуальных машинах вы можете запускать одни и те же три службы в контейнерах на одной виртуальной машине. Это означает меньше денег и меньше времени на обслуживание вашей инфраструктуры, так как меньше виртуальных машин.

Начало работы с контейнерами на первый взгляд может показаться более сложным, но они значительно сокращают время и пространство, необходимое для запуска вашего приложения. Тратьте меньше времени на подготовку, перезагрузку и борьбу с зависимостями и больше времени на то, что вы хотите.

Установка Docker

Если вы используете Linux, установите его через официальные пакеты .

Если вы используете OS X или Windows , вы можете установить Docker через Docker Toolbox. Это может помочь познакомиться с инструментами Docker, прочитав о том, как инструменты в Docker Toolbox работают вместе .

Обратите внимание, что если вы используете Docker Toolbox, вам нужно будет запустить его eval $(docker-machine env machine_name)для запуска команд с вашего терминала.

Докер Экосистема

То, что начиналось как небольшой проект, выросло до очень мощной экосистемы множества различных типов инструментов.

Docker фокусируется на трех основных функциях: Build, Ship и Run. Часть «Сборка» — это то, на чем мы сконцентрируемся на данный момент, так как она, вероятно, будет наиболее актуальной для вас как разработчика.

Первое, с чем вам нужно ознакомиться, когда вы начнете запускать сервисы Dockerized, это образ Docker . Изображение и контейнер — это две разные вещи; изображение запускается внутри контейнера. Вы можете представить себе изображение как класс, а контейнер как экземпляр этого класса.

Вы можете найти общедоступные изображения в Docker Hub , в котором находится публичный реестр Docker. Существует более 15 000 изображений, которые вы можете развернуть и использовать в своих проектах. Вы также можете иметь частные репозитории на хабе. Если вы беспокоитесь о проприетарном коде, вы можете запустить свой собственный реестр (и вы можете найти образ реестра в Docker Hub).

В Docker Hub доступно несколько разных стилей изображений. Первый — это то, что я назвал «образ службы», то есть образ, который вы можете развернуть, запустить в контейнере и получить работающий сервис для использования. Хорошим примером этого типа изображений является база данных. Вы можете запустить базу данных в контейнере и начать работать с ней.

Другой тип изображения — это «базовое изображение проекта». Они предназначены для настройки среды в контейнере, который затем может запускать ваш собственный код. Языковые изображения (например, изображения Ruby или Golang ) попадают в эту категорию. Просто запустив изображение, вы не доберетесь до него без добавления собственного кода. Это просто база для вашего собственного проекта.

Вы также можете найти официальные изображения на хабе. Это изображения, которые поддерживаются компаниями или сообществами с открытым исходным кодом, и они являются хорошей отправной точкой для вашего проекта.

Чтобы снять изображение с Docker Hub, вы можете сказать docker pull image_name.

(Https://no-cache.hubspot.com/cta/default/1169977/224ef658-b146-4569-b00b-3c0ad87be198.png)

Создание ваших собственных изображений Docker

Конечно, вы можете создавать свои собственные изображения Docker. Для этого вам нужен Dockerfile. Вы можете найти ссылку на Dockerfile в документации Docker.

Вот простой Rails Dockerfile:

FROM rails:4.2.4
MAINTAINER Laura Frank <[email protected]>
RUN mkdir -p /var/app
COPY . /var/app
WORKDIR /var/app
RUN bundle install
CMD rails s -b 0.0.0.0

После того, как я написал свой Dockerfile, я могу создать его, сказав:

docker build -t image_name . # don’t forget the dot!

Каждое из прописных слов в Dockerfile является инструкцией. В этом Dockerfile мы используем базовый образ Rails, а затем копируем существующее приложение Rails (в нашем текущем каталоге) во вновь созданный /var/appкаталог в контейнере. Это статическая копия, и после ее завершения единственным способом обновления кода в контейнере является перестройка моего изображения. Когда я запускаю контейнер с этим изображением, он запускается с CMD или команды rails s -b 0.0.0.0.

Чтобы увидеть образы, доступные на вашем хосте Docker, из docker pullили из docker build, запустите docker images.

Сборка Rails-приложения с помощью Docker

У нас есть несколько целей, когда мы запускаем приложение Rails с Docker.

  • просмотреть приложение, запущенное в браузере
  • редактируйте файлы в локальной среде и смотрите изменения
  • запускать грабли, такие как миграции
  • см выход журнала

По сути, мы хотим воспользоваться преимуществами скорости и изоляции, которые предоставляет Docker, но при этом иметь среду разработки, которая кажется нам естественной.

В предыдущем примере с Dockerfile нам приходилось перестраивать образ каждый раз, когда мы меняли код, чтобы увидеть изменения, запущенные в контейнере. Это огромная боль, но вы можете обойти ее, используя крепление громкости.

Вместо того чтобы статически копировать весь код внутри контейнера, вы смонтируете свой рабочий каталог как том внутри контейнера (воспринимайте это как синхронизацию папок), а затем вы можете редактировать код и видеть изменения, выполняющиеся внутри контейнера, без необходимости восстановить изображение.

Вот как docker runбудет выглядеть Dockerfile и строка при использовании смонтированного тома для каталога вашего приложения.

FROM rails:4.2.4
MAINTAINER Laura Frank <[email protected]>
RUN mkdir -p /var/app
COPY Gemfile /var/app/Gemfile
WORKDIR /var/app
RUN bundle install
CMD rails s -b 0.0.0.0

Instead of copying everything, we’ll just copy the Gemfile and Gemfile.lock, then bundle install.

We still have to get the rest of the code inside the container, though. This is done at runtime with a -v flag.

docker run -v local/project/path:/var/app -p 3000:3000 my_image_name

Full docker run reference is available in the Docker docs.

A couple important flags that you’ll use pretty frequently:

  • -p 3000:3000 create a port binding rule; -ip:hostPort:containerPort
  • -v local/path:/path/in/container mount a volume; -v hostPath:containerPath

That docker run string is a little long, and you may not want to type it each time you run your application.

Docker Compose is an application templating tool that allows you to specify all of your applications configurations in a yaml file. Then, instead of running your application directly with Docker, you can simply run it with docker-compose up.

A Rails container identical to the one we ran above with docker run will look like this with Docker Compose.

web:
  build: .
  ports:
3000:3000
  volumes:
‘local/project/path:/var/app’

This instructs Docker to build the image from the Dockerfile in the directory, and it also specifies the port mapping and volume mounting rules just as in the previous docker run string. This application template is stored in a file called docker-compose.yml. Docker Compose is especially helpful when your application has more than one container.

Let’s create a Rails application with an external Postgres database container.

db:
  image: postgres

web:
  build: .
  ports: 
    - 3000:3000'
  volumes:
    - 'local/project/path:/var/app'
  command: rails s -b '0.0.0.0'
  links:
    - db

Running docker-compose up will pull down the Postgres image and run it in a container, as well as run the Rails application (which we’ve named «web») in the same way as the previous examples.

We’ve also declared a dependency on the db container by the web container by specifying a link. This means that the web container will wait to run until the db container is running, and it also adds some special environment variables (like the IP address of the container running the database) and lines in the /etc/hosts file for the web container.

In this example, you’ll still need to monkey with the database.yml file in the same way you would if you were running this outside of Docker container. You can see an example of this in the GitHub repo.

Running One-off Tasks With Docker Compose

What happens when you’re developing and need to run a task against one of your services running in a container? In the Rails world, a common example of this would be running a database migration.

Luckily, you can use docker-compose run to execute one-off commands within a container. To run rake db:migrate in the Rails container, say docker-compose run web rake db:migrate. You’ll see the migration running, and then you can continue on your merry way.

Note that you can only run docker-compose commands in the directory with the corresponding docker-compose.yml file. To run the above command, you’ll probably have to jump into a new terminal tab (and run eval $(docker-machine env default) if you’re using Docker Toolbox).

Ship It!

If your application is running in a container, deploying it to production will involve building a new image and then distributing the new image to your hosts.

Codeship supports Docker, and you can learn more about it on our blog. Happy shipping!

This article was written by Laura Frank.