如何在AWS CodeBuild中的Dockerfile中使用AWS CodeArtifact

19

我正在尝试在AWS CodeBuild的Docker构建中从CodeArtifact进行pip安装。

这篇文章没有完全解决我的问题:https://docs.aws.amazon.com/codeartifact/latest/ug/using-python-packages-in-codebuild.html

AWS CodeArtifact的登录是在prebuild中完成的,在Docker上下文之外。

但是我的pip install在我的Dockerfile内部(我们从私有pypi注册表中提取)。

我该如何做到这一点,而不会像设置环境变量为从prebuild运行登录命令后读取~/.config/pip.conf/导出的密码这样糟糕?

2个回答

17
您可以使用环境变量:PIP_INDEX_URL[1]
下面是一个AWS CodeBuild的buildspec.yml文件,我们使用AWS文档中的示例构建了CodeArtifact的PIP_INDEX_URL。请注意保留HTML标签。

buildspec.yml

  pre_build:
    commands:
      - echo Getting CodeArtifact authorization...
      - export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain "${CODEARTIFACT_DOMAIN}" --domain-owner "${AWS_ACCOUNT_ID}" --query authorizationToken --output text)
      - export PIP_INDEX_URL="https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CODEARTIFACT_DOMAIN}-${AWS_ACCOUNT_ID}.d.codeartifact.${AWS_DEFAULT_REGION}.amazonaws.com/pypi/${CODEARTIFACT_REPO}/simple/"

在您的 Dockerfile 中,在 RUN pip install -r requirements.txt 的上方添加一行 ARG PIP_INDEX_URL,使其在构建过程中成为环境变量:

Dockerfile

# this needs to be added before your pip install line!
ARG PIP_INDEX_URL

RUN pip install -r requirements.txt

最后,我们使用 PIP_INDEX_URL 构建参数构建镜像。

buildspec.yml

  build:
    commands:
      - echo Building the Docker image...
      - docker build -t "${IMAGE_REPO_NAME}" --build-arg PIP_INDEX_URL .

另外,向您的Dockerfile添加ARG PIP_INDEX_URL不应该破坏任何现有的CI或工作流程。如果在构建镜像时省略了--build-arg PIP_INDEX_URL,pip仍将使用默认的PyPI索引。

指定--build-arg PIP_INDEX_URL=${PIP_INDEX_URL}是有效的,但是不必要的。不带值指定参数名称将使Docker从同名的环境变量中获取其值[2]

安全注意事项:如果有人运行docker history ${IMAGE_REPO_NAME},他们可以看到${PIP_INDEX_URL}的值[3]。然而,该令牌最多只能使用12小时,并且您可以使用aws codeartifact get-authorization-token--duration-seconds参数将其缩短至15分钟[4],因此可能是可以接受的。如果您的Dockerfile是多阶段构建,则如果您在目标阶段中未使用ARG PIP_INDEX_URL,则不应该是问题。目前,似乎不支持在CodeBuild中使用docker build --secret


1
谢谢!我会调查切换到这种方法。 - Tommy
1
Docker 是否会在令牌刷新后缓存 ARG PIP_INDEX_URL 之后的构建阶段?如果不能,是否有解决方法? - Roy Assis
1
@Roy 如果 PIP_INDEX_URL 的值发生变化,我相信缓存会从第一次引用 PIP_INDEX_URL 的那一行开始失效。为了解决这个问题,您可以在一个 单独的 Dockerfile 中创建某种构建器映像,并将该映像推送到映像仓库中。然后,在您最终的映像的 Dockerfile 中使用 FROM myrepo/mybuilder as builder COPY --from=myrepo/mybuilder /thing.py /app/thing.py 引用 映像。这样,您只需要在 requirements.txt 发生更改时手动重新创建构建器映像,而不是每次 PIP_INDEX_URL 更改时都重新创建。 - Phistrom

5

现在,我来分享一下我是如何解决这个问题的。看起来有点取巧,但它确实有效。(编辑:我们已经转而使用@phistrom的答案)

  1. 在预构建中,我运行了以下命令,并将 ~/.config/pip/pip.conf 复制到当前构建目录:
pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      ...
      - echo Fetching pip.conf for PYPI
      - aws codeartifact --region us-east-1 login --tool pip --repository ....
      - cp ~/.config/pip/pip.conf .
  build:
    commands:
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  1. 然后在 Dockerfile 中,我使用 COPY 命令将该文件复制到其中,执行 pip install 命令,然后删除它。
COPY requirements.txt pkg/
COPY --chown=myuser:myuser pip.conf /home/myuser/.config/pip/pip.conf
RUN pip install -r ./pkg/requirements.txt
RUN pip install ./pkg
RUN rm /home/myuser/.config/pip/pip.conf


使用这种方法,由于Docker镜像中分层文件系统的工作方式,您的pip.conf(以及其中包含的凭据)仍将包含在Docker镜像中,这并不是最佳实践。 - Snorfalorpagus
@Snorfalorpagus 这是真的;然而它只有12小时的有效期(文件将会失效)。但我同意,我们已经转而使用这里的另一个答案(它在此之后出现)。 - Tommy

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