我应该在Docker构建中运行composer install吗?

10

我可能拥有一个看起来像这样的Docker文件:

COPY . ./
RUN composer install --no-dev --no-interaction -o

但我在我的composer.json文件中有私有仓库,这需要我复制ssh密钥以使docker构建正常工作。将我的ssh密钥放在我的php应用程序docker镜像中让我感到不舒服。

另外,我可以在docker构建之外运行composer install(例如,在build.sh bash脚本中),并在vendor/目录填充后COPY该目录。这是正确的方法吗?

还有其他解决此问题的方法吗?

4个回答

10
This is a really good question which describes a principle that I've faced a few times now, actually two separate but related issues:
1.) 如何最好地处理Docker中的瞬态文件
Docker非常擅长封装环境的完全重建。如果你在容器外部处理部分流程,例如在docker build过程之外运行composer install,则你的构建过程会变得不太可移植,因为你可能引入了你不知道的机器/环境依赖项。
如果你总是在Docker内部重新构建整个环境,那么你就能保证你的依赖始终被满足,并且你可以将dockerfile交给任何其他人,他们也将有高度的信心能够在本地重新构建而不会出现问题。
瞬态文件非常适合在Docker内部构建!因此,我会尽可能在容器内部构建它们。
2.) 如何将授权与Docker构建过程解耦
这让我们进入第二个问题,如何将授权与构建过程解耦?
Option 1 - 预先使用具有专用构建用户凭据的composer auth.json:

正如其他答案所说,您可以“烘焙”凭据,然后再将其删除。但是,您不希望“烘焙”像ssh密钥这样敏感的东西。 Composer支持auth.json文件,为什么不创建一个专用的构建用户,并将其凭据(而不是您的凭据)存储在auth.json文件中?如果它被攻击了,您可以更改密码。一旦composer install完成,删除或覆盖该文件。

COPY . ./
RUN composer install --no-dev --no-interaction -o
RUN rm -f ./auth.json

选项二 - 使凭证本身是短暂的,并使用docker exec将它们传递到Docker容器中:

我尚未完全测试此方法,但我想不出为什么这样的方法不起作用。

1.) 您构建一个基础的PHP容器,该容器能够运行“composer install”(或者使用来自docker hub的容器)

2.) 您启动此基础容器,使其运行

3.) 您使用docker exec将凭证传递给已经包含在容器中的包装脚本。包装脚本将使用HTTP基本身份验证运行composer install - 它已经包含了用户名,因此您只需要提供密码,就像http-basic technique一样。

docker exec -d my_base_php_container php -f /my_wrapper_script.php ${PASSWORD}

4.) 您将此容器提交为新图像

docker commit --change "composer install" ${CONTAINER_ID} my_installed_image:1.0

1
那么,你认为在镜像内部构建的主要原因是拥有我需要的所有依赖项?为什么不使用专门用于构建的私有镜像,然后将创建的构件复制出来呢?这样,我就可以拥有一个一致的构建过程,没有预设的凭证或SSH密钥,而且我的部署镜像不会包含像Composer这样不必要的层。 - NiRR
2
是的,将所有依赖项放在镜像中确实可以提供一致性和可移植性。为什么不让我们的Docker容器创建构件呢?好问题,这是另一种好方法!这是我以前尝试过的一种方法,使用Maven Docker镜像,您可以向其中传递一个POM文件,它可以工作,但需要考虑以下几点:1)如果认证在docker外部,如何让其他人(包括构建服务器/流水线)也构建您的镜像?2)如何从容器中提取构件?(您可以使用卷挂载来实现此目的,但这可能会引入特定于环境的依赖项) - GreensterRox
1
对于NiRR和GreensterRox的+1赞成意见:我同意采用一个私有的docker容器的方法,因为1)你仍然可以获得一致性和可移植性,但2)由于是私有的,你在生产容器中没有composer——(PHP Composer)维护者建议不要在生产容器中使用composer:https://hub.docker.com/r/library/composer/ - therobyouknow

3
有趣。发布这个问题仅几天后,Docker 17.05被发布并为此带来了解决方案:多阶段构建。只需将composer内容放入dockerfile中并构建应用程序,然后启动第二个阶段并将应用程序作为第一个阶段的构建工件复制即可。

2
我认为在您描述的情况下,将composer install放在docker构建之外是有意义的。
通常情况下,您会有一个初始构建过程来构建您的应用程序代码。此构建可能会运行一些linting或自动化测试,然后生成包含运行应用程序所需的所有代码的artifact。这将由您的源代码、vendor文件夹和任何自动生成的代码(ORM类、缓存等)组成。这些artifact通常是tar文件。
然后,您将把该代码artifact复制到您后续的docker构建中的docker容器中。

我倾向于这种方法。我可能想在构建后测试图像,而不是之前,尤其是考虑到我可能需要运行mysql容器。为什么要打tar文件呢?我的最终图像可能是一个php / apache图像。 - NiRR

-1

您可以随时进行构建,它将复制 ~/.ssh,运行 composer install 然后删除 keys ... 之后,如果需要稍后使用 ssh - 在 docker-compose 中(或通常通过 -v)只需在运行期间使用卷/ -v 将 .ssh 挂载到本地即可 :)


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