通常有两种方法可以从存储库中获取可用于构建和运行的 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,但这听起来像是一个不同的问题。