在笔记本上主要还是想以轻量、方便为主,所以采用的是在WSL2中使用docker的这么一个方案。
WSL2
我笔记本原来是预装的是WIN10家庭版,需要先升级为专业版,并加入windows预览体验计划。更新完之后,安装WSL,我选择的是Ubuntu16.04,并且升级到WSL2[1],就可以支持docker了。
在WSL2中安装docker-ce[2]。因为WSL2中没法正常的使用systemctl,我参考了韦易笑的文章[3]对docker做了自启动。
Why docker?
- 环境隔离,相当于轻量级的虚拟机
- 可更新、可扩展,一次配置,到处享用
- 一键部署
镜像与容器
镜像与容器是我们接触得最多的东西和基本的概念。镜像是一个只读的模板,它可以包含一个完整的linux系统、软件和其它运行环境。docker利用容器来运行应用,容器是镜像的运行实例,每个容器都是相互隔离的。
Hello world
我们从hello-world,来看看docker运行容器的流程。
安装完docker后,为了不用每次运行docker命令都需要加上sudo,需要先将用户加入docker用户组:sudo adduser $USER docker
。然后登出账户,再登陆即可。
完了我们运行docker官方的hello-world,看看能否正常运行:docker run -rm hello-world
这条命令的意思是,从hello-world
镜像创建一个容器并运行容器。
容器被创建后,可以启动(start)和停止(stop),不需要之后可以删除。一个容器在程序运行完成后会自动停止,但是容器不会被自动删除。--rm
参数是让容器运行完成、停止后自动删除该容器。 我们可以通过docker ps -a
命令查看已存在的容器。
从图中第二、三行可以看到,docker在从镜像创建容器时,首先会查找本地镜像。当本地查找不到时,会从仓库查找。这里的仓库概念和github、maven的仓库概念类似,默认是从官方的dockerhub查找,可以自行添加其它镜像源。
此外,我们运行nginx测试一下在容器中运行web服务,执行命令docker run nginx
。我们可以通过localhost来访问WSL2中的服务:
创建开发环境
一般情况下,我们不需要自己从头制作一个镜像,可以在别人做好的镜像上进行二次制作。以python的flask程序为例,可以把python3.6的镜像作为基础镜像:docker pull python:3.6
其中冒号后面的3.6是tag,如果不加tag的话默认是latest。
然后从该镜像中运行一个容器实例:docker run -it --name="flask" python:3.6 /bin/bash
可以看到,其实容器内是有一个完整的文件系统的,并且容器内安装好了python 3.6.10。 关于命令,-i是以交互的形式运行容器,-t是为其分配一个伪输入终端,--name="flask"则是为该容器创建一个别名。之后我们可以用docker start/stop flask
之类的命令来启动或停止该容器。
接着我们在容器容器内的根目录创建一个名为app
的文件夹(后来发现不用手动创建),为的是之后将宿主机(WSL2)的目录直接映射到docker容器中,就省去了将宿主机的代码传到docker容器这个步骤。并且这种方式对安全、以及数据持久化来说都有帮助。
然后根据需要,在容器内安装flask:pip install flask
,并用docker commit 4f6 eagle/flask
命令保存新的镜像。4f6是容器的id,和git的版本号有些类似,后面是新镜像的名字。可以看到,由于安装flask,镜像的尺寸也比原来大了一些。
这样我们开发环境的镜像就创建完成了,接下来要测试一下是否可行。先删除之前的容器或者运行容器时指定其它的别名,然后使用命令创建新的容器:
docker run -it --name="flask" -p 5555:2333 -v /home/eagle:/app eagle/flask /bin/bash
其中-p 5555:3333
是将宿主机的5555
端口映射到容器的2333
端口,-v /home/eagle:/app
则是将宿主机的目录映射到容器的app
目录。
接着写一个简单的flask测试程序,来看看这个容器是否能否充当开发环境。在宿主机创建app.py
文件并写入以下代码:
from flask import Flaskapp = Flask(__name__)@app.route('/')
def hello():return 'flask in docker'if __name__ == '__main__':app.run(host='0.0.0.0', port=2333)
在docker容器中运行python app.py
启动flask服务,并在浏览器中查看结果:
环境移植
接下来我们要考虑如何把自己制作好的镜像移植到别的机子上,做到“一次配置,到处享用”。很简单,导出镜像和导入镜像只需要:
docker save eagle/flask > flask-docker-image.tar.gz
docker load < flask-docker-image.tar.gz
但是,我们的问题不在于此。从前面可以看到,我们制作好的镜像足足有900+MB那么大,能不能有什么办法可以使镜像小一些呢?
答案是肯定的!那就是使用alpine版本的python镜像。alpine[4]是一个超轻量级的linux系统,只有5MB的大小,而dockerhub[5]上也提供了python的alpine版本镜像。
运行命令docker pull python:3.6-alpine
下载镜像,然后对比一下几个镜像的大小,可以看到这个镜像也只有95MB,仅占原来的十分之一:
即使安装了flask,也才105MB,并且程序可以正常运行,测试过程和结果和之前差不多,就不赘述了。
另外我这里采用的是在容器中安装依赖和用目录映射,做开发环境的搭建。至于制作镜像和镜像瘦身,还有别的方法[6],等我实际用到的时候再把这部分的坑填了吧。
结语
docker提供的容器化方案为我们日常的开发和部署提供了很大的便捷,所以受到许多人的青睐。但是做机器学习的话,还需要考虑到调用显卡这回事,目前Nvidia官方也提供了nvidia-docker这么个东西。因笔记本没有显卡,无法测试,日后也会把这部分的坑填上,判断其是否能作为日常开发的环境。
参考
- ^如何在 Windows 10 中安装 WSL2 的 Linux 子系统 https://blog.csdn.net/WPwalter/article/details/101508601
- ^Docker Ce | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/
- ^WSL服务自启动的正确方法 https://zhuanlan.zhihu.com/p/47733615
- ^Docker之操作系统Alpine_菲宇运维-CSDN博客 https://blog.csdn.net/bbwangj/article/details/81088231
- ^python - Docker Hub https://hub.docker.com/_/python/
- ^Docker Layers Explained - DZone Cloud https://dzone.com/articles/docker-layers-explained