LoginSignup
14
14

More than 5 years have passed since last update.

Google Container Engine上のRailsアプリにnginxを挟む

Posted at

背景

の続きです。
今回は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側のコンテナとsocketを共有するため(publicもついでに)、ボリュームをマウントする必要があります。
空のボリュームをマウントするため、元々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"

serviceの設定

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

両方のpushが完了したら、serviceとdeploymentを更新します。

kubectl apply -f deployment.yml
kubectl delete svc testapp
kubectl apply -f service.yml

なお、誰も使っていないサービスなのでdeleteをしていますが、ダウンタイムが発生するので普通のサービスではちゃんとRolling Updateなどをする必要があります。

一向にExternal IPが振られない場合、↓のコマンドで詳細を確認してみてください。
Static IPの制限に引っかかっているとExternal IPが振られない、という事態になるため、古いIPは削除するなりしてください。

kubectl describe svc

さて、podやsvcが正常に立ち上がったら、80番にアクセスしてみましょう。
以前と変わらない画面が出てくれば成功です:tada:

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14