Google Container Engine의 Rails 앱에 nginx 끼우기

배경


  • 마지막 기사
  • 지난번 기사

  • 계속됩니다.
    이번에는 nginx를 통해 Rails에 액세스하도록 구성을 변경합니다.

    덧붙여 제 경우에는 https화의 일환으로 nginx를 끼울 필요가 있었으므로 했습니다.

    절차



    지난번 , 전회 의 순서에 따라 구축을 한 것으로 합니다.

    nginx의 Docker 이미지



    이번 준비하는 nginx는, 이하의 처리를 실시하도록 설정 파일을 기입합니다.
  • 80번에 온 http 액세스를 처리
  • $http_x_forwarded_proto가 "http"이면 "https"의 동일한 페이지로 리디렉션
  • (좋아하는) "/public/..."에 오면 그대로 반환
  • 그렇지 않으면 unix:///myapp/tmp/sockets/puma.sock를 통해 Rails에 전달

  • 후술하는 설정과 일치하면, 소켓 파일의 위치는 자유입니다.

    샘플은 ↓입니다.
    원하는 설정을 추가하십시오.
    upstream myapp {
      server unix:///myapp/tmp/sockets/puma.sock;
    }
    
    server {
      listen 80;
      server_name your.domain;
    
      if ($http_x_forwarded_proto = "http") {
          return 301 https://$host$request_uri;
      }
    
      root /myapp/public;
    
      location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    
        if (!-f $request_filename) {
          proxy_pass http://myapp;
          break;
        }
      }
    }
    

    이 파일을 nginx.conf로 nginx 용 Dockerfile과 함께 nginx 폴더에 넣습니다.
  • nginx
  • Dockerfile
  • nginx.conf


  • Dockerfile에서는 설정 파일을 복사하여 사용할 이미지를 만드십시오.
    FROM nginx:1.11.7
    RUN rm -f /etc/nginx/conf.d/*
    ADD nginx.conf /etc/nginx/conf.d/app.conf
    CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
    

    Rails 조정



    nginx 이미지를 사용하여 컨테이너를 세우도록 deployment.yml에 추가합니다.

    그러나 Rails 측 컨테이너와 소켓을 공유하기 때문에 (공개도 마침내) 볼륨을 마운트해야합니다.
    빈 볼륨을 마운트하기 때문에 원래 public에 들어 있던 것이 사라져 버리므로 Rails의 Dockerfile을 고안하고 회피합니다.

    이번에는 사전에 내용을/tmp로 옮기고 마운트된 후 복사하는 고육의 책을 취했습니다.
    해결 방법은 프로젝트에 따라 다르므로 원하는 방법을 적용하십시오.

    잊지 말고 시작에 socket을 사용하십시오.
    ...
    # 逃がす
    RUN mkdir -p /tmp/public && \
        cp -rf /myapp/public/* /tmp/public
    ...
    # 戻す
    CMD \
        bundle exec rails db:migrate \
        && cp -rf /tmp/public/* /myapp/public \
        && bundle exec puma -C config/puma.rb
    
    config/puma.rb에 다음을 추가합니다.
    app_root = File.expand_path('../..', __FILE__)
    bind "unix://#{app_root}/tmp/sockets/puma.sock"
    

    서비스 설정



    nginx를 사이에 두고 있으므로, 80번으로 액세스하지 않으면 안됩니다.service.yml의 3000을 80으로 다시 씁니다.
    apiVersion: v1
    kind: Service
    metadata:
      name: testapp
      labels:
        app: testapp
    spec:
      type: LoadBalancer
      ports:
        - port: 80
      selector:
        app: testapp
    

    deployment 설정



    deployment.yml은 볼륨 마운트 설정과 nginx 컨테이너 설정을 추가합니다.
    간단하네요.
    ...
        spec:
          containers:
            - image <Railsのimage>
              ...
    
    ########### 追記 #############
              volumeMounts:
                - mountPath: /myapp/public
                  name: web-assets
                - mountPath: /myapp/tmp/sockets
                  name: web-sock
    ########### おわり ############
    
            - image: <Cloud SQL Proxyのimage>
              ...
    
    ########### 追記 #############
            # [START nginx]
            - name: nginx
              image: asia.gcr.io/<Your Project ID>/nginx:latest
              ports:
                - name: http-server
                  containerPort: 80
                - name: https-server
                  containerPort: 443
              volumeMounts:
                - mountPath: /myapp/public
                  name: web-assets
                  readOnly: true
                - mountPath: /myapp/tmp/sockets
                  name: web-sock
            # [END nginx]
    
          # [START volumes]
          volumes:
            - name: web-assets
              emptyDir: {}
            - name: web-sock
              emptyDir: {}
    ########### おわり ############
            - name: cloudsql-oauth-credentials
              secret:
                secretName: cloudsql-oauth-credentials
            - name: ssl-certs
              hostPath:
                path: /etc/ssl/certs
          # [END volumes]
    

    배포



    드디어 큰 포장입니다.

    Rails의 Docker 이미지, nginx의 Docker 이미지를 빌드하고 push합니다.
    절차는 이전과 동일합니다.
    IMAGE_ID=$(docker build --no-cache -q .)
    url_base="asia.gcr.io/<Your Project ID>/app"
    docker tag ${IMAGE_ID} ${url_base}:latest
    gcloud docker -- push ${url_base}:latest
    
    IMAGE_ID=$(docker build --no-cache -q ./nginx)
    url_base="asia.gcr.io/<Your Project ID>/nginx"
    docker tag ${IMAGE_ID} ${url_base}:latest
    gcloud docker -- push ${url_base}:latest
    

    두 푸시가 모두 완료되면 서비스와 배포를 업데이트합니다.
    kubectl apply -f deployment.yml
    kubectl delete svc testapp
    kubectl apply -f service.yml
    

    덧붙여 아무도 사용하고 있지 않는 서비스이므로 delete를 하고 있습니다만, 다운타임이 발생하기 때문에 보통의 서비스에서는 제대로 Rolling Update등을 할 필요가 있습니다.

    한쪽으로 External IP가 흔들리지 않는 경우, ↓의 커멘드로 상세를 확인해 보세요.
    정적 IP 제한에 걸리면 External IP가 흔들리지 않기 때문에 이전 IP를 삭제해야합니다.
    kubectl describe svc
    

    그런데 pod나 svc가 정상적으로 일어나면, 80번에 액세스해 봅시다.
    이전과 다르지 않은 화면이 나오면 성공합니다

    좋은 웹페이지 즐겨찾기