Я в настоящее время беру 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»