Развертывание Heroku с помощью докера и поэзии

Я пытаюсь развернуть приложение Django на Heroku. Я использую докер и поэзию. У меня проблема, потому что в файле докеров я устанавливаю поэзию и устанавливаю зависимости с помощью поэзии. Локально все работает нормально, но когда я хочу развернуть на героку, зависимости не устанавливаются. Только размещение кода типа:

«RUN pip install -r require.txt» устанавливает зависимости от Heroku (я создал файл «requirements.txt», используя экспорт поэзии).

Должен ли я иметь два разных файла Dockerfile для разработки и разработки, где я буду использовать поэзию в одном и требования к установке pip в другом? Или мне следует использовать многоэтапный Dockerfile или у вас есть другие предложения?

Мой Dockerfile с потерией:

FROM python:3.11-alpine

WORKDIR /code

ENV PYTHONUNBUFFERED 1
ENV PATH "/root/.local/bin:$PATH"

RUN apk add --no-cache curl \
    && curl -sSL https://install.python-poetry.org | python3 - \
    && apk add --no-cache postgresql-dev musl-dev

COPY poetry.lock pyproject.toml /code/

RUN poetry install --no-root

COPY . /code/

RUN poetry install

геройку.yml:

build:
  docker:
    web: backend/Dockerfile

run:
  web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT

Результат развертывания:

$ git push heroku main
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 12 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 1.09 KiB | 1.09 MiB/s, done.
Total 6 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Updated 63 paths from 075607f
remote: Compressing source files... done.
remote: Building source:
remote: Waiting on build...
remote: Waiting on build... (elapsed: 6s)
remote: Waiting on build... (elapsed: 9s)
remote: Waiting on build... (elapsed: 12s)
remote: === Fetching app code
remote:
remote: === Building web (backend/Dockerfile)
remote:
remote: Sending build context to Docker daemon  53.76kB
remote: Step 1/10 : FROM python:3.11-alpine
remote: 3.11-alpine: Pulling from library/python
remote: 4abcf2066143: Pulling fs layer
remote: c3cdf40b8bda: Pulling fs layer
remote: ac499ccf2147: Pulling fs layer
remote: 416bfceb623e: Pulling fs layer
remote: 76351c33299b: Pulling fs layer
remote: 416bfceb623e: Waiting
remote: 76351c33299b: Waiting
remote: c3cdf40b8bda: Download complete
remote: 4abcf2066143: Verifying Checksum
remote: 4abcf2066143: Download complete
remote: 416bfceb623e: Download complete
remote: ac499ccf2147: Verifying Checksum
remote: ac499ccf2147: Download complete
remote: 76351c33299b: Verifying Checksum
remote: 76351c33299b: Download complete
remote: 4abcf2066143: Pull complete
remote: c3cdf40b8bda: Pull complete
remote: ac499ccf2147: Pull complete
remote: 416bfceb623e: Pull complete
remote: 76351c33299b: Pull complete
remote: Digest: sha256:0b5ed25d3cc27cd35c7b0352bac8ef2ebc8dd3da72a0c03caaf4eb15d9ec827a
remote: Status: Downloaded newer image for python:3.11-alpine
remote:  ---> 10333afc009e
remote: Step 2/10 : WORKDIR /code
remote:  ---> Running in ed5fbef22730
remote: Removing intermediate container ed5fbef22730
remote:  ---> e217b7efac9b
remote: Step 3/10 : ENV DJANGO_SETTINGS_MODULE core.settings
remote:  ---> Running in 35d73be810f5
remote: Removing intermediate container 35d73be810f5
remote:  ---> 06f7f12a8f60
remote: Step 4/10 : ENV PYTHONUNBUFFERED 1
remote:  ---> Running in 13220906f1c2
remote: Removing intermediate container 13220906f1c2
remote:  ---> c7fd5fadf540
remote: Step 5/10 : ENV PATH "/root/.local/bin:$PATH"
remote:  ---> Running in 747dae6a957b
remote: Removing intermediate container 747dae6a957b
remote:  ---> da2b7e7bfd6a
remote: Step 6/10 : RUN apk add --no-cache curl     && curl -sSL https://install.python-poetry.org | python3 -     && apk add --no-cache postgresql-dev musl-dev
remote:  ---> Running in f57663dadafc
remote: fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz
remote: fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/community/x86_64/APKINDEX.tar.gz
remote: (1/7) Installing brotli-libs (1.1.0-r1)
remote: (2/7) Installing c-ares (1.27.0-r0)
remote: (3/7) Installing libunistring (1.1-r2)
remote: (4/7) Installing libidn2 (2.3.4-r4)
remote: (5/7) Installing nghttp2-libs (1.58.0-r0)
remote: (6/7) Installing libcurl (8.5.0-r0)
remote: (7/7) Installing curl (8.5.0-r0)
remote: Executing busybox-1.36.1-r15.trigger
remote: OK: 20 MiB in 45 packages
remote: Retrieving Poetry metadata
remote:
remote: # Welcome to Poetry!
remote:
remote: This will download and install the latest version of Poetry,
remote: a dependency and package manager for Python.
remote:
remote: It will add the `poetry` command to Poetry s bin directory, located at:
remote:
remote: /root/.local/bin
remote:
remote: You can uninstall at any time by executing this script with the --uninstall option,
remote: and these changes will be reverted.
remote:
remote: Installing Poetry (1.8.2)
remote: Installing Poetry (1.8.2): Creating environment
remote: Installing Poetry (1.8.2): Installing Poetry
remote: Installing Poetry (1.8.2): Creating script
remote: Installing Poetry (1.8.2): Done
remote:
remote: Poetry (1.8.2) is installed now. Great!
remote:
remote: You can test that everything is set up by executing:
remote:
remote: `poetry --version`
remote:
remote: fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/APKINDEX.tar.gz
remote: fetch https://dl-cdn.alpinelinux.org/alpine/v3.19/community/x86_64/APKINDEX.tar.gz
remote: (1/39) Upgrading libcrypto3 (3.1.4-r5 -> 3.1.4-r6)
remote: (2/39) Upgrading libssl3 (3.1.4-r5 -> 3.1.4-r6)
remote: (3/39) Installing musl-dev (1.2.4_git20230717-r4)
remote: (4/39) Installing libpq (16.2-r1)
remote: (5/39) Installing pkgconf (2.1.0-r0)
remote: (6/39) Installing openssl-dev (3.1.4-r6)
remote: (7/39) Installing libpq-dev (16.2-r1)
remote: (8/39) Installing libecpg (16.2-r1)
remote: (9/39) Installing libecpg-dev (16.2-r1)
remote: (10/39) Installing fortify-headers (1.1-r3)
remote: (11/39) Installing clang15-headers (15.0.7-r18)
remote: (12/39) Installing libgcc (13.2.1_git20231014-r0)
remote: (13/39) Installing libstdc++ (13.2.1_git20231014-r0)
remote: (14/39) Installing libxml2 (2.11.7-r0)
remote: (15/39) Installing zstd-libs (1.5.5-r8)
remote: (16/39) Installing llvm15-libs (15.0.7-r12)
remote: (17/39) Installing clang15-libs (15.0.7-r18)
remote: (18/39) Installing jansson (2.14-r4)
remote: (19/39) Installing binutils (2.41-r0)
remote: (20/39) Installing libgomp (13.2.1_git20231014-r0)
remote: (21/39) Installing libatomic (13.2.1_git20231014-r0)
remote: (22/39) Installing gmp (6.3.0-r0)
remote: (23/39) Installing isl26 (0.26-r1)
remote: (24/39) Installing mpfr4 (4.2.1-r0)
remote: (25/39) Installing mpc1 (1.3.1-r1)
remote: (26/39) Installing gcc (13.2.1_git20231014-r0)
remote: (27/39) Installing libstdc++-dev (13.2.1_git20231014-r0)
remote: (28/39) Installing clang15-libclang (15.0.7-r18)
remote: (29/39) Installing clang15 (15.0.7-r18)
remote: (30/39) Installing icu-data-en (74.1-r0)
remote: Executing icu-data-en-74.1-r0.post-install
remote: *
remote: * If you need ICU with non-English locales and legacy charset support, install
remote: * package icu-data-full.
remote: *
remote: (31/39) Installing icu-libs (74.1-r0)
remote: (32/39) Installing icu (74.1-r0)
remote: (33/39) Installing icu-dev (74.1-r0)
remote: (34/39) Installing llvm15 (15.0.7-r12)
remote: (35/39) Installing lz4-libs (1.9.4-r5)
remote: (36/39) Installing lz4-dev (1.9.4-r5)
remote: (37/39) Installing zstd (1.5.5-r8)
remote: (38/39) Installing zstd-dev (1.5.5-r8)
remote: (39/39) Installing postgresql16-dev (16.2-r1)
remote: Executing busybox-1.36.1-r15.trigger
remote: Executing ca-certificates-20230506-r0.trigger
remote: OK: 534 MiB in 82 packages
remote: Removing intermediate container f57663dadafc
remote:  ---> 0e39b87928ff
remote: Step 7/10 : COPY poetry.lock pyproject.toml /code/
remote:  ---> 2d0fae435427
remote: Step 8/10 : RUN poetry install --no-root
remote:  ---> Running in 5ba8992a62d2
remote: Creating virtualenv backend-MATOk_fk-py3.11 in /root/.cache/pypoetry/virtualenvs
remote: Installing dependencies from lock file
remote:
remote: Package operations: 25 installs, 0 updates, 0 removals
remote:
remote:   - Installing asgiref (3.8.1)
remote:   - Installing sqlparse (0.5.0)
remote:   - Installing django (5.0.4)
remote:   - Installing iniconfig (2.0.0)
remote:   - Installing packaging (24.0)
remote:   - Installing pluggy (1.4.0)
remote:   - Installing djangorestframework (3.15.1)
remote:   - Installing inflection (0.5.1)
remote:   - Installing mccabe (0.7.0)
remote:   - Installing mypy-extensions (1.0.0)
remote:   - Installing pycodestyle (2.11.1)
remote:   - Installing pyflakes (3.2.0)
remote:   - Installing pytest (8.1.1)
remote:   - Installing pytz (2024.1)
remote:   - Installing pyyaml (6.0.1)
remote:   - Installing typing-extensions (4.11.0)
remote:   - Installing uritemplate (4.1.1)
remote:   - Installing dj-database-url (2.1.0)
remote:   - Installing drf-yasg (1.21.7)
remote:   - Installing flake8 (7.0.0)
remote:   - Installing gunicorn (22.0.0)
remote:   - Installing mypy (1.9.0)
remote:   - Installing psycopg2 (2.9.9)
remote:   - Installing pytest-django (4.8.0)
remote:   - Installing python-dotenv (1.0.1)
remote: Removing intermediate container 5ba8992a62d2
remote:  ---> 2c51709ee889
remote: Step 9/10 : COPY . /code/
remote:  ---> a3af2a6c5b5c
remote: Step 10/10 : RUN poetry install
remote:  ---> Running in 3ecd2f328645
remote: Installing dependencies from lock file
remote:
remote: No dependencies to install or update
remote:
remote: Installing the current project: backend (0.1.0)
remote:
remote: Warning: The current project could not be installed: [Errno 2] No such file or directory: '/code/README.md'
remote: If you do not want to install the current project use --no-root.
remote: If you want to use Poetry only for dependency management but not for packaging, you can disable package mode by setting package-mode = false in your pyproject.toml file.
remote: In a future version of Poetry this warning will become an error!
remote: Removing intermediate container 3ecd2f328645
remote:  ---> 542545ea1195
remote: Successfully built 542545ea1195
remote: Successfully tagged a31f1f813825dc98a956f33b6a3822912f137c40:latest
remote:
remote: === Pushing web (backend/Dockerfile)
remote: Tagged image "a31f1f813825dc98a956f33b6a3822912f137c40" as "registry.heroku.com/wanderer-test/web"
remote: Using default tag: latest
remote: The push refers to repository [registry.heroku.com/wanderer-test/web]
remote: 1e4eca4bbbe5: Preparing
remote: 115e0e85b9ba: Preparing
remote: 81bae2c8c9e6: Preparing
remote: bab36042a757: Preparing
remote: 08bf6ffaa8ac: Preparing
remote: 4a770d99ce52: Preparing
remote: dbf59eaac1dd: Preparing
remote: ed829bc3e4b2: Preparing
remote: 4c9c2b9681ab: Preparing
remote: d4fc045c9e3a: Preparing
remote: 4a770d99ce52: Waiting
remote: dbf59eaac1dd: Waiting
remote: ed829bc3e4b2: Waiting
remote: 4c9c2b9681ab: Waiting
remote: d4fc045c9e3a: Waiting
remote: 08bf6ffaa8ac: Pushed
remote: 81bae2c8c9e6: Pushed
remote: 1e4eca4bbbe5: Pushed
remote: 4a770d99ce52: Layer already exists
remote: dbf59eaac1dd: Layer already exists
remote: ed829bc3e4b2: Layer already exists
remote: d4fc045c9e3a: Layer already exists
remote: 4c9c2b9681ab: Layer already exists
remote: 115e0e85b9ba: Pushed
remote: bab36042a757: Pushed
remote: latest: digest: sha256:b9da90ba3205e3c005fee403be4f0e631cd41e1de27ef7c93a2a57d4c4d860c3 size: 2417
remote:
remote: Verifying deploy... done.

Да, это работает правильно. Вы правы, что python:3.11-alpine не включает Poetry, поэтому мне пришлось его установить (посмотрите на вторую строку команды: «RUN apk add --no-cache...») и установить ENV PATH как « /root/.local/bin:$PATH". Тогда это работает.

tomtom 24.04.2024 17:31

Как вы проводите развертывание в Heroku? Используете ли вы реестр контейнеров (т. е. используете heroku container:push и heroku container:release) или используете файл Heroku.yml со стеком контейнера?

Chris 24.04.2024 18:10

Я использую файл Heroku.yml со стеком

tomtom 24.04.2024 18:24

Пожалуйста, покажите вывод Heroku при развертывании приложения.

Chris 24.04.2024 18:31

Вот журналы Heroku после развертывания: 2024-04-24T16:47:41.000000+00:00 приложение[api]: сборка выполнена успешно 2024-04-24T16:47:42.968820+00:00 Heroku[web.1]: состояние изменено от сбоя до запуска2024-04-24T16:47:55.811929+00:00 Heroku[web.1]: Запуск процесса с помощью команды /bin/sh -c gunicorn\ core.wsgi:application\ --bind\ 0.0.0.0:\7149 2024-04-24T16:47:56.601108+00:00 Heroku[web.1]: Процесс завершен со статусом 127 2024-04-24T16:47:56.550277+00:00 app[web.1]: /bin/sh: Gunicorn: не найдено 2024-04-24T16:47:56.627143+00:00 Heroku[web.1 ]: состояние изменилось с запуска на сбой.

tomtom 24.04.2024 19:09

Я прошу логи развертывания, а не того, что будет дальше. Пожалуйста, отредактируйте их в свой вопрос как блок кода.

Chris 24.04.2024 19:14

хорошо, я добавил все журналы развертывания в свой вопрос.

tomtom 24.04.2024 19:21

кроме того, теперь я вижу, что после «поэтического шоу Heroku Run» я вижу все пакеты, установленные в virtualenv, но после «списка запуска Heroku PIP» я не вижу эти пакеты. Я думаю, что, вероятно, поэзия создает виртуальную среду, устанавливает все пакеты в этой среде, а Heroku не может использовать эту виртуальную среду, и у нее не установлены эти пакеты.

tomtom 25.04.2024 16:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
8
132
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На данный момент у меня нет динамометрического стенда Heroku для тестирования, но я думаю, вас укусило это:

Мы настоятельно рекомендуем тестировать изображения локально под пользователем без полномочий root, поскольку контейнеры не запускаются с правами root в Heroku.

(В документации далее объясняется, как это сделать, но я не буду копировать это здесь, поскольку это своего рода врезка.)

Поскольку Poetry по умолчанию создает виртуальную среду, именно туда направляются ваши зависимости. Системы python, pip и т. д. понятия не имеют об их существовании.

Я предлагаю заставить Poetry устанавливать пакеты в системной среде Python, отключив его настройку virtualenvs.create (выделено автором):

Если установлено значение false, Poetry не будет создавать новую виртуальную среду. Если он обнаружит уже включенную виртуальную среду или существующую в {cache-dir}/virtualenvs или {project-dir}/.venv, он установит в них зависимости, в противном случае он установит зависимости в среду Python системы.

Один из способов сделать это — добавить новую команду RUN или связать ее с существующей командой, которую вы запускаете poetry install:

RUN poetry config virtualenvs.create false && poetry install
#   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(Примечание: я не думаю, что вам нужно запускать poetry install дважды. У вас должна быть возможность избавиться от того, в котором есть --no-root, перед командой COPY.)

Вам также не нужно создавать requirements.txt. Наличие его рядом с вашими файлами Poetry сбивает с толку, и это просто еще одна вещь, которую нужно поддерживать. Предлагаю удалить его полностью.

Другие вопросы по теме