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]