Установка гемов в Dockerfile без Gemfile - PullRequest
4 голосов
/ 11 апреля 2020

Моя команда размещает наше приложение Rails из Dockerfile. У нас есть несколько медленных драгоценных камней, которые действительно замедляют наши сборки. (Я смотрю на вас grpc. ?)

Можно ли установить несколько драгоценных камней перед копированием Gemfile в наш Dockerfile? Это позволило бы Docker кэшировать эти этапы сборки, поэтому нам не нужно переустанавливать медленные гемы каждый раз, когда меняется Gemfile.

Я пробовал это, но bundle install все еще устанавливает grpc, sassc и nokogiri.

RUN gem install grpc --version 1.28.0
RUN gem install sassc --version 2.2.1
RUN gem install nokogiri --version 1.10.9

WORKDIR /app

ADD Gemfile Gemfile.lock .ruby-version /app/
RUN bundle install

Ответы [ 3 ]

4 голосов
/ 15 апреля 2020

Проблема:

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

  1. скачать гем из inte rnet
  2. установить и раскрутить приложение

Возможные решения:

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

Решения:

  • Загрузка файлов gem локально, помещенных в папку, и в dockerfile скопируйте эти файлы gem внутри затем установите контейнер.

  • Создайте базовый образ для своего приложения . Создайте базовый образ из Ruby / любого другого файла и установите gems любым из указанных выше способов:

    1. скопируйте gems из локальной папки и затем вставить внутри container или
    2. Используйте команду RUN для установки драгоценных камней. Как хочешь.

Это будет однократный процесс. Благодаря этому вы можете установить базовый образ, который уже содержит ваши драгоценные камни, отнимающие много времени. Теперь внутри вашего приложения dockerfile (которое отвечает за запуск приложения) вам просто нужно использовать собственный созданный базовый образ вместо Ruby или Linux с Docker Hub

Мы будем Посмотрите, как создать свой собственный предварительно настроенный образ. Давайте посмотрим шаг за шагом.

Давайте следовать этому репозиторию GitHub: https://github.com/dupinder/docker-ruby-gem-game

Структура папок (Это поможет понять эту статью )

  • application / dockerfile
  • gems / скачать и разместить локальные самоцветы
  • dockerfile

  • Создание базового образа и установка локальных драгоценных камней внутри контейнера docker.

dockerfile


    FROM ruby:latest
    RUN mkdir -p /gems 
    COPY /gems/grpc-1.28.0-universal-darwin.gem /gems/grpc-1.28.0-universal-darwin.gem
    COPY /gems/sassc-2.2.1.gem /gems/sassc-2.2.1.gem
    WORKDIR /gems
    RUN gem install --force --local *.gem

Сборка изображение из этого файла Docker с помощью следующей команды

docker build --rm -f "dockerfile" -t ruby-gem-base-image:latest "."

  • Шаг 1: Я использую базовое изображение как ruby, вы можете использовать все, что хотите, если вы используете Linux, тогда на следующем шаге вам нужно установить Ruby

  • Шаг 2: Создайте драгоценные камни с именем папки в контейнере.

  • Шаг 3 и 4: Скопируйте драгоценные камни, которые нужно установить внутри контейнер из локального каталога в каталог внутри * 1 118 * container.
  • Шаг 5 и 6: Измените рабочий каталог на gems, потому что мы хотим установить место gems внутри этого каталога, поэтому следующая команда is gem install --force --local *.gem, которая помогает устанавливать гемы внутри локального каталога.

Таким образом, мы решили сократить время на 50%. Теперь docker никогда не будет загружать драгоценные камни из inte rnet каждый раз и устанавливать.

Теперь давайте проверим, установлены ли какие-либо из наших необходимых драгоценных камней, не наши. Для этого:

  • Запустить команду docker images у нас будет наш новый образ сборки ruby-gem-base-image enter image description here

  • Запустите контейнер в отдельном режиме, чтобы мы могли exec позже docker run -it -d ruby-gem-base-image

  • Выполнить docker ps, чтобы получить идентификатор контейнера.

  • Выполнить exec как bash внутри контейнера docker exec -it d28234630343 bash.
  • Запустить gem list Будет выведен список установленных драгоценных камней, и вы увидите там необходимые вам камни.

enter image description here

Убедитесь, что ваши драгоценные камни установлены из локального каталога.


Если вы выполните эти шаги, ваша проблема будет решена. Но теперь вам нужно, если до запуска вашего приложения docker в контейнере уже были установлены гемы.

Для этой проблемы мы можем использовать ruby-gem-base-image образ в качестве нашего ruby базового образа приложения. Если вы помните репозиторий GitHub, у нас есть каталог приложения, в котором есть один dockerfile, если мы увидим это.

FROM ruby-gem-base-image:latest
CMD ["gem", "list"]

Это ваш докер-файл, который можно использовать, когда вы хотите развернуть приложение. Используйте prebuilt * 1196. * изображение, которое имеет ваши драгоценные камни. Я пишу задачу gem list, чтобы проверить, есть ли в этом контейнере драгоценные камни из родительского изображения или нет.

Думаю, это немного понятно. Ваша проблема будет решена с помощью этого.

Если вам нужна другая помощь или вам нужна помощь, чтобы понять этот процесс, пожалуйста, спросите.

--------- Dupinder.

2 голосов
/ 14 апреля 2020

Вы можете подумать о разбиении своего гемфайла, подумайте о следующих файлах:

медленных самоцветов

ruby File.read('.ruby-version').strip

gem 'rubocop'

гемфайл

ruby File.read('.ruby-version').strip

# add the "slow" gems to the gem-bundle so we do not have to redefine them.
instance_eval File.read('slow-gems')

gem 'flay'

dockerfile

WORKDIR /app

ADD slow-gems slow-gems.lock .ruby-version /app/
RUN bundle install --gemfile=slow-gems

ADD Gemfile Gemfile.lock /app/
RUN bundle install

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

Второй bundle install будет повторно использовать уже установленный гем из slow-gems -файл, это занимает меньше секунды.

Adition: Не забудьте использовать встроенное кэширование docker, иначе это не будет быстрее и не помогает тебе.

0 голосов
/ 14 апреля 2020

Вы можете использовать пакет параметров install --deployment или --path, чтобы указать папку, в которую вы можете установить ваши гемы (создайте контейнер только для этой цели, а затем скопируйте папку за пределы docker). Затем сопоставьте этот каталог как том в вашем контейнере, запустив пакетную установку после сопоставления ... или просто скопируйте папку :

# outside actual image

bundle install --path=vendor/cache

# actual docker image
COPY . /app
COPY vendor/cache /app/vendor/cache
COPY .bundle /app/.bundle 

WORKDIR /app

RUN bundle install --path=vendor/cache

Команда с --path = vendor / cache генерирует конфигурацию пакета так же, как эта:

---
BUNDLE_DEPLOYMENT: "true"
BUNDLE_PATH: "vendor/cache"

Пока ваши версии скомпилированных расширений не изменяются в вашем Gemfile, их не следует устанавливать снова.

Чтобы не фиксировать папку vendor / cache в исходных файлах, вы можете разместить ее где-нибудь и попросить разработчиков загрузить ее. Я думаю, где вы могли бы оставить эту папку и как скопировать ее в изображение, это довольно открытый вопрос, и мне нужно больше информации о вашей настройке, чтобы что-то порекомендовать. Где именно вы развертываете свое приложение в работе?

ПРИМЕР:

AWS лямбда-гемы с собственными расширениями представляют проблему - вы можете установить их внутри своей системы ОС, но они не будут совместимы с лямбда-окружением.

Подход к созданию работающего комплекта гемов заключается в следующем:

1 - используйте контейнер для установки самоцветов с собственными расширениями способом, совместимым с лямбда-выражением:

docker run --rm -v "$PWD":/var/task lambci/lambda:build-ruby2.7 bundle install --deployment

2 - Затем, в другом контейнере, вы СОЗДАЕТЕ КАМНИ как том или копируете их и запускаете приложение

docker run --rm --env-file=.env -v $PWD:/var/task:ro,delegated lambci/lambda:ruby2.7 send.lambda_handler

Я предлагаю вам сделать нечто подобное для вашего приложения - использовать один образ для построения гемов вашей платформы, а затем другой для запуска приложения, передавая эти гемы ему. Пока эти два образа являются одной и той же ОС, гемы будут совместимы.

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

...