编写Dockerfile文件创建自己的镜像并运行自己的程序 您所在的位置:网站首页 如何自己编写歌词文件内容 编写Dockerfile文件创建自己的镜像并运行自己的程序

编写Dockerfile文件创建自己的镜像并运行自己的程序

2024-06-28 09:10| 来源: 网络整理| 查看: 265

最近在看《深入浅出Docker》这本书,想练习一下Dockerfile的写法

先记录一下几个需要注意的点:

1.Dockerfile的注释以#开头,每一行都是一个指令,不区分大小写,但是为了可读性,通常写成INSTRUCTION argument的形式。

2.有的命令会增加新的镜像层,有的会增加镜像元数据,一个简单的区分标准是,看该条命令有没有向镜像中添加新的文件或程序,如果有,就会增加新的镜像层,如果只是告诉docker如何构建或者运行程序,那么就只会增加镜像的元数据,可以通过docker image history来查看构建镜像的过程中都执行了哪些指令。

3.docker镜像的体积应该尽可能地小,不同的docker写法会对镜像的大小产生显著影响,常见的例子就是,一条RUN命令会产生一个镜像,因此可以把命令行通过&&连接以及使用\换行的方式,将多个命令包含在一个RUN指令中;另外一个问题是开发者通常不会在构建完成后清理,当使用RUN产生一个命令时,可能会拉取一些构建工具,这些构建工具会留在镜像中移交至生产环境,这是不合适的,有多种方式可以改善这一问题,比较麻烦的做法是采用建造者模式(Builder Pattern),另一个比较好的方式是多阶段构建(Multi-Stage Build),能在不增加复杂性的情况下优化构建过程。

4.docker的构建使用缓存机制,如果重复构建镜像,第一次构建的内容能被缓存下来,并被后续的构建使用,对每一条指令,docker都会检查有没有相应的缓存镜像与其对应,如果有,则为缓存命中,但是一旦没有命中,此后的所有命令将不再使用缓存,所以,在编写Dockerfile文件的时候,尽量将稳定的不会改变的命令放在前面,产生变化的命令放在后面,以更好的利用缓存,也可以通过对docker image build 命令加入--nocache=true参数可以强制忽略对缓存的使用,并且copy和add指令会检查镜像中的内容自上一次构建后是否发生了变化,如果发生了变化,则认为缓存无效并构建新的镜像层。

5.合并镜像的操作利弊参半,当层数太多的时候,合并是个不错的选择,但是合并的镜像无法共享镜像层,这导致存储空间的低效利用,并且在推送到仓库的时候,合并的镜像需要传递所有字节,而分层镜像只需传递发生更改的镜像层,可以在执行docker image build 命令时,增加--squash参数来创建一个合并的镜像。

6.在构建Linux镜像时,若使用的是APT包管理器,则应该在执行apt-get install命令时增加no-install-recommends参数,这能够确保APT仅安装核心依赖包

7.更多的指令可以去官网参考文档https://docs.docker.com/engine/reference/builder/

好了,正文开始,这次的实验是,以centos为基础镜像,在此基础之上运行自己一个简单的测试程序lld.c,并在运行过程中更改程序内容。

一:首先编写Dockerfile,具体内容如下:

FROM centos:latest as mycentos LABEL author="WR" WORKDIR /home/wr/mytest COPY ./temp/test ./ctemp CMD cd ctemp &&./lld

首先Dockerfile以FROM开头,基础镜像是centos,tag选择latest就可以,as mycentos可写可不写;

第二行LABEL写维护者的名字

第三行指定WORKDIR,记住WORKDIR一定要有Dockerfile,在这里工作路径选择绝对路径

第四行将宿主机中的程序拷贝到当前工作目录中,将整个test文件里的内容都拷贝到工作目录的ctemp文件下,我的程序放在/home/wr/mytest/temp/test里面,在这里COPY只能用相对路径(查了很多实例,好像提到的都是这么说),相对于工作目录的相对路径。

第五行是容器运行后需要执行的操作,用&&将其合并成了一条指令,因为程序放在ctemp文件夹中,所以要先进入文件夹再执行。

二:生成镜像

使用命令docker build -t print:v1 .,-t是给镜像打上tag,此次的tag为print:v1,后面的.是指代的Dockerfile的位置,因为我就在Dockerfile的目录下,所以直接写.就行,可以用-f来指定Dockerfile的位置,运行完命令之后如下图所示:

[wr@localhost mytest]$ docker build -t print:v1 . Sending build context to Docker daemon 27.65kB Step 1/5 : FROM centos:latest as mycentos ---> 300e315adb2f Step 2/5 : LABEL author="WR" ---> Using cache ---> 3063f3ccebee Step 3/5 : WORKDIR /home/wr/mytest ---> Using cache ---> 85d72918bb39 Step 4/5 : COPY ./temp/test ./ctemp ---> 38a04e0768ab Step 5/5 : CMD cd ctemp&&./lld ---> Running in 136424e49184 Removing intermediate container 136424e49184 ---> 38d80460633f Successfully built 38d80460633f Successfully tagged print:v1

可以看出镜像成功生成,之所以有个using cache是因为之前用这个Dockerfile生成过其他的镜像,有些重复的命令就直接使用缓存了

三:运行镜像

输入命令

docker run -it -v /home/wr/mytest/temp/test:/home/wr/mytest/ctemp print:v1 bash,结果如图所示:

[wr@localhost temp]$ docker run -it -v /home/wr/mytest/temp/test:/home/wr/mytest/ctemp print:v1 bash [root@64ed9fd25700 mytest]#

docker run 是运行镜像的命令,-it 是进行界面交互,-v是进行目录的映射,参数格式是宿主机目录:容器目录,后面跟镜像的名字,最后的bash意味着将终端控制权交给容器,也就是进入容器内部,第二行[root@64ed9fd25700 mytest]#可以看出目前已经进入容器内部,可以输入ls来查看,这和Dockerfile文件中,把test目录中的文件拷贝到ctemp目录中一致。同时要注意,不要将-v及其后面的参数写到print:v1后面,会报错的;还有,如果不确定容器的目录,可以用docker image inspect 镜像名称 来查看,二者都要使用绝对路径。

[root@64ed9fd25700 mytest]# ls ctemp [root@64ed9fd25700 mytest]# cd ctemp [root@64ed9fd25700 ctemp]# ls lld lld.c

进行映射的好处是,当需要改容器中的应用程序时,可以直接修改宿主机的内容,并且修改长期有效。

在容器中执行程序./lld,如图所示:

[root@64ed9fd25700 ctemp]# ./lld 78 v1:The input is 78 [root@64ed9fd25700 ctemp]#

当我直接修改宿主机的程序后,再次运行,结果如下,可以看到容器中的相关文件也被更改,输出有了变化:

[root@64ed9fd25700 ctemp]# ./lld 78 v2:The input is 78 [root@64ed9fd25700 ctemp]#

如果要退出容器,直接输入exit即可

[root@64ed9fd25700 ctemp]# exit exit [wr@localhost temp]$

这样容器就停止运行了,如果要重新进入该容器,首先输入命令docker container restart 64ed9fd25700,重启容器,其中数字为容器的ID,也可以用容器名称代替,可以用docker ps -a来查看所有容器的ID和名字。

[wr@localhost test]$ docker container restart 64ed9fd25700 64ed9fd25700

然后再输入命令docker exec -it 64ed9fd25700 bash,就可以重新进入了,如下图所示:

[wr@localhost test]$ docker exec -it 64ed9fd25700 bash [root@64ed9fd25700 mytest]# cd ctemp [root@64ed9fd25700 ctemp]# ./lld 89 v2:The input is 89 [root@64ed9fd25700 ctemp]#

当然,也可以不进行目录的映射,或者不进入容器内部,只需要去掉-v 和bash即可,但是如果是以原始镜像重新运行容器的话,程序内容将不会改变,比如输入docker run -it print:v1,结果如下

[wr@localhost test]$ docker run -it print:v1 98 v1:The input is 98 [wr@localhost test]$

若要删除镜像,要先停止并删除以该镜像为基础运行的容器,再删除镜像。

这只是个很简单的例子,下一步准备测试两个容器间通信的实验,暂定收发包吧。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有