Heroku에 컨테이너화된 NginX를 배치하는 것은 얼마나 어려운가?

저는 지금 공부하고 있습니다Docker MOOC course.이 과정의 세 번째 부분에서 CI/CD 파이프를 사용하여 정지 소프트웨어를 Heroku에 배치하는 연습이 있습니다.소프트웨어는 무엇이든 할 수 있기 때문에 저는 과정 자료를 배치하고 Github 조작을 사용하여 배치하기로 결정했습니다.내가 보기에 Github Actions의 사용은 매우 간단해서 나는 이것에 대해 아무런 문제가 없다.반대로 히로쿠에서 쓸만한 재료를 얻기 위해 문제가 생겼어요.이 블로그에서 저는 여러분과 제가 직면한 도전을 공유하고 제가 이 도전들을 어떻게 해결했는지 알려드리고 싶습니다.

교과 과정 재료 및 그것들이 어떻게 만들어졌는지
따라서 과정 자료는 사용Jekyll으로 구축된 간단한 사이트이다.이 사이트는 컨테이너화되어 있기 때문에 Dockerfilein the course material repository이 이미 있다.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에서 볼 수 있듯이 1단계에서는 Jekyll image를, 2단계에서는 NginX를 사용합니다.저장소에는 NginX에 대한 구성이 없으므로 기본 구성 파일만 사용합니다.

NginX와 Heroku의 질문입니다.
NginX는 광범위하게 사용되는 웹 서버로 부하 균형기나 역방향 에이전트를 충당할 수 있다.
역방향 에이전트로서 클라이언트의 요청을 받아들여 서버로 전송합니다.이렇게 하면 클라이언트는 서버 자체와 통신하지 않을 것이다. 왜냐하면 프록시 서버는 서버가 아니라 인터넷을 향하기 때문이다.그것 또한 부하 균형기를 충당하여 여러 서버가 있는 상황에서 클라이언트로부터 요청을 서로 다른 서버로 고르게 보낼 수 있다.
이 예에서 NginX는 기본 웹 서버로 사용되며 jekyll build 명령을 사용하여 생성된 정적 페이지에 서비스를 제공한다.
Heroku는 PaaS(플랫폼 즉 서비스)로서 소프트웨어를 배치하고 이를 클라우드에 위탁 관리할 수 있습니다.그것은 다양한 프로그래밍 언어를 지원하고, 도커 용기도 지원한다.
기본적으로 NginX 스니퍼 포트는 80입니다.현재, 노트북에 로컬로 docker 이미지를 만들고 명령 docker run -p 8080:80 docker-course-material 을 사용하여 실행할 때, 브라우저에서localhost: 8080을 열면 수업 자료를 표시할 수 있습니다.현재 내가 처음으로 이 자료들을 히로쿠에 배치했을 때 히로쿠에 배치한 것은 성공했지만 사이트를 열면 문제가 생겼다는 메시지가 나온다.로그에서 오류가 발생했습니다.
State changed from starting to crashed
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
구글에서 한동안 검색한 후에, 나는 Heroku가 응용 프로그램을 배치할 때 웹 응용 프로그램에 무작위 포트를 분배하는 것을 발견했다.그것은 the Heroku documentation에서 말했다

Each web process simply binds to a port, and listens for requests coming in on that port. The port to bind to is assigned by Heroku as the PORT environment variable.


이것은 NginX가 Heroku가 응용 프로그램에 할당한 무작위 포트를 감청하도록 해야 한다는 것을 의미한다.나는 어떻게 해야만 이 점을 해낼 수 있습니까?

솔루션의 첫 번째 버전
데이터 공학에 들어가기 전에 소프트웨어 개발자였지만 NginX에 대한 경험이 전혀 없었다는 것을 명확히 하겠습니다.그러나 다른 포트를 감청할 수 있도록 설정 파일을 만들어야 한다는 것을 깨달았다.나의 첫 번째 목표는 로컬 8080과 같은 다른 포트를 감청하도록 하는 것이다. 그러면 나는 설정을 테스트할 수 있다.
NginX 사용 경로/etc/NginX/conf.d/default의 구성 파일을 읽었습니다.나의 첫 번째 해결 방안은 부모 이미지에 추가된 기본 파일을 바꾸고 이 파일에 다른 포트를 정의하는 프로필을 만드는 것이다.구성에 조금 애를 먹었지만 구성 파일의 첫 번째 작업 버전(하드 코딩 포트가 있음)은 다음과 같습니다.
server {
  listen 0.0.0.0:8080;

  location / {
    root /usr/share/nginx/html;
    index index.html;
  }   
}
listen 0.0.0.0:8080;가 있는 줄은 NginX가 localhost와 포트 8080을 수신한다고 알려줍니다.Dockerfile에서 구성 파일을 복사한 후 포트 8080에 바인딩하여 해당 자료에 액세스할 수 있습니다.하지만 히로쿠의 문제는 해결되지 않았다.

바인딩 포트 환경 변수
따라서, 현재 포트를 8080으로 성공적으로 변경했습니다. Heroku에서 포트를 분배할 때 포트를 동적으로 정의하는 방법을 알아야 합니다.하드코딩 포트 번호만 사용할 수 없고, 자리 차지 문자를 사용해서 용기가 실행될 때 바꿔야 합니다.
그래서 나는 설정에서 하드코딩된 8080을 $PORT로 바꾸었고, Dockerfile에 코드를 한 줄 추가해서 환경 변수로 바꾸었다.런타임에 완료해야 하기 때문에 유일한 선택은 CMD를 사용하는 것입니다.Heroku가 설정한 환경 변수 PORT는 컨테이너가 시작될 때만 사용할 수 있으므로 RUN 명령을 파일에서 사용할 수 없습니다.RUN 명령은 빌드할 때 한 번 실행됩니다.
환경 변수의 값으로 자리 표시자를 바꾸기 위해서 sed s 명령을 사용했습니다.Sed는 텍스트를 변환할 수 있는 간단한 흐름 편집기입니다.sed s는 가장 흔한sed 명령일 수 있으며 정규 표현식으로 텍스트를 다른 텍스트로 바꿀 수 있습니다.
sed 명령 예sed -i 's/cat/dog/g input-file.txt'파일 입력 파일에 나타나는 모든 문자열cat을 문자열dog로 바꿉니다.txt.옵션 -i 는 교체가 완료되었음을 나타냅니다.

최종 버전
마지막으로 구성 파일은 다음과 같습니다.
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 값으로 대체합니다.Docker를 사용할 때, NginX가 프런트에 있고 용기가 바로 멈추지 않도록 마지막 명령 nginx -g 'daemon off' 을 사용해야 합니다.
마지막으로 내가 지적해야 할 것은 내가 겪는 문제는 사실상 NginX에 특정된 것이 아니라 Heroku에 특정된 것이다.이 문제는 모든 웹 서버와 Heroku에서 발생할 수 있습니다. Heroku가 분배한 포트를 연결해서 해결해야 합니다.나는 단지 공교롭게도 NingX에서 처음으로 이 문제를 만났을 뿐이다.
해결 방안은 매우 간단하지만, 나는 몇 시간을 써서 이 문제를 해결하려고 했다.만약 네가 확실히 이 문제에 부딪혔다면, 나는 이 박문이 도움이 될 수 있기를 바란다.

좋은 웹페이지 즐겨찾기