使用Docker构建已编译的应用程序

Ale*_*nko 13 c++ deployment docker docker-compose

我正在构建一个用C++编写的服务器,并希望使用Docker和docker-compose来部署它.这样做的"正确方法"是什么?我应该make从Dockerfile 调用还是手动构建,从Dockerfile上传到某个服务器然后上传COPY二进制文件?

Mat*_*ice 23

我在构建自动化时遇到了困难,docker-compose我最终使用docker build了所有内容:

三层用于建筑

运行 - >开发 - >构建

然后我将构建输出复制到"部署"图像中

运行 - >部署

四层玩:

  • 包含应用程序运行所需的任何包
    • 例如libsqlite3-0
开发
  • FROM <projname>:run
  • 包含构建所需的包
    • 例如g ++,cmake,libsqlite3-dev
  • Dockerfile执行任何外部构建
    • 例如,构建boost-python3的步骤(不在包管理器repo中)
建立
  • FROM <projname>:develop
  • 包含来源
  • Dockerfile执行内部构建(经常更改的代码)
  • 从此映像复制已构建的二进制文件以用于部署
部署
  • FROM <projname>:run
  • 构建的输出复制到映像并安装
  • RUNENTRYPOINT用于启动应用程序

文件夹结构如下所示:

.
??? run
?   ??? Dockerfile
??? develop
?   ??? Dockerfile
??? build
?   ??? Dockerfile
?   ??? removeOldImages.sh
??? deploy
    ??? Dockerfile
    ??? pushImage.sh
Run Code Online (Sandbox Code Playgroud)

设置构建服务器意味着执行:

docker build -f run -t <projName>:run
docker build -f develop -t <projName>:develop
Run Code Online (Sandbox Code Playgroud)

每次我们进行构建时,都会发生这种情况:

# Execute the build
docker build -f build -t <projName>:build

# Install build outputs
docker build -f deploy -t <projName>:version

# If successful, push deploy image to dockerhub
docker tag <projName>:<version> <projName>:latest
docker push <projName>:<version>
docker push <projName>:latest
Run Code Online (Sandbox Code Playgroud)

我将人们引用到Dockerfiles作为有关如何构建/运行/安装项目的文档

如果构建失败并且输出不足以进行调查,我可以/bin/bash进入<projname>:build并四处查看出现了什么问题


编辑

我围绕这个想法组成了一个github回购.它适用于c ++,但你可以将其用于任何事情.

https://github.com/MatrixManAtYrService/lifecycle-snapshots

  • 看起来很酷。我很乐意使用HelloWorld C ++示例(包含所有4个docker文件和两个shell文件...)来查看您的Github存储库。感谢您的共享。 (2认同)

blu*_*kin 6

我的建议是完全开发,构建和测试容器本身.这确保了Docker的理念,即开发人员的环境与生产环境相同https://blog.newrelic.com/2016/06/20/docker-osx-mac/ 特别是在C++应用程序中,通常存在依赖关系使用共享库/目标文件.

我不认为存在用于在Docker上开发,测试和部署C++应用程序的标准化开发过程.要回答您的问题,我们现在的处理方式是将容器视为您的开发环境,并在团队中执行一系列实践,例如:

  1. 我们的代码库(配置文件除外)总是存在于共享卷上(在本地机器上)(在Git上版本化)
  2. 共享/依赖库和二进制文件等... 总是存在于容器中
  3. 在容器上构建和测试,并在提交图像之前清理不需要的对象文件,库等...并确保docker diff更改符合预期
  4. 对环境的更改/更新(包括共享库,依赖项)始终记录并与团队进行通信.


Mis*_*man 5

我这样做的方法是在容器外部运行构建,只将构建的输出(二进制文件和任何必需的库)复制到容器中.然后,您可以将容器上载到容器注册表(例如,使用托管的容器或运行自己的容器),然后从该注册表中提取到生产计算机上.因此,流程可能如下所示:

  1. 建立二进制
  2. test/sanity-检查二进制文件本身
  3. 用二进制构建容器图像
  4. test/sanity - 使用二进制文件检查容器图像
  5. 上传到容器注册表
  6. 部署到staging/test/qa,从注册表中提取
  7. 部署到prod,从注册表中拉出来

由于在生产部署之前进行测试非常重要,因此您希望测试与生产中部署完全相同的内容,因此您不希望在构建之后以任何方式提取或修改Docker镜像.

我不会您计划在prod中部署的容器中运行构建,因为那时您的容器将具有您在生产中不需要的各种其他工件(例如临时构建输出,工具等)并且不必要地增长您的容器图像包含您不会用于部署的内容.

  • 这个解决方案并不完全符合Docker的理念.这可能导致同样的老问题"哦!!但它在我的机器上工作".除非C++应用程序具有很少或没有依赖关系并且不依赖于共享对象文件(.so文件),否则此解决方案将导致链接不正确版本的依赖项 - blueskin 49分钟前 (8认同)

fug*_*ede 5

虽然其他答案中提出的解决方案——特别是 Misha Brukman 在对这个答案的评论中关于使用一个 Dockerfile 进行开发和一个用于生产的建议——在编写问题时被认为是惯用的,它应该需要注意的是,他们试图解决的问题——特别是清理构建环境以减小镜像大小的问题,同时仍然能够在开发和生产中使用相同的容器环境——已经通过多方有效地解决了。stage builds,这是在 Docker 17.05 中引入的。

这里的想法是将 Dockerfile 分成两部分,一部分基于您最喜欢的开发环境,例如成熟的 Debian 基础映像,它与创建您想要在最后部署的二进制文件有关。 day,另一个只是在最小环境(例如 Alpine)中运行构建的二进制文件。

通过这种方式,您可以避免开发环境和生产环境之间可能存在的差异,正如 blueskin 在其中一条评论中所暗示的那样,同时仍确保您的生产映像不会被开发工具污染。

该文档提供了以下 Go 应用程序的多阶段构建示例,然后您可以将其应用于 C++ 开发环境(一个问题是 Alpine 使用musl,因此在开发环境中链接时必须小心)。

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
Run Code Online (Sandbox Code Playgroud)