我编写的GitHub操作无权访问调用该操作的repo文件

2022-04-06 00:00:00 python docker github github-actions

问题描述

GitHub here上有一个带有我正在处理的目录结构的示例repo。要运行GitHub操作,您只需转到存储库的操作选项卡并手动运行操作。


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

我遇到的问题是我无法访问调用GitHub操作的原始repo文件。例如,假定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文件。

在我使用的阿尔卑斯山示例中,操作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脚本,它应该使用动态版本的阿尔卑斯(或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中的main.pyfile1.pyfolder1/file2.py


解决方案

通常有两种方法可以将存储库中的文件提供给您构建和运行的停靠容器。您可以(1)在构建镜像时将文件添加到镜像中,或者(2)在运行容器时将文件装载到容器中。还有一些其他方法,如指定卷,但这可能不在此例的范围内。

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

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

参阅参考文献:

  • COPYreference
  • Docker run reference
但是,这种仅仅为了获得用户提供的Python版本而构建另一个容器的方法对于GitHub操作来说是一种非常有问题的做法,应该避免。请考虑改为使用setup-python操作。

对接问题

不过,如果您继续此路线并希望开始挂载目录,则必须记住,当从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的系统上尝试这种方法,它将完全正常工作。怎么回事?

处理魔鬼(后台进程)

在操作中,文件检出到的起始工作目录。在停靠操作中,这是/github/workspace。当您的操作由操作运行器从运行停靠程序后台进程的主机装载工作区时,工作区文件将填充到工作区中。

您可以在操作开始时的命令run中看到这一点:

/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,实际上都是在与容器外部的停靠守护进程对话。这一点很重要,因为这意味着当您在操作中使用-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变量来构建路径,但不能保证AFAIK:

总是这样
PROJECT_NAME="$(basename ${GITHUB_REPOSITORY})"
WORKSPACE="${RUNNER_WORKSPACE}/${PROJECT_NAME}"

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

TL;DR

运行容器时需要在容器中挂载文件。在GitHub中,您运行的是docker-in-docker,因此装载文件所需的路径工作方式不同,因此您需要找到从操作容器中调用时要传递到docker的正确路径。

您链接的示例项目的最低有效解决方案是repo根目录中的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 "$@"

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

那么,这有可能吗?好的。仅仅获得一个动态版本的阿尔卑斯山/蟒蛇是否合理?我不这样认为。可能还有更好的方法来完成你想做的事情,比如使用setup-python,但这听起来是另一个问题。

相关文章