docker实践入门之五:Dockerfile
image的派生
上面这个例子 有一个问题就是,如果应用程序修改了,就需要重新build一次,问题是重build的时候需要把前面一堆的命令都跑一遍,特别是安装软件那些还是挺慢 的,而且是不必要的重复工作,实际上我们只是修改了应用程序而已,所以更机智的办法是把这个image分成两个image,一个是python3基础环 境,一个是应用程序image。
先来python3环境的Dockerfile:
FROM alpine MAINTAINER raptor<[email protected]> COPY repositories /etc/apk/ RUN apk update \ && apk add python3 curl \ && curl -O https://bootstrap.pypa.io/get-pip.py \ && python3 get-pip.py \ && rm get-pip.py
这是python3基础image:
docker build -t python3 .
然后是应用程序Dockerfile:
FROM python3 MAINTAINER raptor<[email protected]> EXPOSE 5000 RUN mkdir /var/app COPY app /var/app/ WORKDIR /var/app/ RUN pip3 install -r requirements.txt CMD python3 start.py
然后创建应用程序image:
docker build -t app1 .
这样以后修改了应用程序只需要build第二个image即可。不过因为安装依赖包也是很慢的,还可以考虑再加一层image,作为应用程序的基础环境。
image的标签
image分层以后又会带来一个新的问题:比如我们用了三层image来部署两个应用A和B,最底层的是osimage,然后是py3image,然后是两个应用:Aimage, Bimage。
刚 开始总是很简单,直接按顺序一个个build即可。但是用了一段时间以后,比如应用B修改了,增加了一些新的依赖包,这时就需要重新build py3image,但是因为Aimage又依赖py3image,所以不一定能直接重build(比如A应用有些地方与新依赖包不兼容,可能需要A应用作 一些修改以后才能切过来),只能新建一个py3image2,然后让新的Bimage去依赖py3image2。那么以后要是os层也改了呢?再搞一个 osimage2吗?那分层的意义何在?如果不止两个应用,而是有十几个应用呢?那不是要麻烦死?
所以这时我们需要tag(标签)
tag在某种意义上相当于版本号,其中latest是一个特殊tag,如果在build image时不指定tag,默认就是这个,其好处就在于它总是对应于最新一个版本。
在 不指定tag的情况下,每次build一个同名的image,就是把它的latest给覆盖掉——不过如果这个image已经运行为container或 者有派生的image,则并不会被实际覆盖,只是旧版本会不显示,并且被标记为删除,一旦不再有其它引用,它才会被实际删除。
仍然以简单的AB两个应用的情况为例:
现在build一个baseimage,然后派生Aimage和Bimage。然后假设这时A应用需要有新的依赖,所以修改了baseimage,但是Bimage没有需要,暂时也不想跟着升级,则可以这样做:
docker tag baseimage baseimage:1
即生成一个版本号为1的baseimage。
注意,这个操作只是打个标签,并没有生成两个image,通过查看images可以知道,它们的ID是一样的。
docker images
这时用修改过的Dockerfile重新build:
docker build -t baseimage .
则会生成一个新的baseimage:latest,这时二者的ID就不一样了。而A应用的Dockerfile里只要保持这一句,它就始终是依赖latest的:
FROM baseimage
而B应用只要重新build一次,即可同样更新到新的latest,如果不想更新到latest,也可以修改Dockerfile,改成:
FROM baseimage:1
即可用旧版build。
以上的做法是在build新版前给旧版打标签,但实际上更好的做法是在build的同时就给新版打上标签,这样就可以很清楚地知道,从这个时间点以后生成的派生image默认都是用这个版本的base。
推送到[go4pro.org]