DOCKER 03:镜像制作 Dockerfile

本文主要谈谈如何使用 Dockerfile 制作一个自己定制的镜像!

现有容器制作成镜像

我们可以将依据运行的容器,通过我们的自定义修改,然后制作成镜像,举个例子,我们运行一个 busybox 的镜像:

docker run -it --name b1 busybox /bin/sh

在内部运行一个死循环:

while true;do echo $(date) > /tmp/123.txt && sleep 5;done &

然后 ctrl + p + q 退出,结果如图:

将该容器目前的状态制作成为镜像:

docker container commit b1 busybox:v1.0

查看镜像:

此时我们使用这个镜像构建容器试试:

可以看到文件得以保留下来,但是进程却没有。

使用 Dockerfile 制作镜像

Dockerfile 其实就是一个配置文件,格式都差不多,主要就是几个关键字的使用,当然,本文这里还只是简单的 Dockerfile 的编写。

其主要的关键字包含以下一些:

关键字 说明
FROM 基于那个镜像,如:FROM nginx:latest。如果没有基于的镜像则 FROM scratch
LABEL 老版本中叫 MAINTAINER,脚本说明,也算是打标签,如:LABEL author="Dylan" email="[email protected]"
RUN 你想执行的操作,多个操作建议使用 && 连接,这样能够减少镜像分层,每个 RUN 一层,\ 可以换行
WORKDIR 类似于 linux 的 cd 命令,进入该目录
ADD 添加当前目录的指定文件或者目录到指定目录,如果文件是 tar 压缩文件会自动解压,如果文件是 url 则不会解压
COPY 和 ADD 类似,只是少了解压功能
ENV 设置环境变量,能够被文件调用,如 ENV MYSQL_VERSION 5.7
ENTRYPOINT 容器启动时的命令,一定会执行
CMD RUN 是在构建镜像时执行,CMD 是容器启动后默认的运行命令,但是如果 docker run 的时候后面有命令,如 /bin/sh,则 CMD 不会执行,多个 CMD 也只会执行最后一个。
EXPOSE 服务的端口

至于更复杂的写法,可以参照 MySQL 5.7 的官方 Dockerfile:

https://github.com/docker-library/mysql/blob/master/5.7/Dockerfile

Dockerfile 实例

这里以一个 flask 项目代码实战为例:

1. 现在服务器上面新建一个目录用于存放该项目:

mkdir flask-demo
cd flask-demo/
vim app.py

内容如下:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello docker!"

if __name__ == "__main__":
    app.run(port= 5000)

2. 在该目录下新建 Dockerfile 文件:

FROM python:2.7
LABEL author="Dylan" mail="[email protected]"
RUN pip install flask
COPY app.py /app/
WORKDIR /app/
EXPOSE 5000
CMD ["python", "app.py"]

值得注意的地方:

a. 将文件 COPY 到指定目录的时候,目录后面需要 /,否则文件是重命名为目录最后一级。

b. CMD 运行方式主要有两种,一种是直接完整命令,一种是像这里一样拆分成列表。

3. 构建镜像:

docker image build -t dylan/flask-demo:v1.0 .

这里可能会出现 pip 安装失败的情况,再执行一次就行了。

可以看到每一个 Step 就是一层,所以我们的 Dockerfile 尽量层少一些。

可以看到这个镜像,包括他基于 python 2.7 镜像。

4. 运行容器测试:

docker run -d --name flask-demo-1 dylan/flask-demo:v1.0

我们这里有个关键参数,-d,后台运行,否则该容器会前台命令行运行!

可以见到我们这个容器多了一个 Dockerfile 里面定义的端口选项。

5. 进入容器访问测试:

docker container exec -it flask-demo-1 /bin/sh

结果如图:

可以看到服务能够正常访问到!但是问题在于我们只能在容器内部访问到该地址,而无法外部访问,这肯定不是想要的结果。

后面会谈谈如何让外部也能访问到!

猜你喜欢

转载自www.cnblogs.com/Dy1an/p/12362382.html