docker实践入门之四:创建Image

在前一个实践中,我们演示了如何使用现成的image来运行container供我们使用,这一节我们来试试自己建立image。

使用交互方式创建image

在第一篇文章里说过,通过对一个container执行commit操作可以创建一个image,这里先用这个方法做一个例子。

首先需要一个基本image,目前docker推荐的是用一个轻量级linux发行版:Alpine Linux,这个发行版的最大优点就是小,只有不到5M。

docker pull alpine
docker run -it alpine /bin/sh

现在进入了alpine的交互环境,为了方便在国内使用,首先修改/etc/apk/repositories文件,把默认的源改为ustc的:

https://mirrors.ustc.edu.cn/alpine/v3.3/main
https://mirrors.ustc.edu.cn/alpine/v3.3/community

官方源在国内速度太慢了。然后更新并安装python3环境:

apk update
apk add python3
apk add curl
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
rm get-pip.py

好了,现在可以执行exit退出交互环境,然后commit成一个新的image:

docker ps -a | grep Exit
docker commit xxxx alpine-py3

第一条命令查看刚才退出的那个container的ID是什么,然后把那个ID(XXXX)放到第二条命令里,即可生成一个叫alpine-py3的image。

注意,container ID不需要输入完整,只要前几位,保证唯一即可。

现在,可以来试试这个新的alpine-py3:

docker run -it alpine-py3 /bin/sh

现在这个交互环境里就是已经安装好py3的container了。

使用build命令自动创建

使用交互方式虽然看起来简单,但是实用性有限,最大的问题就是不能实现自动化操作——比如你需要一个新的image的时候,又要手工跑一堆命令,有没有办法让它自动构建呢?

当然有办法,那就用build命令,通过Dockerfile来创建image。

一个与上一例子一样结果的Dockerfile是这样的:

FROM alpine
MAINTAINER raptor<[email protected]>
RUN echo "https://mirrors.ustc.edu.cn/alpine/v3.3/main" > /etc/apk/repositories \
    && echo "https://mirrors.ustc.edu.cn/alpine/v3.3/community" >> /etc/apk/repositories \
    && apk update \
    && apk add python3 curl \
    && curl -O https://bootstrap.pypa.io/get-pip.py \
    && python3 get-pip.py \
    && rm get-pip.py

这 个文件算是一个比较简单的例子,只用到三个Dockerfile命令:FROM指定一个基础image,这里指定为alpine。MAINTAINER指 定这个Dockerfile的维护者,仅作为一个说明。RUN是最主要的命令,后面跟一个shell命令(就是前一个例子中交互操作时输入的命令)。

本来多个shell命令可以用多个RUN来跑,但是这里是用&&连接起来的一串。之所以这样用,是因为一个RUN会生成一个中间container,虽然之后会被删除,但总是多余的工作量,放在一起就可以避免这种事,build的时候可以稍微快一点。

然后用这样的命令即可生成一个新的image,image的名字叫做alpine-py3a:

docker build -t alpine-py3a .

注意,Dockerfile的文件名必须是Dockerfile,build命令中的“.”表示当前目录,也是Dockerfile所在的目录。之所以指定目录而不是Dockerfile文件,是因为还可以对目录中的其它文件进行操作。

现在用交互操作也可以打开一个已经安装好python3的环境:

docker run -it alpine-py3a /bin/sh

跟前一个例子一样。

往image里添加文件,创建一个实际应用

前一个例子是通过echo来修改repositories文件,当然也可以把改好的文件直接放到image里去替换掉。

...
COPY repositories /etc/apk/
RUN apk update ...

其中repositories就是改好的repositories文件,放在跟Dockerfile同一目录中。

现在以一个bottle的web应用为例,以下为应用包含的文件和目录:

start.py
requirements.txt
static
|-default.css

具体内容就不列了,只是举个栗子而已。其中start.py为主文件,requirements.txt为python依赖包,views目录下为模板文件index.html。

然后把这些全部放到Dockerfile所在的目录下的app子目录中。新的Dockerfile是这样的:

FROM alpine
MAINTAINER raptor<[email protected]>
EXPOSE 5000
COPY repositories /etc/apk/
RUN mkdir /var/app
COPY app /var/app/
WORKDIR /var/app/
RUN apk update \
    && apk add python3 curl \
    && curl -O https://bootstrap.pypa.io/get-pip.py \
    && python3 get-pip.py \
    && rm get-pip.py \
    && pip3 install -r requirements.txt
CMD python3 start.py

现在可以创建一个image并启动为一个微服务:

docker build -t app1 .
docker run -d -p 5000:5000 app1

这 个Dockerfile相对来说比较完整了,多了几个命令:EXPOSE是指定在docker内网中开放指定端口,注意,这个命令只对docker内网有 效,-p参数与这个命令无关,所以如果不在docker内网中使用服务的话,这条命令也可以不用。WORKDIR指定了container运行时默认的启 动目录,所以后面的requirements.txt和start.py都不需要指定目录。另外,COPY命令也与前面不同,因为这里是COPY目录,注 意,这里并不会把源目录一起COPY过来,所以并不会有/var/app/app这样的结果。

推送到[go4pro.org]