Redis and flask app, web container does not want to start IndexError: pop from empty list

Redis and flask app, web container does not want to start IndexError: pop from empty list

我正在尝试解决大学作业运行 一个用 flask + redis 编写的应用程序。我必须为此使用 docker。使用 docker-compose up redis 可以正确启动,但是 flask 应用程序会抛出错误,我真的不知道为什么。

flask应用的部分代码 如果我理解正确的话,我需要在 Dockefile 中声明环境变量,因为应用程序将从这些变量中获取 Redis

的 IP 地址和端口
app = Flask(__name__)
redis = redis.Redis(host=os.environ.get('REDIS_HOST'),
                    password=None,
                    port=os.environ.get('REDIS_PORT'),
                    db=0)

我的 Dockerfile

ARG PYTHON_VERSION=3.7-alpine

FROM python:${PYTHON_VERSION}

ENV REDIS_HOST 127.0.0.1 \
    REDIS_PORT 6379

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "main:app"]

和docker-撰写

version: "3"

services:
  web:
    build: .
    container_name: "python_app"
    ports:
      - "8000:8000"
    depends_on:
      - redis
  
  redis:
    image: "redis:alpine"
    container_name: "redis"
    ports: 
      - "6379:6379"

docker-编写构建

Creating network "tt_default" with the default driver
Pulling redis (redis:alpine)...
alpine: Pulling from library/redis
Digest: sha256:fa785f9bd167b94a6b30210ae32422469f4b0f805f4df12733c2f177f500d1ba
Status: Downloaded newer image for redis:alpine
Building web
Sending build context to Docker daemon  10.75kB
Step 1/7 : ARG PYTHON_VERSION=3.7-alpine
Step 2/7 : FROM python:${PYTHON_VERSION}
 ---> a436fb2c575c
Step 3/7 : ENV REDIS_HOST 127.0.0.1     REDIS_PORT 6379
 ---> Running in ad3a17ce15e9
Removing intermediate container ad3a17ce15e9
 ---> 937330185f34
Step 4/7 : COPY requirements.txt .
 ---> d81cbb22f113
Step 5/7 : RUN pip install -r requirements.txt
 ---> Running in 1c0bac282a92
Collecting Flask==1.1.2
  Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)
Collecting redis==3.4.1
  Downloading redis-3.4.1-py2.py3-none-any.whl (71 kB)
Collecting gunicorn<20,>=19
  Downloading gunicorn-19.10.0-py2.py3-none-any.whl (113 kB)
Collecting itsdangerous>=0.24
  Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting click>=5.1
  Downloading click-8.0.1-py3-none-any.whl (97 kB)
Collecting Jinja2>=2.10.1
  Downloading Jinja2-3.0.1-py3-none-any.whl (133 kB)
Collecting Werkzeug>=0.15
  Downloading Werkzeug-2.0.1-py3-none-any.whl (288 kB)
Collecting importlib-metadata
  Downloading importlib_metadata-4.8.1-py3-none-any.whl (17 kB)
Collecting MarkupSafe>=2.0
  Downloading MarkupSafe-2.0.1.tar.gz (18 kB)
Collecting typing-extensions>=3.6.4
  Downloading typing_extensions-3.10.0.2-py3-none-any.whl (26 kB)
Collecting zipp>=0.5
  Downloading zipp-3.5.0-py3-none-any.whl (5.7 kB)
Building wheels for collected packages: MarkupSafe
  Building wheel for MarkupSafe (setup.py): started
  Building wheel for MarkupSafe (setup.py): finished with status 'done'
  Created wheel for MarkupSafe: filename=MarkupSafe-2.0.1-py3-none-any.whl size=9761 sha256=43b5e0d8ef8bcbadc8e8d6845f85b770ad2b918760d7541b8c3f9c403ab04b14
  Stored in directory: /root/.cache/pip/wheels/1a/18/04/e3b5bd888f000c2716bccc94a565239f9defc47ef93d9e7bea
Successfully built MarkupSafe
Installing collected packages: zipp, typing-extensions, MarkupSafe, importlib-metadata, Werkzeug, Jinja2, itsdangerous, click, redis, gunicorn, Flask
Successfully installed Flask-1.1.2 Jinja2-3.0.1 MarkupSafe-2.0.1 Werkzeug-2.0.1 click-8.0.1 gunicorn-19.10.0 importlib-metadata-4.8.1 itsdangerous-2.0.1 redis-3.4.1 typing-extensions-3.10.0.2 zipp-3.5.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
Removing intermediate container 1c0bac282a92
 ---> 6dddf2a4ad27
Step 6/7 : COPY . .
 ---> 37bd8f541844
Step 7/7 : CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "main:app"]
 ---> Running in f19c3226fff2
Removing intermediate container f19c3226fff2
 ---> 861a5c53a545
Successfully built 861a5c53a545
Successfully tagged tt_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating redis ... done
Creating python_app ... done
Attaching to redis, python_app

使用docker-compose up

后得到的部分日志
 Attaching to redis, python_app
    redis    | 1:C 27 Sep 2021 14:36:16.063 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    redis    | 1:C 27 Sep 2021 14:36:16.063 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
    redis    | 1:C 27 Sep 2021 14:36:16.063 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
    redis    | 1:M 27 Sep 2021 14:36:16.064 * monotonic clock: POSIX clock_gettime
    redis    | 1:M 27 Sep 2021 14:36:16.065 * Running mode=standalone, port=6379.
    redis    | 1:M 27 Sep 2021 14:36:16.065 # Server initialized
    redis    | 1:M 27 Sep 2021 14:36:16.065 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
    redis    | 1:M 27 Sep 2021 14:36:16.065 * Ready to accept connections
    python_app | [2021-09-27 14:36:16 +0000] [1] [INFO] Starting gunicorn 19.10.0
    python_app | [2021-09-27 14:36:16 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
    python_app | [2021-09-27 14:36:16 +0000] [1] [INFO] Using worker: sync
    python_app | [2021-09-27 14:36:16 +0000] [8] [INFO] Booting worker with pid: 8
    python_app | [2021-09-27 14:36:16 +0000] [9] [INFO] Booting worker with pid: 9
    python_app | [2021-09-27 14:36:16 +0000] [8] [ERROR] Exception in worker process
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1179, in get_connection
    python_app |     connection = self._available_connections.pop()
    python_app | IndexError: pop from empty list
    python_app | 
    python_app | During handling of the above exception, another exception occurred:
    python_app | 
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 586, in spawn_worker
    python_app |     worker.init_process()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 135, in init_process
    python_app |     self.load_wsgi()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
    python_app |     self.wsgi = self.app.wsgi()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
    python_app |     self.callable = self.load()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load
    python_app |     return self.load_wsgiapp()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 41, in load_wsgiapp
    python_app |     return util.import_app(self.app_uri)
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 350, in import_app
    python_app |     __import__(module)
    python_app |   File "/main.py", line 21, in <module>
    python_app |     redis.set('sessionvisitors', 0)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/client.py", line 1766, in set
    python_app |     return self.execute_command('SET', *pieces)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/client.py", line 875, in execute_command
    python_app |     conn = self.connection or pool.get_connection(command_name, **options)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1181, in get_connection
    python_app |     connection = self.make_connection()
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1220, in make_connection
    python_app |     return self.connection_class(**self.connection_kwargs)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 502, in __init__
    python_app |     self.port = int(port)
    python_app | TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
    python_app | [2021-09-27 14:36:16 +0000] [8] [INFO] Worker exiting (pid: 8)
    python_app | [2021-09-27 14:36:16 +0000] [10] [INFO] Booting worker with pid: 10
    python_app | [2021-09-27 14:36:16 +0000] [9] [ERROR] Exception in worker process
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1179, in get_connection
    python_app |     connection = self._available_connections.pop()
    python_app | IndexError: pop from empty list
    python_app | 
    python_app | During handling of the above exception, another exception occurred:
    python_app | 
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 586, in spawn_worker
    python_app |     worker.init_process()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 135, in init_process
    python_app |     self.load_wsgi()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
    python_app |     self.wsgi = self.app.wsgi()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
    python_app |     self.callable = self.load()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load
    python_app |     return self.load_wsgiapp()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 41, in load_wsgiapp
    python_app |     return util.import_app(self.app_uri)
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 350, in import_app
    python_app |     __import__(module)
    python_app |   File "/main.py", line 21, in <module>
    python_app |     redis.set('sessionvisitors', 0)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/client.py", line 1766, in set
    python_app |     return self.execute_command('SET', *pieces)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/client.py", line 875, in execute_command
    python_app |     conn = self.connection or pool.get_connection(command_name, **options)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1181, in get_connection
    python_app |     connection = self.make_connection()
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 1220, in make_connection
    python_app |     return self.connection_class(**self.connection_kwargs)
    python_app |   File "/usr/local/lib/python3.7/site-packages/redis/connection.py", line 502, in __init__
    python_app |     self.port = int(port)
    python_app | TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
    python_app | [2021-09-27 14:36:16 +0000] [9] [INFO] Worker exiting (pid: 9)
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 203, in run
    python_app |     self.manage_workers()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 548, in manage_workers
    python_app |     self.spawn_workers()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 620, in spawn_workers
    python_app |     time.sleep(0.1 * random.random())
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 245, in handle_chld
    python_app |     self.reap_workers()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 528, in reap_workers
    python_app |     raise HaltServer(reason, self.WORKER_BOOT_ERROR)
    python_app | gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>
    python_app | 
    python_app | During handling of the above exception, another exception occurred:
    python_app | 
    python_app | Traceback (most recent call last):
    python_app |   File "/usr/local/bin/gunicorn", line 8, in <module>
    python_app |     sys.exit(run())
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 61, in run
    python_app |     WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 223, in run
    python_app |     super(Application, self).run()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 72, in run
    python_app |     Arbiter(self).run()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 232, in run
    python_app |     self.halt(reason=inst.reason, exit_status=inst.exit_status)
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 345, in halt
    python_app |     self.stop()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 396, in stop
    python_app |     time.sleep(0.1)
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 245, in handle_chld
    python_app |     self.reap_workers()
    python_app |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 528, in reap_workers
    python_app |     raise HaltServer(reason, self.WORKER_BOOT_ERROR)
    python_app | gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>

如果您仔细查看堆栈跟踪,您看到的应用错误是因为 Redis 连接无法打开。连接失败的原因是 REDIS_HOST 在您的 Dockerfile 中被错误地设置为 127.0.0.1。要解决这个问题,REDIS_HOSTREDIS_PORT 的值实际上应该通过 docker-compose 传递到您的应用程序容器中,因为这是真正知道 Redis 所在的层。您的 Dockerfile 仅适用于您的应用程序容器,它 依赖于 Redis 但不知道它可能在哪里 运行.

由于默认情况下 compose 使服务在与服务名称相同的主机名处可用,因此 Redis 应该可以在 tcp://redis:6379 上访问,所以我会先给出这些值:

  web:
    build: .
    container_name: "python_app"
    ports:
      - "8000:8000"
    depends_on:
      - redis
    environment:
      REDIS_HOST: redis
      REDIS_PORT: 6379