質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.20%

GunicornでのDjangoアプリ起動に失敗する

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,149

 概要

現在、DjangoでWebアプリケーションを作るにあたり、DockerとH2O、MariaDBを使ってdocker-compose環境を構築しています。

 発生したエラー

H2OとGunicornでUNIXソケットを使って繋ぐ方法を試しているのですが、ファイルが見つからないというエラーが出てGunicornが起動しません。
エラーのログは以下の通りです。

[2018-10-09 15:30:37 +0000] [284] [INFO] Booting worker with pid: 284
[2018-10-09 15:30:37 +0000] [284] [ERROR] Exception in worker process
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
    worker.init_process()
  File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/base.py", line 134, in init_process
    self.run()
  File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 124, in run
    self.run_for_one(timeout)
  File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 61, in run_for_one
    self.notify()
  File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/base.py", line 69, in notify
    self.tmp.notify()
  File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/workertmp.py", line 43, in notify
    os.fchmod(self._tmp.fileno(), self.spinner)
FileNotFoundError: [Errno 2] No such file or directory
[2018-10-09 15:30:37 +0000] [284] [INFO] Worker exiting (pid: 284)


他の起動手段を試しても、同様のエラーが繰り返し表示されます。

 コード

なお、このコードはGitHubのリポジトリ https://github.com/huideyeren/e-koto-3-server にあげてあります。

H2Oのコンテナはフォークしたリポジトリ https://github.com/huideyeren/h2o-proxy-letsencrypt を使っています。

とりわけ、 docker-compose.yml は以下のようになっています。

version: '3.4'

volumes:
  mysite.db.volume:
    name: mysite.db.volume

services:
  h2o:
    build: ./h2o
    container_name: mysite.h2o
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - "./etc/letsencrypt:/etc/letsencrypt"
      - ./static:/static
      - ./tmp:/tmp
      - ./tmp/django.sock:/tmp/django.sock:ro
    depends_on:
      - webapi
    environment:
      - EMAIL
      - AGREEMENT=yes

  db:
    image: mariadb:10.3
    container_name: mysite.db
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: mysitepass
      TZ: 'Asia/Tokyo'
    volumes:
      - mysite.db.volume:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d

  webapi:
    build: ./webapi
    container_name: mysite.webapi
    command: gunicorn e_koto_3.wsgi --bind=unix:/tmp/django.sock
    volumes:
      - ./src:/code
      - ./static:/static
      - ./tmp:/tmp
      - ./tmp/django.sock:/tmp/django.sock
    expose:
      - "8000"
    depends_on:
      - db

また、 h2o.conf はGoによるテンプレート部分も含めて以下の通りです。

---
user: root
hosts:
  "127.0.0.1.xip.io:80":
    listen:
      host: 0.0.0.0
      port: 80
    access-log: /dev/stdout
    paths:
      /:
        proxy.reverse.url: http://[unix:/tmp/django.sock]/
        proxy.preserve-host: ON
        proxy.timeout.keepalive: 0
      "/static":
        file.dir: /static
  "127.0.0.1.xip.io:443":
    listen:
      host: 0.0.0.0
      port: 443
    access-log: /dev/stdout
    paths:
      /:
        proxy.reverse.url: http://[unix:/tmp/django.sock]/
        proxy.preserve-host: ON
        proxy.timeout.keepalive: 0
      "/static":
        file.dir: /static

{{ define "proxy" }}
      /:
        proxy.preserve-host: ON
        proxy.timeout.keepalive: 0
        {{ if .Address }}
        {{ if (and .Container.Node.ID .Address.HostPort) }}
        proxy.reverse.url: "http://{{ .Container.Node.Address.IP }}:{{ .Address.HostPort }}" 
        {{ else }}
        proxy.reverse.url: "http://{{ .Address.IP }}:{{ .Address.Port }}"
        {{ end }}
        {{ else }}
        proxy.reverse.url: "http://{{ .Container.IP }} down"
        {{ end }}
{{ end }}

{{ define "host" }}
  "{{ .Host }}:{{ .Port }}":
    listen:
      host: 0.0.0.0
      port: {{ .Port }}
      {{ if (and .SSL (exists (printf "/etc/letsencrypt/live/%s/privkey.pem" .Host))) }}
      ssl:
        certificate-file: "/etc/letsencrypt/live/{{ .Host }}/fullchain.pem"
        key-file: "/etc/letsencrypt/live/{{ .Host }}/privkey.pem"
      {{ end }}
    access-log: /dev/stdout
    paths:
      /.well-known/acme-challenge:
        file.dir: /opt/data/{{ .Host }}/.well-known/acme-challenge/
      {{ template "proxy" .Proxy }}
{{ end }}

{{ define "hosts" }}
  {{ if not .Test }}
  {{ template "host" (dict "Host" .Host "Port"  80 "Proxy" .Proxy "SSL" (parseBool "false")) }}
  {{ template "host" (dict "Host" .Host "Port" 443 "Proxy" .Proxy "SSL" (parseBool "true")) }}
  {{ else }}
  {{ template "host" (dict "Host" .Host "Port" 5002 "Proxy" .Proxy "SSL" (parseBool "false")) }}
  {{ template "host" (dict "Host" .Host "Port" 5001 "Proxy" .Proxy "SSL" (parseBool "true")) }}
  {{ end }}
{{ end }}

{{ $ACMETEST := (parseBool (coalesce .Env.ACME_TEST "false")) }}
{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}

{{ if (ne $host "") }}
hosts:
{{ range $container := $containers }}
  {{ $addrLen := len $container.Addresses }}

  {{ if (eq $addrLen 1) }}
  {{ $proxy := (dict "Container" $container "Address" (index $container.Addresses 0)) }}
  {{ template "hosts" (dict "Host" $host "Proxy" $proxy "Test" $ACMETEST) }}
  {{ else }}
  {{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }}
  {{ $addr :=    where $container.Addresses "Port" $port | first }}
  {{ $proxy := (dict "Container" $container "Address" $addr) }}
  {{ template "hosts" (dict "Host" $host "Proxy" $proxy "Test" $ACMETEST) }}
  {{ end }}
{{ end }}

{{ end }}

{{ end }}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

Dockerの問題で、UNIXドメインソケットを生成するパスを /var/sock/gunicorn に変えたら動きました。

docker-compose.yml は以下の通りです。

version: '3.4'

volumes:
  mysite.db.volume:
    name: mysite.db.volume
  gunicorn-run:
    name: gunicorn-run


services:
  h2o:
    build: ./h2o
    container_name: mysite.h2o
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - "./etc/letsencrypt:/etc/letsencrypt"
      - ./static:/static
      - ./sock:/var/sock/gunicorn
      - gunicorn-run:/var/sock
    depends_on:
      - webapi
    environment:
      - EMAIL
      - AGREEMENT=yes

  db:
    image: mariadb:10.3
    container_name: mysite.db
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: mysitepass
      TZ: 'Asia/Tokyo'
    volumes:
      - mysite.db.volume:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d

  webapi:
    build: ./webapi
    container_name: mysite.webapi
    command: gunicorn e_koto_3.config.wsgi:application --bind=unix:/var/sock/gunicorn/django.sock
    volumes:
      - ./src:/code
      - ./static:/static
      - ./sock:/var/sock/gunicorn
      - gunicorn-run:/var/sock/gunicorn
    ports:
      - "8000:8000"
    depends_on:
      - db

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/22 09:02

    さらに、h2oとwebapiのコンテナのvolumesで `/var/sock/gunicorn` をホストの作業ディレクトリ下の `sock` ディレクトリと共有しているのも原因でした。

    これを修正することで、H2OとGunicornでDjangoに接続することが出来るようになりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる