技术背景

基于已有的Docker容器镜像,去创建一个本地的镜像,有两种方法:一种是在之前的博客中提到过的,使用docker commit的方案,也就是先进去基础系统镜像内部完成所需的修改,然后commit到一个新的容器内部;还有另外一种也非常常用的方法,就是写一个Dockerfile,在本文中会作简单介绍。

另外我们在上一篇博客中介绍了如何部署与使用IBM主导的Cplex线性规划求解器的一些基本使用方法。在本文中我们会介绍另外一套由Google主导的开源线性规划求解器ortools的部署与基本使用方法。

Dockerfile的创建

对于简单的场景而言,尤其是别人已经把基础容器镜像做的比较完善的情况下,使得我们减少了大量的工作量。比如这里我们直接使用一个别人做好的python3.7的基础镜像,而获得该镜像的方法在上一篇博客中也作了介绍。那么我们在dockerfile里面只需要安装好我们所需要的ortools的python包即可:

[dechin-root ortools]# cat Dockerfile
FROM rackspacedot/python37
RUN python3 -m pip install pip --upgrade \
&& python3 -m pip install ortools

这里FROM后面所跟随的基础镜像是必须在本地所具备的,可以在docker images里面看到的才行。最好也在本地通过运行docker run your_iamge来测试一下这个容器镜像是否正常工作,因为有些容器镜像必须要跟随版本号才能正常使用。在上述dockerfile中我们先对pip管理工具做了一个升级,然后才安装ortools工具包。有一个需要注意的点是,我们也可以选择使用多次的RUN来制作一个dockerfile,但是这会导致添加了多层的镜像,因此最好我们是可以用命令拼接的方式一次性完成所有的任务,这样只会增加一层镜像(截图来自于参考链接2):

按照上述流程编写好dockerfile之后,我们就可以使用docker build来构建一个本地的容器镜像:

[dechin-root ortools]# docker build -t dechin/ortools:v1 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM rackspacedot/python37
---> ab7083b6c7c4
Step 2/2 : RUN python3 -m pip install pip --upgrade && python3 -m pip install ortools
---> Running in ff6b1971bdc9
Requirement already satisfied: pip in /usr/local/lib/python3.7/site-packages (20.3.1)
Collecting pip
Downloading pip-21.0.1-py3-none-any.whl (1.5 MB)
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 20.3.1
Uninstalling pip-20.3.1:
Successfully uninstalled pip-20.3.1
Successfully installed pip-21.0.1
Collecting ortools
Downloading ortools-8.2.8710-cp37-cp37m-manylinux1_x86_64.whl (14.2 MB)
Collecting protobuf>=3.14.0
Downloading protobuf-3.15.6-cp37-cp37m-manylinux1_x86_64.whl (1.0 MB)
Collecting absl-py>=0.11
Downloading absl_py-0.12.0-py3-none-any.whl (129 kB)
Requirement already satisfied: six in /usr/local/lib/python3.7/site-packages (from absl-py>=0.11->ortools) (1.15.0)
Installing collected packages: protobuf, absl-py, ortools
Successfully installed absl-py-0.12.0 ortools-8.2.8710 protobuf-3.15.6
Removing intermediate container ff6b1971bdc9
---> b9ff988385a5
Successfully built b9ff988385a5
Successfully tagged dechin/ortools:v1

我们可以看到2条dockerfile的指令的运行结果都在屏幕上输出,显示是成功安装了的。在执行完build之后,我们可以在本地的images仓库里面看到这个新的容器镜像:

[dechin-root ortools]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dechin/ortools v1 b9ff988385a5 35 seconds ago 1.09GB

我们也可以测试一下这个容器镜像的功能是否正常:

[dechin-root ortools]# docker run -it dechin/ortools:v1 /bin/bash
root@198255eacb30:/# python3
Python 3.7.9 (default, Nov 18 2020, 14:29:12)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ortools
>>>

通过执行一个简单的python指令我们可以看到ortools这个工具已经被成功的部署在容器镜像内,在下一个章节中我们会介绍如何使用ortools来解决一个实际问题。当然,上述测试方案也有一个更加简单的方法,使用-c标签来运行代码:

[dechin-root ortools]# docker run dechin/ortools:v1 python3 -c "import ortools;print('hello')"
hello

这里再补充介绍一下在docker中如何删除一个容器镜像的方法,那就是使用rmirm指令。这两个指令也容易区分,如果是在docker images指令下找到的容器镜像,那就用rmi来进行删除,如果是在docker ps里面看到的容器,那就用rm来删除,以下是两个示例:

[dechin-root ortools]# docker rmi cplex-py37
Error response from daemon: conflict: unable to remove repository reference "cplex-py37" (must force) - container 7ce9dbee3e55 is using its referenced image 34e272969701
[dechin-root ortools]# docker rmi -f cplex-py37
Untagged: cplex-py37:latest
Deleted: sha256:34e2729697010b1320c2f7dbfd1fc45004e9ffae6a1d26ffb8748b5627cb2224

上面这个用例是表示我们在docker images中有一个名为cplex-py37的容器镜像,其实也是在上一篇博客中制作的产物。假如我们需要删除这个镜像,就用删除的rmi指令。当我们第一次尝试删除的时候,我们收到一个提示,关于一些冲突的提示。假如我们认定了这个冲突并不影响我们的操作,那么我们可以强制删除,也就是加上-f指令。

另外也展示一下rm指令的使用场景。假如我们使用docker ps -n 5查看过去执行的最近5条指令,并且需要删除第一条镜像id为2df3的容器:

[dechin-root ortools]# docker ps -n 5
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2df3fcc803e0 34e272969701 "/bin/bash" 20 hours ago Exited (0) 20 hours ago bold_colden
c766ed62d149 rackspacedot/python37 "/bin/bash" 20 hours ago Exited (0) 20 hours ago xenodochial_ardinghelli
af037db88540 cplex "/bin/bash" 21 hours ago Exited (0) 12 minutes ago magical_cori
e8c49c211039 cplex "/bin/bash" 21 hours ago Exited (0) 21 hours ago gracious_babbage
1e053a1b6330 cplex "/bin/bash" 21 hours ago Exited (0) 21 hours ago suspicious_ride
[dechin-root ortools]# docker rm 2df3
2df3
[dechin-root ortools]# docker ps -n 5
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c766ed62d149 rackspacedot/python37 "/bin/bash" 20 hours ago Exited (0) 20 hours ago xenodochial_ardinghelli
af037db88540 cplex "/bin/bash" 21 hours ago Exited (0) 12 minutes ago magical_cori
e8c49c211039 cplex "/bin/bash" 21 hours ago Exited (0) 21 hours ago gracious_babbage
1e053a1b6330 cplex "/bin/bash" 21 hours ago Exited (0) 21 hours ago suspicious_ride
de7f22ac259b cplex "python3 -m pip inst…" 21 hours ago Exited (0) 21 hours ago hardcore_meitner

可以看到用rm删除之后就不会在最新的结果查询中出现这个容器,这也方便我们释放不需要的容器资源给本地环境。

ortools案例

这里我们还是使用上一篇博客中所提到的单背包问题(Knapsack Problem)来进行测试。相关问题的定义如下:



当然在ortools的案例中我们不需要写lp文件,只是借用这个lp文件来展示一下我们的约束条件和目标函数。这个问题的含义也在上一篇博客中介绍过了,这里我们直接截图引用:

ortools求解器的使用

在了解清楚问题的背景之后,现在我们就可以开始写测试代码了,首先我们也是从进入docker容器开始,然后出于方便我们直接在python指令中执行相关的测试(这里的测试代码我们参考了官方文档,也就是本文的参考链接1):

[dechin-root ortools]# docker run -it dechin/ortools:v1 /bin/bash
root@3882b83959c8:/# python3
Python 3.7.9 (default, Nov 18 2020, 14:29:12)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ortools.linear_solver import pywraplp
>>> solver = pywraplp.Solver.CreateSolver('SCIP') # 这里使用了第三方后端SCIP
>>> x1 = solver.IntVar(0.0, 1.0, 'x1')
>>> x2 = solver.IntVar(0.0, 1.0, 'x2')
>>> x3 = solver.IntVar(0.0, 1.0, 'x3')
>>> print ('Number of variables = ', solver.NumVariables()) # 参数数量
Number of variables = 3
>>> solver.Add(3 * x1 + 4 * x2 + 5 * x3 <= 8)
<ortools.linear_solver.pywraplp.Constraint; proxy of <Swig Object of type 'operations_research::MPConstraint *' at 0x7f9013411de0> >
>>> solver.Maximize(2 * x1 + 3 * x2 + 4 * x3)
>>> status = solver.Solve()
>>> print('Number of constraints =', solver.NumConstraints()) # 约束条件数量
Number of constraints = 1
>>> print('Objective value =', solver.Objective().Value()) # 最终解的函数值
Objective value = 6.0
>>> print('x1 =', x1.solution_value())
x1 = 1.0
>>> print('x2 =', x2.solution_value())
x2 = 0.0
>>> print('x3 =', x3.solution_value())
x3 = 1.0
>>> print (status == pywraplp.Solver.OPTIMAL) # 是否最优解?
True

在这个案例中我们使用了一个第三方的求解器后端来进行计算,叫SCIP。我们得到的最终解已经达到了最优解,这个我们在上一篇博客中也分析过了。到这里为止,我们就成功的使用ortools提供的框架求解了一个实际的背包问题。

总结概要

在本地构建基于Docker的编程环境是一个兼容性和可用性非常强的解决方案,这里我们介绍了一个使用Dockerfile来构建Docker容器镜像的简单实例。同时也用谷歌所主导的开源线性规划求解器ortools来测试这个容器化的编程环境解决方案,最终我们用ortools成功的求解了一个单背包问题,并且跟前面一篇博客中所介绍的IBM主导的cplex一样都得到了问题的最优解。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/ortools.html

作者ID:DechinPhy

更多原著文章请参考:https://www.cnblogs.com/dechinphy/

参考链接

  1. https://developers.google.cn/optimization/mip/integer_opt?hl=zh-cn
  2. https://www.runoob.com/docker/docker-dockerfile.html
  3. https://www.cnblogs.com/dechinphy/p/cplex.html#

创建ortools的Dockerfile的更多相关文章

  1. centos7下安装docker(3.3创建镜像--修改dockerfile)

    1.我们在制作dockerfile的时候可能有些命令无法执行,导致镜像无法创建成功,这时我们可以修改dockerfile,从而达到我们的目的 查看Dockerfile内容 创建新的镜像,失败 Dock ...

  2. docker镜像的创建commit及dockerfile

    在docker 1.3版本以前使用attach进入容器会经常出现卡死的情况,之后官方退出了exec命令,从宿主机进入,但是从其他远程主机进入使用ssh服务来维护是用户熟悉的方法.所以这里来创建一个带有 ...

  3. 如何用Dockerfile创建镜像

    本文原创,原文地址为:http://www.cnblogs.com/fengzheng/p/5181222.html 创建镜像的目的 首先说DockerHub或其它一些镜像仓库已经提供了够多的镜像,有 ...

  4. Docker(2):使用Dockerfile创建支持SSH服务的镜像

    1.创建工作目录 # mkdir sshd_ubuntu # ls 在其中,创建Dockerfile和run.sh文件 # cd sshd_ubuntu/ # touch Dockerfile run ...

  5. docker学习系列(二):使用Dockerfile创建自己的镜像

    dockerfile可以允许我们自己创建镜像,通过编写里面的下载软件命令,执行docker build 即可生成镜像文件. 初尝dockerfile 新建一个目录test,然后进入这个目录,创建一个名 ...

  6. 基于alpine用dockerfile创建的ssh镜像

    1.下载alpine镜像 [root@docker43 ~]# docker pull alpine Using default tag: latest Trying to pull reposito ...

  7. 使用 dockerfile 创建镜像

    dockerfile 是一个文本格式的配置文件,可以使用 dockerfile 快速创建自定义的镜像. dockerfile 一般包含4部分信息:基础镜像信息.维护者信息.镜像操作指令.容器启动时执行 ...

  8. 「两」创建一个带 ssh 镜座服务(修订版)--采用 Dockerfile 创

    创建目录 首先,创建一个叫做 sshd_ubuntu 的目录,用于存放我们的 Dockerfile .脚本文件.以及其它文件. $ mkdir sshd_ubuntu $ ls sshd_ubuntu ...

  9. 创建的docker容器时间显示错误/date错误/时区错误

    前几天在测试应用的功能时,发现存入数据库中的数据create_time或者update_time字段总是错误,其他数据都是正常的,只有关于时间的字段是错误的. 进入linux服务器中查看,也没有任何的 ...

随机推荐

  1. React Gatsby 最新教程

    React Gatsby 最新教程 https://www.gatsbyjs.com/docs/quick-start/ https://www.gatsbyjs.com/docs/tutorial/ ...

  2. 吐槽 Apple iPhone 十大反人类的设计 All In One

    吐槽 Apple iPhone 十大反人类的设计 All In One 不支持 GPS 快捷开关 每次都要到,设置> 隐身 > 位置,脑残的设计 顶部的状态栏,网络不支持显示网速 顶部的状 ...

  3. CSS & new class name

    CSS & new class name { test: /\.((s*)css|sass)$/, // test: /\.(css|scss|sass)$/, use: ExtractTex ...

  4. learning-js-by-reading-source-codes

    learning-js-by-reading-source-codes BigInt https://github.com/learning-js-by-reading-source-codes/lo ...

  5. ES6 Arrow Function return Object

    ES6 Arrow Function return Object https://github.com/lydiahallie/javascript-questions/issues/220#issu ...

  6. eui & search select

    eui & search select https://element.eleme.io/#/zh-CN/component/select demo <template> < ...

  7. modal over table bug

    modal over table bug table can not clickable bad <el-row> <el-col :span="24"> ...

  8. iPad pro & Mac mini

    iPad pro & Mac mini

  9. banner自用图床2

  10. 生产者和消费者问题(synchronized、Lock)

    1.synchronized的生产者和消费者 synchronized是锁住对象 this.wait()释放了锁 并等待 this.notify()随机通知并唤醒同一个对象中的一个线程 this.no ...