GKEでRails5(puma)+nginxのDeployment

Google Kubernetes Engine で Rails5 のアプリケーションを動かすための記事です。

puma + nginx をソケットで繋げて動かします。http から https にリダイレクトしたりするために nginx をリバースプロキシとして置いておくと、なにかと便利です。

Rails アプリケーションと nginx のコンテナをそれぞれ別に作って、同じポッド内で動かします。共有ボリュームにソケットファイルを置くことで、ふたつを繋げます。この記事では、この点について説明します。

puma + nginx の連携に関する詳しいことは、その他の記事などを参考にしてください。この記事の最後に、参考リンク一覧があります。


nginx の設定
-----------

まずは、nginx の設定です。`server unix:///app/myapp/sockets/puma.sock;`の部分が重要です。

このあと、ソケットファイルを置くための共有ボリュームの作成について説明します。その共有ボリュームを nginx コンテナ上の`/app/myapp/sockets`にマウントしています。

なので、マウントするパスを変える場合は、この設定を変える必要があります。

```nginx:/etc/nginx/conf.d/default.conf
upstream puma {
  server unix:///app/myapp/sockets/puma.sock;
}

server {
    listen 80;
    server_name puma;

    location / {
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://puma;
    }
}
```

Rails5 の設定
------------

つぎに、Rails の設定です。`RAILS_ROOT/config/puma.rb`を修正します。ソケットでの接続のために`RAILS_ROOT/tmp/sockets/puma.sock`を作成するようにする、よくあるやつです。

「[Rails5でpuma + nginx連携](https://qiita.com/mzn/items/50bb45263698006a6577)」を参考にしました。

これも、bind の値を変える場合は、このあとの設定も変える必要があります。

```ruby:RAILS_ROOT/config/puma.rb
# port ENV.fetch("PORT") { 3000 }
...
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
```


Deployment の設定
----------------

さいごに、Deployment の設定です。関係ない設定も多いですが、今回は、コメントをつけた、[1]、[2]、[3]の部分が関係あります。

myapp が Rails アプリケーションのコンテナ、myapp-nginx が nginx のコンテナです。

[1] の volumes の設定で、共有ボリュームが作成されるようにます。

[2] の volumeMounts の設定で、nginx コンテナ上の`/app/myapp/sockets`に共有ボリュームをマウントしています。name には [1] の name を指定します。この例では sockets です。

[3] も [2] と同じ要領で Rails アプリケーションのコンテナ上の`/app/myapp/tmp/sockets`に共有ボリュームをマウントしています。

この設定で、Rails アプリケーションと nginx の、それぞれ別々のコンテナが同じ puma.sock を参照することができ、連携が可能になります。

```yaml:myapp-deployment.yaml
apiVersion: "extensions/v1beta1"
kind: "Deployment"
metadata:
  name: "myapp"
  namespace: "default"
  labels:
    app: "myapp"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: "myapp"
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: "myapp"
    spec:
      # [1]
      volumes:
      - name: "sockets"
        emptyDir: {}
      containers:
      - name: "myapp-nginx"
        image: "asia.gcr.io/[PROJECT_NAME]/myapp-nginx:latest"
        # [2]
        volumeMounts:
        - name: "sockets"
          mountPath: "/app/myapp/sockets"
        livenessProbe:
          httpGet:
            scheme: HTTP
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
      - name: "myapp"
        image: "asia.gcr.io/[PROJECT_NAME]/myapp:latest"
        # [3]
        volumeMounts:
        - name: "sockets"
          mountPath: "/app/myapp/tmp/sockets"
        envFrom:
        - configMapRef:
            name: myapp-env-config
        - secretRef:
            name: myapp-env-secret
```

おしまい。

参考
---

* [Rails5でpuma + nginx連携](https://qiita.com/mzn/items/50bb45263698006a6577)
* [nginxで unix ドメイン socket をlisten してバックエンド専用に設定する。](http://takuya-1st.hatenablog.jp/entry/2018/01/13/214349)
* [Kubernetesによる同一ポッド内の共有ボリュームを介したコンテナ間通信](https://qiita.com/mamorita/items/c0c937bba52aae7253ee)