#docker #docker-compose #dockerfile #devops
Вопрос:
Я пытаюсь решить задание колледжа, запустив приложение, написанное на flask redis. Для этого мне нужно использовать докер. Использование docker-compose up redis запускается правильно, однако приложение flask выдает ошибки, и я действительно не знаю, почему.
Некоторый код приложения flask, если я правильно понимаю, мне нужно объявить переменные среды в файле Dockefile, потому что именно из них приложение получит ip-адрес и порт Redis
app = Flask(__name__)
redis = redis.Redis(host=os.environ.get('REDIS_HOST'),
password=None,
port=os.environ.get('REDIS_PORT'),
db=0)
Мой Док-файл
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"]
И докер-сочиняй
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"
докер-создание сборки
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-составьте
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>
Ответ №1:
Ошибка приложения, которую вы видите, вызвана тем, что соединение Redis не открывается, если вы внимательно посмотрите на трассировку стека. Причина неудачного подключения заключается в том, что REDIS_HOST
127.0.0.1
в вашем файле Dockerfile неверно установлено значение. Чтобы исправить это, значения для REDIS_HOST
и REDIS_PORT
должны на самом деле передаваться в контейнер приложения docker-compose, так как именно этот слой фактически знает, где живет Redis. Ваш файл настройки предназначен только для контейнера приложения, который зависит от Redis, но не имеет представления, где он может работать.
Поскольку compose делает службы доступными по именам хостов, равным имени службы по умолчанию , Redis должен быть доступен по адресу just tcp://redis:6379
, поэтому я бы дал этим значениям шанс для начала:
web:
build: .
container_name: "python_app"
ports:
- "8000:8000"
depends_on:
- redis
environment:
REDIS_HOST: redis
REDIS_PORT: 6379