在一套Dockerfile中完成编译和运行环境部署

大纲

  • 解释型语言
  • 编译环境
  • 解释环境
  • 编译型语言
    • 编译环境
    • 运行环境
  • 方法
    • 编译环境
      • 安装系统
      • 安装编译依赖
      • 下载代码
      • 特殊处理(可以忽略)
      • 编译准备(可以忽略)
      • 编译
      • 打包依赖(编译结果)
    • 运行环境
      • 安装操作系统
      • 安装运行时依赖
      • 复制编译结果和依赖
      • 暴露端口(非必须)
      • 重整目录
      • 运行时命令
    • 打包命令和运行命令
  • 效果
  • 参考资料

对于像C、C++这类编译型语言,编译器会直接将代码编译成二进制,然后在操作系统上执行。而像Java这类解释型语言,编译器(Java编译器是Java写的)会将代码编译成中间码,然后在虚拟机上执行,而虚拟机(Java虚拟机是C++写的,最后编译成二进制码)是在操作系统上执行的。
在这里插入图片描述
不管是编译型语言还是解释型语言,我们都可以把上述过程拆解为两部分

解释型语言

编译环境

在这里插入图片描述

解释环境

在这里插入图片描述
只是去除了Java代码和编译器,并不会让Docker产出的镜像小多少。

编译型语言

编译环境

在这里插入图片描述

运行环境

在这里插入图片描述
C、C++这类语言编译时期往往需要大量的资源,比如本文案例中,编译环境的镜像是2个多G,而运行环境这是1百多M,减少了93%的大小。

方法

我们可以在一套Dockerfile中,将编译环境的产出放置到运行环境,并且抛弃编译环境,只留下运行环境的镜像。

FROM ubuntu:22.04 as builder
RUN apt-get update && apt-get install -y binutils-dev uuid-dev libssl-dev python3 python3-pip cmake git zip
RUN pip3 install gil
RUN mkdir source
WORKDIR /source
RUN git clone https://github.com/chronoxor/CppServer.git
WORKDIR /source/CppServer/examples
COPY http_server_diff.patch ./http_server_diff.patch
RUN patch -p0 < http_server_diff.patch
WORKDIR /source/CppServer
RUN gil update
WORKDIR /source/CppServer/build
COPY unix_diff.patch ./unix_diff.patch
RUN patch -p0 < unix_diff.patch
RUN ./unix.sh
WORKDIR /source/CppServer
RUN zip -r www.zip www/

FROM ubuntu:22.04 as runner
RUN apt-get update && apt-get install -y libbinutils unzip
COPY --from=builder /source/CppServer/bin/cppserver-example-http_server /usr/local/bin/cppserver-example-http_server
COPY --from=builder /source/CppServer/www.zip /usr/local/bin/www.zip
EXPOSE 8080
WORKDIR /cppserver
RUN unzip /usr/local/bin/www.zip -d /cppserver
RUN apt remove -y unzip
RUN rm /usr/local/bin/www.zip
WORKDIR /cppserver/bin
RUN mv /usr/local/bin/cppserver-example-http_server ./cppserver-example-http_server
CMD ["cppserver-example-http_server"]

这段Dockerfile分为两部分

编译环境

安装系统

首先选择ubuntu 22作为基础系统。我们要保证运行环境和编译环境的操作系统版本是一致的。
as builder是标识我们要将其当做编译环境使用。在运行环境的Dockerfile中我们需要借此标识引用编译环境,来导出二进制编译结果等在运行环境中需要数据。

FROM ubuntu:22.04 as builder

安装编译依赖

安装好系统后,我们更新系统中包装管理软件(apt),以及安装编译代码时需要用的软件以及依赖(这一步,不同软件会需要不同的依赖)。

RUN apt-get update && apt-get install -y binutils-dev uuid-dev libssl-dev python3 python3-pip cmake git zip
RUN pip3 install gil

下载代码

准备好基础环境后,就可以下载代码了

RUN mkdir source
WORKDIR /source
RUN git clone https://github.com/chronoxor/CppServer.git

特殊处理(可以忽略)

因为我们使用的开源库,在设计上不太符合我们要求,导致一运行就会退出。于是我们对源码打了Patch。这块知识可以参考《代码打补丁的利器——diff和patch》

WORKDIR /source/CppServer/examples
COPY http_server_diff.patch ./http_server_diff.patch
RUN patch -p0 < http_server_diff.patch

http_server_diff.patch文件如下。它不再判断getline的返回值,而根据输入字母来决定是否退出还是重启。

--- http_server.cpp     2024-04-04 13:23:38.519576917 +0000
+++ http_server_bak.cpp 2024-04-04 13:52:57.483416162 +0000
@@ -221,17 +221,18 @@ int main(int argc, char** argv)
     server->Start();
     std::cout << "Done!" << std::endl;

-    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;
+    std::cout << "Press 'q' to stop the server or 'r' to restart the server..." << std::endl;

     // Perform text input
     std::string line;
-    while (getline(std::cin, line))
+    while (true)
     {
-        if (line.empty())
+       getline(std::cin, line);
+        if (line == "q")
             break;

         // Restart the server
-        if (line == "!")
+        if (line == "r")
         {
             std::cout << "Server restarting...";
             server->Restart();

这一段具有特异性,算是针对该项目的一个补丁。一般项目不太需要这个步骤。

编译准备(可以忽略)

这一步是该编译项目需要做的前置动作,不具有普遍性。

WORKDIR /source/CppServer
RUN gil update
WORKDIR /source/CppServer/build
COPY unix_diff.patch ./unix_diff.patch
RUN patch -p0 < unix_diff.patch

因为上一步我们修改了代码,导致这个开源项目的原始自动化测试不通过。上述补丁我们就是将自动化测试从流程中去除。
unix_diff.patch文件如下。

--- unix.sh     2024-04-04 14:01:10.668521739 +0000
+++ unix_bak.sh 2024-04-04 14:06:59.667047513 +0000
@@ -3,7 +3,6 @@ set -e
 cd Unix
 ./01-generate.sh
 ./02-build.sh
-./03-tests.sh
 ./04-install.sh
 if [[ "$doxygen" ]]; then
     ./05-doxygen.sh

编译

每个软件的编译指令不同。下面的指令只针对我们例子中的工程。

RUN ./unix.sh

打包依赖(编译结果)

因为我们这个工程是http服务器,它会用到www目录下的一些网页文件,所以我们需要用zip指令对它们进行打包,以方便后续统一搬运到运行环境。

WORKDIR /source/CppServer
RUN zip -r www.zip www/

运行环境

运行环境的命令和编译环境的命令是在一个Dockerfile中的。

安装操作系统

我们使用和编译环境一样的操作系统以及版本。

FROM ubuntu:22.04 as runner

安装运行时依赖

这一步我们安装的依赖就减少很多,主要是libbinutils 。它主要提供一些动态链接库,这些都是在运行时软件需要加载的公共库。
安装unzip是为了解压之前压缩的文件,后续我们会卸载它。

RUN apt-get update && apt-get install -y libbinutils unzip

复制编译结果和依赖

这一步我们将编译环境的编译结果cppserver-example-http_server拷贝到运行时环境,同时拷贝它依赖的一些文件。

COPY --from=builder /source/CppServer/bin/cppserver-example-http_server /usr/local/bin/cppserver-example-http_server
COPY --from=builder /source/CppServer/www.zip /usr/local/bin/www.zip

暴露端口(非必须)

cppserver-example-http_server 需要运行在8080端口上。

EXPOSE 8080

重整目录

这一步,我们会将之前复制过来的文件按照软件的要求重新部署目录结构。
另外我们卸载了为了搬运方便而安装的unzip软件。

WORKDIR /cppserver
RUN unzip /usr/local/bin/www.zip -d /cppserver
RUN apt remove -y unzip
RUN rm /usr/local/bin/www.zip
WORKDIR /cppserver/bin
RUN mv /usr/local/bin/cppserver-example-http_server cppserver-example-http_server

运行时命令

CMD ["./cppserver-example-http_server"]

打包命令和运行命令

docker build --pull --rm -f "Dockerfile" -t cppserver:latest "." 
docker container run -d -p 8080:8080 --name cppserver cppserver:latest cppserver-example-http_server

效果

在这里插入图片描述
我们删除了运行时Dockerfile,生成的镜像cppserver-builder,然后对比下它和运行时镜像的大小。
在这里插入图片描述

参考资料

  • 《代码打补丁的利器——diff和patch》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/517260.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ高级-应用问题、集群搭建

1.消息补偿 消息可靠性保障&#xff1a;——消息补偿机制 需求&#xff1a;100%确保消息发送成功 2.幂等性保障 幂等性指一次和多次请求某一资源&#xff0c;对于资源本身应该具有同样的结果。也就是说&#xff0c;其任意多次执行对资源本身所产生的影响均与第一次执行的影响…

AI编程005/ 逆向生成mysql的建表语句

1/ 通过insert into 语句生成建表语句 有些时候我们能获取到表的insert语句&#xff0c;但是没有表结构。我们可以借助AI工具&#xff0c;让其逆向生成mysql的建表语句。 提示词如下&#xff1a; 根据下面的SQL语句&#xff0c;逆向生存mysql的建表语句&#xff0c;每个字段…

Redis配置与优化

目录 引言 一、关系型数据库与非关系型数据库 1、关系型数据库 2、非关系型数据库 3、关系型数据库和非关系型数据库的区别 1.数据存储方式不同 2.扩展方式不同 3.对事物性的支持不同 4、非关系型数据库产生背景 二、Redis简介 1、Redis优点 2、Redis为什么这麽快&…

企业员工岗前培训管理系统的设计与实现(论文+源码)_kaic

摘 要 有效的处理想要的相关信息和如何传播有效的信息&#xff0c;一直是人类不断探索的动力。人类文明火种的传承都是通过了多种媒介作为载体&#xff0c;也是随着社会生产力的发展不断的更新。随着互联网的到来&#xff0c;信息传播与管理都上升了一个新的台阶&#xff0c;并…

基于单片机的全自动洗衣机系统仿真设计

**单片机设计介绍&#xff0c;基于单片机的全自动洗衣机系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的全自动洗衣机系统仿真设计概要是关于利用单片机技术实现全自动洗衣机控制功能的系统设计概述。以…

【5】JavaScript - 控制语句 循环[ for/while ]

控制语句 while/do...while 语句while 语句&#xff1a;do...while 语句&#xff1a;两者的区别无限循环 for 语句普通的 for 循环for...in 循环for...of 循环 循环过程&#xff1a;跳出/跳过跳出跳过 循环嵌套扩展延申&#xff1a;做一次杠精 当前 控制语句 章节主要介绍 循环…

【QT+QGIS跨平台编译】056:【pdal_kazhdan+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_kazhdan介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_kazhdan介绍 pdal_kazhdan 是 PDAL(Point Data Abstraction Library)相关的 Kazhdan 算法的实现。PDAL 是一个用于处理和分析点云数据的开源库,而 Kazhdan 算法通常…

【教学类-09-09】20240406细线迷宫图05(正方形)30格+动物+箭头(15CM横版一页-1份横版)

作品展示&#xff1a; 背景需求&#xff1a; 增加迷宫图的吸引力&#xff0c;起点的地方放一个小动物。 素材准备&#xff1a; 图片来自midjounery文生图&#xff08;四图&#xff09;&#xff0c;但同种动物只留1个&#xff08;如4个老鼠只保留一只老鼠&#xff09;&#xff…

YOLOv8 UI界面设计+热力图显示

进入可视化设计界面&#xff0c;设计UI pyside6-designer 设计好UI保存&#xff0c;然后通过以下命令将ui文件保存为py pyside6-uic myui.ui > myui.py 通过以下命令将资源文件qrc保存为py pyside6-rcc my_rc.qrc > my_rc.py 写主窗口函数实现功能... 项目基于yol…

React - 连连看小游戏

简介 小时候经常玩连连看小游戏。在游戏中&#xff0c;当找到2个相同的元素就可以消除元素。 本文会借助react实现连连看小游戏。 实现效果 实现难点 1.item 生成 1. 每一个图片都是一个item&#xff0c;items数组的大小为size*size。 item对象包括grid布局的位置&#xff0c;…

哈佛大学商业评论 -- 第二篇:增强现实是如何工作的?

AR将全面融入公司发展战略&#xff01; AR将成为人类和机器之间的新接口&#xff01; AR将成为人类的关键技术之一&#xff01; 请将此文转发给您的老板&#xff01; --- 本文作者&#xff1a;Michael E.Porter和James E.Heppelmann 虽然物理世界是三维的&#xff0c;但大…

【ORB-SLAM3】Ubuntu20.04 使用 RealSense D435i 运行 ORB-SLAM3 时遇到的一些 Bug

【ORB-SLAM3】使用 RealSense D435i 跑 ORB-SLAM3 时遇到的一些 Bug 1 hwmon command 0x80( 5 0 0 0 ) failed (response -7 HW not ready)2 No rule to make target /opt/ros/noetic/lib/x86_64-linux-gnu/librealsense2.so, needed by ../lib/libORB_SLAM3.so 1 hwmon comman…

Tomcat调优总结

Tomcat自身的调优是针对conf/server.xml中的几个参数的调优设置。首先是对这几个参数的含义要有深刻而清楚的理解。以tomcat8.5为例&#xff0c;讲解参数。 同时也得认识到一点&#xff0c;tomcat调优也受制于linux内核。linux内核对tcp连接也有几个参数可以调优。 因此可以将…

intellij idea 使用git ,快速合并冲突

可以选择左边的远程分支上的代码&#xff0c;也可以选择右边的代码&#xff0c;而中间是合并的结果。 一个快速合并冲突的小技巧&#xff1a; 如果冲突比较多&#xff0c;想要快速合并冲突。也可以直接点击上图中 Apply non-conflicting changes 旁边的 All 。 这样 Idea 就会…

构建未来交通:香橙派OPI Airpro上的智能交通监管系统

引言&#xff1a; 随着城市化进程的加速&#xff0c;交通管理变得越来越复杂。 传统的交通监管系统往往无法有效应对日益增长的车辆数量和复杂的交通状况。因此&#xff0c;我们需要一种更加智能和自适应的解决方案来提高交通效率并减少事故发生率。 香橙派OPI Airpro以其强大的…

什么是redis缓存的雪崩、穿透以及击穿

缓存雪崩 举个例子&#xff0c;例如在双十一中&#xff0c;一点进去。访问量大&#xff0c;所以它很多数据是放在redis区缓存起来&#xff0c;对应redis的100个key。然后假设设置缓存失效时间是三小时。当双十一期间&#xff0c;购物超过这个三小时之后。这个首页的redis缓存会…

LeetCode十一题:容纳最多水的容器【11/1000 python】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 LeetCode解锁1000题: 打怪升级之旅htt…

信息系统项目管理师——第18章项目绩效域管理(一)

本章节内容属于第四版新增知识&#xff0c;为PMBOK第七版专有&#xff0c;选择、案例、论文都会考&#xff0c;属于比较重要的章节。 选择题&#xff0c;稳定考3分左右&#xff0c;新教材基本考课本原话&#xff0c;需要多读课本&#xff0c;多刷题。 案例题&#xff0c;考的概…

SpringBoot快速入门笔记(3)

文章目录 一、MybatisPlus1、ORM2、添加依赖3、全局配置4、Navicat5、UserController6、CRUD操作7、BaseMapper8、两个注解 二、多表查询1、模拟用户订单2、通过用户查相关订单3、UserMapperNew4、查询订单和所属用户5、OrderMapper6、OrderController 三、条件查询四、分页查询…

C++之类

目录 一&#xff1a;面向过程和面向对象的初步认识 二&#xff1a;类的引入 三&#xff1a;类的定义 3.1类的两种定义方式&#xff1a; 3.2成员变量命名的建议 四&#xff1a;类的访问限定符及封装 4.1类的访问限定符 4.2封装 一&#xff1a;面向过程和面向对象的初步认…