Рубрики
Uncategorized

Развертывание контейнерных Nginx в Heroku — как сильно это может быть?

В настоящее время я принимаю курс Docker MOOC. В части 3 курса есть упражнение о развертывании … Tagged с Docker, Heroku, Nginx, Devops.

Я в настоящее время беру Docker MOOC курс Отказ В части 3 курса есть упражнение о развертывании докеренного программного обеспечения для Heroku с CI/CD-трубопроводом. Программное обеспечение может быть чем угодно, поэтому я решил развернуть материалы курса и использовать действия GitHub, чтобы сделать развертывание. Действия GitHub были очень простыми, чтобы использовать на мой взгляд, и у меня не было проблем с этим. Вместо этого я бежал в некоторые проблемы, чтобы получить материалы, доступные в Героку. В этом посте в блоге я подумал, что поделись проблемами, с которыми я столкнулся, и сказал, как я решил их.

Материалы курса и Как они построены

Таким образом, материал курса — простой веб-сайт, построенный с Jekyll Отказ Веб-сайт был контейнерен, поэтому у него уже было докерафила В репозитории материала курса . Я развел репозиторий, чтобы иметь возможность настроить для него трубопровод CI/CD и развернуть его к Heroku. DockerFile, который уже существовал в репозитории курса, выглядит так:

FROM jekyll/jekyll:3.8.3 as build-stage

WORKDIR /tmp

COPY Gemfile* ./

RUN bundle install

WORKDIR /usr/src/app

COPY . .

RUN chown -R jekyll .

RUN jekyll build

FROM nginx:alpine

COPY --from=build-stage /usr/src/app/_site/ /usr/share/nginx/html

Поэтому из DockerFile вы видите, что он использует многоступенчатую сборку: в первом этапе он использует Jekyll Image, а во второй фазе Nginx. Репозиторий не содержит никакой конфигурации для Nginx, поэтому он просто использует файл конфигурации по умолчанию.

Проблема с Nginx и Heroku

Nginx Это широко используемый веб-сервер, который также может действовать, например, как балансировщик нагрузки или обратный прокси. Как обратный прокси, требуется запрос, исходящий с клиента и пересылает его на сервер. Таким образом, клиент не связывается с самим сервером, потому что прокси находится в Интернете, а не сервер. Он также может действовать как балансировщик нагрузки и равномерно отправлять запросы от клиентов на разных серверах, если есть несколько. В этом случае nginx используется в качестве основного веб-сервера, обслуживая статические страницы, созданные с Jekyll Build команда.

Heroku это PAAS (платформа как услуга), где вы можете развернуть ваше программное обеспечение и разместить его в облаке. Он поддерживает несколько языков программирования, а также контейнеры докера.

По умолчанию Nginx слушает порт 80. Теперь, когда я построю изображение докера локально на моем ноутбуке, а затем запустить его с помощью команды Docker Run -P 8080: 80 Docker-Tource-Material Я могу открыть localhost: 8080 в браузере, и это отобразит материалы курса. Теперь, когда я впервые развернул материалы к Heroku, развертывание Героку прошло успешно, но открытие сайта показало сообщение о том, что что-то пошло не так. Я заметил ошибку в журналах:

State changed from starting to crashed
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)

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

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

Это означает, что мне нужно сделать NGINX слушать случайный порт, который Heroku назначает для приложения. Как я могу сделать это?

Первая версия решения

Позвольте мне быть понятно, хотя я работал разработчиком программного обеспечения до того, как я пошел в технику для данных, у меня не было опыта в Nginx Whatsoe. Однако я понял, что мне пришлось создать файл конфигурации для этого, чтобы он слушал другой порт. Моя первая цель состояла в том, чтобы она слушала какой-то другой порт, такой как 8080 локально, чтобы я мог проверить конфигурацию.

Я прочитал, что nginx использует файл конфигурации в пути/etc/nginx/Conf.d/default.conf. Мое первое решение состояло в том, чтобы создать файл конфигурации, который заменил бы, добавил добавить родительское изображение файла по умолчанию, и что в файле был определен другой порт. Я немного боролся с конфигурацией, но первая рабочая версия файла конфигурации с HardCoded Port выглядит так:

server {
  listen 0.0.0.0:8080;

  location / {
    root /usr/share/nginx/html;
    index index.html;
  }   
}

Линия с Слушать 0.0.0.0:8080; Рассказывает Nginx прослушать localhost и порт 8080. После копирования файла конфигурации в DockerFile я смог привязать к порту 8080 и получить доступ к материалам. Это не решило проблему с Heroku, хотя.

Переменная среды связывания порта

Так что теперь, когда мне удалось перейти на порт до 8080, мне все равно нужно выяснить, как динамически определить порт, когда Heroku назначает это. Затем я не мог просто жесткокодировать номер порта, но вместо этого мне нужно использовать какой-нибудь заполнитель и заменить его, когда контейнер работает.

Поэтому я заменил жесткозедированный 8080 в конфигурацию с $ Port и добавил строку в DockerFile, которая заменит ее с переменной среды. Поскольку нужно было сделать во время выполнения, единственный вариант должен был использовать CMD. Я не мог использовать команду запуска в файле, потому что портретный портретный порт Heroku доступен только при запуске контейнера. Запуск команды выполняется один раз в строю времени.

Для замены заполнителя ценность переменной среды я использовал Sed S команда. SED — это простой редактор потока и может использоваться для преобразования текста. Sed S. Вероятно, для наиболее часто известной команды SED, и его можно использовать для замены текста каким-то другим, используя регулярное выражение. Пример команды SED S Sed -i 'S/Cat/Dog/G input-file.txt ' Заменяет все вхождения строкового кота со струнной собакой в файл ввод-файл.txt. Опция — Я означает, что замена выполняется на месте.

Окончательный вариант

Так что в конце конфигурация так выглядит файл конфигурации:

server {
  listen 0.0.0.0:$PORT;

  location / {
    root /usr/share/nginx/html;
    index index.html;
  }   
}

И вот как выглядит DockerFile:

FROM jekyll/jekyll:3.8.3 as build-stage

ARG PORT

WORKDIR /tmp

COPY Gemfile* ./

RUN bundle install

RUN echo $PORT

WORKDIR /usr/src/app

COPY . .

RUN chown -R jekyll .

RUN jekyll build

FROM nginx:alpine

COPY --from=build-stage /usr/src/app/_site/ /usr/share/nginx/html

COPY nginx.conf /etc/nginx/conf.d/default.conf

CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'

DockerFile имеет только две новые строки: копирование файла конфигурации Nginx и замена заполнителя за счет значение $ Port. Окончательная команда NGINX -G 'демон от' Нужен, когда используется Docker, так что Nginx остается на переднем плане, а контейнер не прекращается немедленно.

Окончательная вещь, которую мне нужно упомянуть, заключается в том, что проблема, которую я столкнулся, это не, на самом деле, на самом деле, специфичный NGINX, а скорее, специфичный Heroku. Эта проблема может возникнуть с любым веб-сервером и Heroku и должна быть решена путем привязки к порту, которое назначает Heroku. Я просто случайно встречал эту проблему впервые с Nginx.

Решение довольно простое, но мне удалось использовать пару часов с этой проблемой. Если вы столкнулись с проблемой, я надеюсь, что этот пост блога помогает!

Оригинал: «https://dev.to/levelupkoodarit/deploying-containerized-nginx-to-heroku-how-hard-can-it-be-3g14»