【问题标题】:GitHub Action I wrote doesn't have access to repo's files that is calling the action我写的 GitHub Action 无权访问调用该操作的 repo 文件
【发布时间】:2021-12-05 03:04:20
【问题描述】:

GitHub here 上有一个包含我正在处理的目录结构的示例 repo。要运行 GitHub Action,您只需转到 repo 的 Action 选项卡并手动运行 Action。


我有一个自定义的 GitHub Action,我也使用 python 作为 Docker 容器中的基础映像编写了一个自定义 GitHub Action,但希望将 python 版本作为 GitHub Action 的输入。为此,我正在创建第二个中间 Docker 容器以使用 python 版本输入参数运行。

我遇到的问题是我无权访问调用 GitHub 操作的原始存储库文件。例如,假设 repo 名为 python-sample-project 并具有文件夹结构:

python-sample-project
│   main.py
│   file1.py    
│
└───folder1
│   │   file2.py

我在entrypoint.sh 中看到了main.pyfile1.pyfolder1/file2.py。但是,在docker-action/entrypoint.sh 中,我只能看到 linux 文件夹结构和在docker-action/Dockerfile 中复制的entrypoint.sh 文件。

在我使用的 Alpine 示例中,动作 entrypoint.sh 脚本如下所示:

#!/bin/sh -l
ALPINE_VERSION=$1
cd /docker-action
docker build -t docker-action --build-arg alpine_version="$ALPINE_VERSION" . && docker run docker-action

docker-action/ 中,我有一个Dockerfileentrypoint.sh 脚本,应该使用动态版本的Alpine(或Python)为内部容器运行

docker-action/Dockerfile如下:

# Container image that runs your code
ARG alpine_version
FROM alpine:${alpine_version}

# Copies your code file from your action repository to the filesystem path `/` of the container
COPY entrypoint.sh /entrypoint.sh

RUN ["chmod", "+x", "/entrypoint.sh"]

# Code file to execute when the docker container starts up (`entrypoint.sh`)
ENTRYPOINT ["/entrypoint.sh"]

docker-action/entrypoint 中,我运行ls,但看不到存储库文件。

是否可以访问docker-action/entrypoint.sh 中的entrypoint.sh 中的main.pyfile1.pyfolder1/file2.py

【问题讨论】:

  • 我不确定我是否理解问题陈述。您能否提供错误输出以及预期输出?此外,您链接的存储库不包含任何与 Python 相关的内容,并且其中的操作似乎是成功的。请非常具体地说明问题。
  • 问题似乎出在你的Dockerfile,但是,你没有包含它的内容。

标签: python docker github github-actions


【解决方案1】:

通常有两种方法可以从存储库中获取可用于构建和运行的 docker 容器的文件。您可以 (1) 在构建镜像时将文件添加到镜像中,或者 (2) 在运行镜像时将文件挂载到容器中。还有其他一些方法,比如指定卷,但这可能超出了这种情况的范围。

Dockerfile docker-action/Dockerfile 不会复制除 entrypoint.sh 脚本之外的任何文件。您的 entrypoint.sh 在运行容器时也不提供任何挂载点。因此,您观察到的结果是基于这些事实的预期结果。

为了解决这个问题,您必须 (1) 在 Dockerfile 中添加 COPY/ADD 语句以将文件复制到映像中(并设置适当的构建上下文)或 (2) 将文件挂载到容器中当它通过将-v /source-path:/container-path 添加到entrypoint.sh 中的docker run 命令来运行时。

参见参考资料:

不过,这种构建另一个容器只是为了获得用户提供的 python 版本的方法对于 GitHub Actions 来说是一个非常值得怀疑的做法,应该避免。考虑改用setup-python 操作。

docker-in-docker 问题

尽管如此,如果您继续这条路线并想要挂载目录,则必须记住,当从 GitHub 上的 docker 操作中调用 docker 时,挂载规范中的文件系统指的是docker 主机的文件系统,而不是容器的文件系统。

它可以在我的机器上运行?!

与您在本地系统上运行 docker 时可能遇到的相反,例如,这在 GitHub 中不起作用——工作目录未挂载:

docker run -v $(pwd):/opt/workspace \
           --workdir /opt/workspace \ 
           --entrypoint /bin/ls \
           my-container "-R"

这也不起作用:

docker run -v $GITHUB_WORKSPACE:$GITHUB_WORKSPACE \
           --workdir $GITHUB_WORKSPACE \ 
           --entrypoint /bin/ls \
           my-container "-R"

如果您在本地运行 docker 的系统上进行尝试,这种方法会非常好用。什么给了?

对付恶魔(守护进程)

在 Actions 中,文件检出到 $GITHUB_WORKSPACE 的起始工作目录。在 docker 操作中,这是 /github/workspace。当 your 操作由 Actions 运行程序运行时,工作区文件会填充到工作区中从运行 docker 守护程序的主机安装工作区。

您可以在操作开始时的命令运行中看到:

/usr/bin/docker run --name f884202608aa2bfab75b6b7e1f87b3cd153444_f687df --label f88420 --workdir /github/workspace --rm -e INPUT_ALPINE-VERSION -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_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -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 GITHUB_ACTION_REPOSITORY -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_OS -e RUNNER_NAME -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/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/my-repo/my-repo":"/github/workspace" f88420:2608aa2bfab75b6b7e1f87b3cd153444  "3.9.5"

重要的一点是:

-v "/home/runner/work/my-repo/my-repo":"/github/workspace" 
-v "/var/run/docker.sock":"/var/run/docker.sock"

/home/runner/work/my-repo/my-repo 是主机上的路径,存储库文件所在的位置。如前所述,第一行是它在运行时将其挂载到操作容器中的/github/workspace 的原因。

第二行是将 docker 套接字从主机安装到操作容器。这意味着任何时候您在操作中调用 docker,实际上都是在与容器外的 docker 守护进程对话。这很重要,因为这意味着当在您的操作内部使用-v 参数时,参数需要反映容器外部存在的目录。

所以,您实际上需要做的是:

docker run -v /home/runner/work/my-repo/my-repo:/opt/workspace \
           --workdir /opt/workspace \ 
           --entrypoint /bin/ls \
           my-container "-R"

对他人有用

这行得通。如果您仅将其用于项目本身。但是,如果您希望其他项目可以使用此操作,那么您还有一个(除其他外)问题。您如何知道工作空间在主机上的位置?毕竟,每个存储库的路径都会改变。 GitHub 也不保证这些路径。它们在不同平台上可能不同,或者您的操作可能在自托管运行器上运行。

那么您如何满足于这个问题呢?不幸的是,没有内置的环境变量指向您特别需要的这个目录。但是,通过依赖实现细节,您可能能够避免使用$RUNNER_WORKSPACE 变量,在这种情况下,该变量将指向/home/runner/work/your-project。这与$GITHUB_WORKSPACE 的起源不是同一个地方,但很接近。您可以使用GITHUB_REPOSITORY 变量来构建路径,但不能保证始终如此:

PROJECT_NAME="$(basename ${GITHUB_REPOSITORY})"
WORKSPACE="${RUNNER_WORKSPACE}/${PROJECT_NAME}"

您还需要修复一些其他问题,例如您构建的工作目录表单。

TL;DR

运行时需要在容器中挂载文件。在 GitHub 中,您正在运行 docker-in-docker,因此您需要用于挂载文件的路径会有所不同,因此您需要找到正确的路径,以便在从您的操作容器中调用时传递给 docker

您链接的示例项目的最低工作解决方案是回购根目录中的entrypoint.sh,如下所示:

#!/usr/bin/env sh
ALPINE_VERSION=$1

docker build -t docker-action \
             -f ./docker-action/Dockerfile \
             --build-arg alpine_version="$ALPINE_VERSION" \
             ./docker-action

PROJECT_NAME="$(basename ${GITHUB_REPOSITORY})"
WORKSPACE="${RUNNER_WORKSPACE}/${PROJECT_NAME}"

docker run --workdir=$GITHUB_WORKSPACE \
           -v $WORKSPACE:$GITHUB_WORKSPACE \
           docker-action "$@"

您的操作可能还有其他问题,具体取决于它的作用,例如将操作的所有默认和用户定义的环境变量提供给“内部”容器,如果这很重要的话。

那么,这可能吗?当然。仅仅获得 alpine/python 的动态版本是否合理?我不这么认为。可能有更好的方法来完成您想做的事情,例如使用 setup-python,但这听起来像是一个不同的问题。

【讨论】:

  • 感谢您的反馈。您如何为 GitHub 操作处理不同版本的 python?
  • 使用GitHub的第一方setup-pythonaction可能是最合理的方式。您可以通过多种方式将此要求纳入您的操作中......关于您如何进行的一些想法:(1)期望用户在之前的步骤中使用setup-python(类似于我们期望他们使用结帐的方式)(2 ) 使用复合动作 (3) 使用不同版本发布您的动作的多个标签(例如myaction@v3-python3.9)。部分取决于 为什么 您需要指定的 python 版本。但是依靠setup-python 几乎可以肯定是正确的方法。
  • 使用 docker-in-docker 方法的另一个困难是挂载文件不是直截了当的,因为挂载点是在守护进程主机文件系统上指定的,而不是在你的容器的文件系统上指定的。正在运行您的操作的操作。你可以很容易地解决这个问题,但它非常脆弱。如果操作需要,还需要做额外的工作以使“内部”容器拥有所有GITHUB_ 或用户定义的变量。也许考虑一个非码头行动开始。我将为此添加一个最低限度的工作解决方案,FWIW。
  • 感谢所有反馈。我还没有机会在我自己的机器上完成你的解决方案,但我非常怀疑有人会像你一样给我一个彻底的答案。感谢您抽出宝贵时间。
猜你喜欢
  • 2020-10-01
  • 2022-07-16
  • 2022-08-10
  • 2021-09-30
  • 2021-10-22
  • 2020-02-24
  • 2021-12-06
  • 2022-12-12
  • 2021-05-18
相关资源
最近更新 更多