将代码库烘焙到生产映像中

时间:2018-03-16 10:23:25

标签: git docker production-environment

我目前正在使用 git 在我的不同主机中部署我的应用程序。我的代码库被安装到运行 Docker镜像

搬运工-compose.yml

services:
    app:
        image: my.registry.net:5000/my/app
        volumes:
            - .:/app
# [...]

所以我的部署是这样的:

$ git pull
$ docker-compose build && docker-compose up -d
$ docker-compose exec app some_dependencies_installation_command
$ docker-compose exec app some_cache_clearing_command

对我来说似乎错误的原因很多,你可以想象。虽然如果出现问题我仍然可以恢复到我以前的git发布标签。

我想通过将代码库添加到映像中来简化部署,因此我不再使用git 进行部署,而是依赖图像提取。如果你不建议这样做以及为什么,请不要犹豫告诉我。

我很想简单地将我的代码库添加到我的图像的末尾,并在主机中只安装所需的东西:

Dockerfile

# [...]
ADD . /app

搬运工-compose.prod.yml

services:
    app:
        image: my.registry.net:5000/my/app
        volumes:
            - ./config.yml:/app/config.yml
            - ./logs:/app/logs
            - ./cache:/app/cache
            - ./sessions:/app/sessions
# [...]

因此,一旦构建,我只需要使用以下部署我的图像:

$ docker-compose pull && docker-compose up -d

这是一个好的方式吗?如何修改我的图片,以便在出现问题时还原(因为Dockerfile实际上从不更改)?另外,是不是每次都依赖于一层Dockerfile来拉动整个代码库而不仅仅是差异(就像使用git一样)?

3 个答案:

答案 0 :(得分:2)

将源代码绑定到容器上通常是为了在开发时具有快速反馈循环。这是通过避免在代码更改完成后重建映像来实现的。该技术主要用于本地开发目的。对于生产环境,不应使用此技术。

Docker镜像设计为独立的。图像所需的所有依赖项都应该打包在图像中。依赖于绑定挂载来提供源代码或依赖关系不是 建议因为生成的Docker镜像不可移植。无论何时切换到新计算机,都需要将该源代码和依赖项传输到该新计算机。

因此,建议的方法是将源代码添加到图像中。您还应该从标准的Docker工作流程中受益,您可以在其中构建图像,为其提供特定标记(通常是版本)和推送 它进入Docker存储库。从那时起,您只需拉动图像并在您拥有的任何计算机上启动它。

关于版本控制:构建图像时,使用源代码版本(或git标记或提交ID)标记它。

docker build -t <image-name>:<version> .

您还可以使用docker pull <image-name>:<version>提取特定版本。使用此技术,您始终可以恢复为任何版本的图像。

答案 1 :(得分:1)

docker-compose是docker的一个编排工具,但还有其他像kubernetes或docker swarm。你应该自己检查一下,考虑一下你可以使用这些工具的地方。

要对图像进行版本控制,您可以标记它们(使用-t)。因此,您将能够推出特定版本my.registry.net:5000/my/app:1.1.0等。

构建可以在您的计算机上本地完成,也可以在CI / CD管道中自动完成。

Docker不会提取代码库,只提取带文件的图层。如果编译程序,则只应添加二进制文件和一些资产。图层会被缓存,只在需要时才会启用。

如果要最小化注册表中的图像,可以在docker中使用多阶段构建。这使用多个阶段来构建最后一个容器,该容器仅为您的应用程序提供服务,因此需要的文件更少。例如。您可以使用javac在一个阶段编译二进制文件,使用nodejs和webpack在另一个阶段编译资产,并将生成的文件复制到最后一个只包含java运行时和静态生成资产的容器中。官方文档在这里:https://docs.docker.com/develop/develop-images/multistage-build/

答案 2 :(得分:1)

你是对的,你的方法有很多问题,包括:

  • Your containers are not ephemeral
  • 应用程序的每个实例都必须等待构建完成才能启动
  • 如果您的构建失败会怎样?不包括手动测试,您只能知道&#34;部署时间&#34;
  • 中的故障
  • 构建过程将在每次运行时生成相同的工件(前提是您未更改源)。为什么浪费时间重复这个过程?

不是在容器内烘焙应用程序的源代码并在每次部署时重建应用程序,而是可以构建应用程序(可能在另一个&#34; build&#34;容器中,如果您想构建构建环境也是可移植的,即用于构建的容器),并将构建产生的工件添加到将在生产环境中部署的另一个图像中(在测试和QA之后,因为你确实有多个环境,对吧?:)。 p>

Docker图像标记可以这样工作:在每次提交(可能在最新的图像标记下)和每个git标记(在相应的图像标记下)构建图像。示例:对于主分支上的每个提交,您需要更新&#34; your-image:latest当您标记1.0.0版本时,您会生成your-image:1.0.0

如果您有各种CI服务,您也可以自动执行此过程。

请注意,在生产中使用最新标记可能会导致环境不稳定,因为您不知道要部署的版本。使用另一个更具体的标签。

更新:正如其他人一直指出的那样,将您的资源放在容器中是一种可以应用于开发阶段的策略。但这不是你的情况,因为我假设你在谈论(预)生产过程。