30113011tr
@30113011tr (田畑 綾也)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

connect() to unix:///app/tmp/sockets/puma.sock failed (2: No such file or directory)を解決したい

解決したいこと

ECS Fargateを用いてRails + Nginxで構成したアプリをデプロイしています。
しかしNginxがpuma.sockを参照できず困っています。

発生している問題・エラー

デプロイした時の、NginxコンテナのCloudWatchログ

connect() to unix:///app/tmp/sockets/puma.sock failed 
(2: No such file or directory) while connecting to upstream, 
client: 10.0.15.207, server: ALBエンドポイント, request: "GET / HTTP/1.1",
upstream: "http://unix:///app/tmp/sockets/puma.sock:/", host: "10.0.18.246"

Nginxログ全体


[notice] 1#1: using the "epoll" event method

[notice] 1#1: nginx/1.25.0

[notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)

[notice] 1#1: OS: Linux 5.10.179-166.674.amzn2.x86_64

[notice] 1#1: getrlimit(RLIMIT_NOFILE): 65535:65535

[notice] 1#1: start worker processes

[notice] 1#1: start worker process 7

2023-06-04T10:05:16.747+09:00

2023/06/04 01:05:16 [crit] 7#7: *2 connect() to unix:///app/tmp/sockets/puma.sock failed (2: No such file or directory) while connecting to upstream, client: 10.0.26.206, server: to-do-app-prod-557176862.ap-northeast-1.elb.amazonaws.com, request: "GET / HTTP/1.1", upstream: "http://unix:///app/tmp/sockets/puma.sock:/", host: "10.0.12.172"
2023/06/04 01:05:16 [crit] 7#7: *2 connect() to unix:///app/tmp/sockets/puma.sock failed (2: No such file or directory) while connecting to upstream, client: 10.0.26.206, server: to-do-app-prod-557176862.ap-northeast-1.elb.amazonaws.com, request: "GET / HTTP/1.1", upstream: "http://unix:///app/tmp/sockets/puma.sock:/", host: "10.0.12.172"

また、問題なのかわからないのですがRailsコンテナのログをみると起動時にunix:///app/tmp/sockets/puma.sockという記述がありませんでした。
スクリーンショット 2023-06-04 9.19.47.png

こちらの記事を見ると、unix:///app/tmp/sockets/puma.sockとログが出てるので、Railsコンテナで指定のファイルパスでpumaが動作していないことが原因でしょうか?

該当するソースコード

nginx.conf
..
..
pid /var/run/nginx.pid;
http {
    upstream app {
      # ソケット通信したいのでpuma.sockを指定
      server unix:///app/tmp/sockets/puma.sock;
    }
    include /etc/nginx/conf.d/*.conf;
    ..
    ..
}
nginx/default.conf

server {
    listen 80 default_server;
    server_name ALBエンドポイント;

    root /app/public;
    location / {
      proxy_pass http://app;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
puma.rb
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

plugin :tmp_restart

app_root = File.expand_path('..', __dir__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"
Dockerfile
FROM ruby:3.2.1 AS base 

WORKDIR /app 
ENV RAILS_ENV production
ENV NODE_MAJOR_VERSION 14
ENV BUNDLE_PATH vendor/bundle
ENV BUNDLE_WITHOUT development:test
RUN gem update --system && gem install bundler:2.4.8
RUN mkdir -p tmp/pids
RUN mkdir -p tmp/sockets

#builder
FROM base AS builder 
RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR_VERSION.x | bash - && \
    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list && \
    apt-get update -qq && \
    apt-get install -y --no-install-recommends \
    vim locales build-essential curl libpq-dev libmariadb-dev nodejs yarn nginx sudo

#bundle
FROM builder AS bundle
COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs=4 --retry=3 && rm -rf $BUNDLE_PATH/ruby/3.2.1/cache/*

#yarn
FROM builder AS yarn
COPY package.json yarn.lock ./
RUN yarn install --production --frozen-lockfile && yarn cache clean 

#main
FROM builder AS main 
COPY . /app
COPY --from=bundle /app/vendor/bundle /app/vendor/bundle 
COPY --from=yarn /app/node_modules /app/node_modules
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true bundle exec rails webpacker:install
RUN NODE_ENV=production ./bin/webpack

COPY docker/production/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

VOLUME ["/app/public"]
VOLUME ["/app/tmp"]
CMD bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb"
Dockerfile.nginx
FROM nginx:1.25

RUN rm -f /etc/nginx/conf.d/* /etc/nginx/nginx.conf
ADD ./nginx/nginx.conf /etc/nginx/nginx.conf
ADD ./nginx/default.conf /etc/nginx/conf.d/default.conf
CMD ["/usr/sbin/nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
entrypoint.sh
#!/bin/bash
set -e 
rm -f /app/tmp/pids/server.pid
RAILS_ENV=production bin/rails db:create
RAILS_ENV=production bin/rails db:migrate
exec "$@"

ECS Fargate

task_definition.json

こちらのドキュメントを参考にバインドマウントを実装しました。

{
    "family": "to_do_app-prod",
    "containerDefinitions": [
        {
            "name": "to_do_app-prod",
            "image": "943726312182.dkr.ecr.ap-northeast-1.amazonaws.com/to_do_app-prod:latest",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "to_do_app-prod-3000-tcp",
                    "containerPort": 3000,
                    "hostPort": 3000,
                    "protocol": "tcp",
                    "appProtocol": "http"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "RAILS_ENV",
                    "value": "production"
                },
                {
                    "name": "RAILS_MASTER_KEY",
                    "value": "b30430bbe41e498a955b3900833032e9"
                },
                {
                    "name": "DB_USERNAME",
                    "value": "admin"
                },
                {
                    "name": "DB_HOST",
                    "value": "to-do-app-database-1.chfsoner1ldd.ap-northeast-1.rds.amazonaws.com"
                },
                {
                    "name": "DB_PASSWORD",
                    "value": "30113011tr"
                }
            ],
            "mountPoints": [
                {
                    "sourceVolume": "public",
                    "containerPath": "/app/public",
                    "readOnly": false
                },
                {
                    "sourceVolume": "tmp",
                    "containerPath": "/app/tmp",
                    "readOnly": false
                }
            ],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "to_do_app-nginx",
                    "condition": "START"
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-create-group": "true",
                    "awslogs-group": "/ecs/to_do_app-prod",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                }
            }
        },
        {
            "name": "to_do_app-nginx",
            "image": "943726312182.dkr.ecr.ap-northeast-1.amazonaws.com/to_do_app-nginx:latest",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "to_do_app-nginx-80-tcp",
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp",
                    "appProtocol": "http"
                }
            ],
            "essential": true,
            "environment": [],
            "mountPoints": [
                {
                    "sourceVolume": "public",
                    "containerPath": "/app/public",
                    "readOnly": false
                },
                {
                    "sourceVolume": "tmp",
                    "containerPath": "/app/tmp",
                    "readOnly": false
                }
            ],
            "volumesFrom": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-create-group": "true",
                    "awslogs-group": "/ecs/to_do_app-prod",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                }
            }
        }
    ],
    "executionRoleArn": "arn:aws:iam::943726312182:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "volumes": [
        {
            "name": "public",
            "host": {}
        },
        {
            "name": "tmp",
            "host": {}
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "1024",
    "memory": "3072",
    "ephemeralStorage": {
        "sizeInGiB": 21
    },
    "runtimePlatform": {
        "cpuArchitecture": "X86_64",
        "operatingSystemFamily": "LINUX"
    }
}

コンソール画面

Railsコンテナ
スクリーンショット 2023-06-04 9.43.12.png
スクリーンショット 2023-06-04 9.43.53.png
スクリーンショット 2023-06-04 9.44.31.png

Nginxコンテナ

スクリーンショット 2023-06-04 9.48.44.png
スクリーンショット 2023-06-04 9.45.13.png
スクリーンショット 2023-06-04 9.45.25.png
スクリーンショット 2023-06-04 9.45.40.png

ボリュームの設定をしているはずなのにボリュームソースが無い?

Railsコンテナ
スクリーンショット 2023-06-04 10.08.09.png
Nginxコンテナ
スクリーンショット 2023-06-04 10.05.42.png

ドキュメントによるとソースコンテナの指定は以下のようにすればいいとのことでしたが、EC2の場合のみでFargateでは出来ないみたいでした...

task_definition.json
      "volumesFrom": [
        {
          "sourceContainer": "web"
        }

自分で試したこと

  • task_definition.jsonでsource_pathを追加してみましたが、Fargateではサポートしていないとエラーが出ました。
task_definition.json
   "volumes": [
        {
            "name": "public",
            "host": {
                "sourcePath": "/app/public"
            }
        },
        {
            "name": "tmp",
            "host": {
                "sourcePath": "/app/tmp"
            }
        }
    ]
Fargate compatible task definitions do not support sourcePath
  • nginx.confのupstreamで、直接Railsコンテナを参照するようにしてみました。
nginx.conf
     upstream app {
       server to_do_app-prod:3000;  #Railsコンテナ名:Railsコンテナポート番号
     }

     upstream app {
       server to_do_app-prod-3000-tcp:3000;  #Railコンテナポート名:Railsコンテナポート番号
     }

エラー

nginx: [emerg] host not found in upstream "to_do_app-prod:3000" in /etc/nginx/nginx.conf:20
nginx: [emerg] host not found in upstream "to_do_app-prod-3000-tcp:3000" in /etc/nginx/nginx.conf:20
  • nginx.confのlocationを変更しましたがエラー内容に変化はありませんでした。
nginx.conf
    location / {
      try_files $uri $uri/index.html $uri.html @puma;
    }
    location @puma {
      proxy_set_header    Host $http_host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-Host $host;
      proxy_set_header    X-Forwarded-Server $host;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://app;
    }
  • puma.socketのパスを変更しましたが変化はありませんでした。
nginx.conf
    upstream app {
      server unix:///usr/src/app/tmp/sockets/puma.sock;
    }

最後に

馬鹿な話ですがこの作業だけで4日も停滞しています。以下の参考サイトを見ながらやっているのですが解決の兆しが見えません...。そもそも上記のやり方は、Fargateでサポートされていないのでしょうか?
それともどこか間違いがあるのでしょうか?わかる方がいらっしゃいましたらご教授していただきたいです。よろしくお願いします。

参考

FargateにRailsをデプロイする (CI/CDまでの道⑦)
AWS FargateにRailsアプリケーションをデプロイする手順
【ポートフォリオをECSで!】Rails×NginxアプリをFargateにデプロイするまでを丁寧に説明してみた(VPC作成〜CircleCIによる自動デプロイまで) 前編
AWS CDKでRailsアプリをECS(on Fargate)にデプロイしてみる

0

1Answer

2: No such file or directory
puma.sockのファイルが無いです。

pumaとnginxを別々のコンテナで運用してませんか?unix socketを利用するなら同一コンテナにpumaとnginxを入れましょう!

別々のコンテナで運用ならtcpで
tcpでもそこそこpumaは速いですよ!
また、nginxでhash分散するためにもtcpを推奨します。

upstream app {
   ip_hash;
   server 10.20.30.40:8080;
   server 10.20.30.41:8080;
}

1Like

Your answer might help someone💌