如何在GitHub action中使用pipenv?

6

我正在使用pipenv为GitHub行动安装Python依赖项。这是我的pipfile的样子:

name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pylint = "*"

[packages]
pandas = "*"
pygithub = "*"
matplotlib = "*"

[requires]
python_version = "3.8"

这是Dockerfile的外观:
FROM python:3

COPY main.py /
COPY Pipfile /
COPY Pipfile.lock /
COPY views.csv /

# https://github.com/pypa/pipenv/issues/4273
RUN pip install 'pipenv==2018.11.26'
RUN pipenv install --deploy --ignore-pipfile

ENTRYPOINT ["pipenv", "run", "python", "./main.py"

我可以在本地运行Docker镜像,一切都符合预期,但是当我将其推送到GitHub时,会失败并显示以下错误:

Virtualenv location: /github/home/.local/share/virtualenvs/workspace-0SZQOxG8
Traceback (most recent call last):
  File "./main.py", line 1, in <module>
    from github import Github
ModuleNotFoundError: No module named 'github'

出现某些原因,当在GitHub虚拟机上运行Docker映像时,它没有捕获任何依赖项。
编辑于2020年7月28日: 这是触发操作的工作流程的main.yml文件。
on: 
  push: 
    branches: 
      - master


# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "insights_job"
  insights_job:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - uses: actions/checkout@v2
      
    - name: GitHub insights 
      id: insights
      uses: ./

你是如何创建/配置GitHub action的? - Omer Tuchfeld
我在repo的根目录下有一个action.yml和Dockerfile。我添加了一个工作流程(我已经添加到原始问题中),当更改被推送时触发该操作。 - sgonzalez
1个回答

5

简短版本

只需将以下内容添加到Dockerfile的顶部:

# Tells pipenv to create virtualenvs in /root rather than $HOME/.local/share.
# We do this because GitHub modifies the HOME variable between `docker build` and
# `docker run`
ENV WORKON_HOME /root

# Tells pipenv to use this specific Pipfile rather than the Pipfile in the 
# current working directory (the working directory changes between `docker build` 
# and `docker run`, this ensures we always use the same Pipfile)
ENV PIPENV_PIPFILE /Pipfile

简化版本

这里可以看到,Github actions将HOME环境变量定义为/github/home

随后,我们可以通过查看操作步骤日志中的run命令,发现该变量被传递给了Docker容器:

/usr/bin/docker run --name c201c6ad6ba986775dbb96d3c072d294f3c8_a057c6 --label 87c201 --workdir /github/workspace --rm -e HOME -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_ACTOR -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e RUNNER_OS -e RUNNER_TOOL_CACHE -e RUNNER_TEMP -e RUNNER_WORKSPACE -e ACTIONS_RUNTIME_URL -e ACTIONS_RUNTIME_TOKEN -e ACTIONS_CACHE_URL -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/j/j":"/github/workspace" 87c201:c6ad6ba986775dbb96d3c072d294f3c8

(注意-e home标志)

pipenv install$HOME/.local/share/virtualenvs 中创建虚拟环境并安装所有依赖项。然后,pipenv run ... 使用同一路径查找虚拟环境以运行所需命令。

在 Docker 镜像的构建阶段(docker build)中,$HOME 的默认值为 /root(因为这是 root 用户的主目录),所以 virtualenv 会被创建在 /root/.local/share/virtualenvs

但是,在 docker run 阶段,HOME 被设置为 /github/home(如上所述)。因此,virtualenv 会被创建在 /github/home/.local/share/virtualenvs

总结一下:

pipenv install 使用 /root/.local/share/virtualenvs

pipenv run 使用 /github/home/.local/share/virtualenvs

这意味着依赖项被安装在一个地方,但实际运行脚本时却希望位于另一个地方。

为了解决这个问题,我们可以在 Dockerfile 中使用 ENV 声明来设置 WORKON_HOME

pipenv 尊重 WORKON_HOME 变量,它会优先将其虚拟环境放在 WORKON_HOME 所定义的路径中,而不是在 HOME 中所定义的路径中。

因此,解决方案就是将以下内容添加到 Dockerfile

ENV WORKON_HOME /root

然而,这还不够,因为 pipenv 根据 pipenv 文件的位置选择虚拟环境。Github 设置 --workdir/github/workspace,然后将整个项目源代码挂载到该文件夹中,所以当我们运行 pipenv run 时,我们实际上是在使用位于 /github/workspace 中的 Pipenv 文件。这是与在 docker build 阶段将其复制到 / 并用于 pipenv install 不同的 Pipenv 文件。由于使用了两个不同的 Pipenv 位置,将使用两个不同的虚拟环境。

为了解决这个问题,我们可以使用 PIPENV_PIPEFILE 环境变量。该变量告诉 pipenv 在指定的位置而不是当前工作目录中查找 Pipfile

因此,让我们将以下内容添加到 Dockerfile 中:

ENV PIPENV_PIPFILE /Pipfile

感谢您深入的解释,问题已经解决了。 - sgonzalez
非常感谢@omer-tuchfeld,它解决了我的问题。 - Milind Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接