Docker之Dockerfile常用指令及镜像的构建shell和exec格式的区别
一.概念讲解(一)dockerfile 最佳实践(二)dckerfile常用指令1.FROM:指定base镜像,如果本地不存在会从远程仓库下载。2.MAINTAINER:设置镜像的作者,比如用户邮箱等。3.COPY:把文件从build context复制到镜像,支持两种形式:COPY src dest 和 COPY [“src”, “dest”],src必须指定build contex...
一.概念讲解
(一)dockerfile 最佳实践
(二)dckerfile常用指令
1.FROM:指定base镜像,如果本地不存在会从远程仓库下载。
2.MAINTAINER:设置镜像的作者,比如用户邮箱等。
3.COPY:把文件从build context复制到镜像,支持两种形式:COPY src dest 和 COPY [“src”, “dest”],src必须指定build context中的文件或目录
4.ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:ADD html.tar /var/www ADD http://ip/html.tar /var/www
5.ENV:设置环境变量,变量可以被后续的指令使用:ENV HOSTNAME sevrer1.example.com
实验开始:
6.EXPOSE:如果容器中运行应用服务,可以把服务端口暴露出去:,EXPOSE 80
7.VOLUME:申明数据卷,通常指定的是应用的数据挂在点:VOLUME ["/var/www/html"]
8.WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
9.RUN:在容器中运行命令并创建新的镜像层,常用于安装软件包:RUN yum install -y vim
10.CMD 与 ENTRYPOINT:这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。docker run后面的参数可以传递给ENTRYPOINT指令当作参数。Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。
二.Dockerfile常用指令的相关实验
(一)指令(run,copy,cmd的使用)
1.进入/tmp下删除所有内容并创建一个目录,在此目录下建立一个文件(此
文件用于)
[root@server1 ~]# cd /tmp
[root@server1 tmp]# rm -rf *
[root@server1 tmp]# mkdir docker/
[root@server1 tmp]# cd docker/
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM rhel7
2.删除掉没有用的读写层
#查看docker的镜像
[root@server1 docker]# docker images
#删除docker的v1镜像
[root@server1 docker]# docker rmi ubuntu:v1
#删除docker的v2镜像,发现会报错,因为之前没有关闭容器
[root@server1 docker]# docker rmi ubuntu:v2
#查看容器的进程
[root@server1 docker]# docker ps -a
#首先删除容器,必须先关闭容器,因为之前没有关闭容器(即没有使用ctrl+d或exit,而是使用了ctrl+q+p)
[root@server1 docker]# docker stop vm2
[root@server1 docker]# docker rm vm2
[root@server1 docker]# docker rmi ubuntu:v2
3.检查是否将没有用的内容全部删除
[root@server1 docker]# docker images
[root@server1 docker]# docker ps -a
4.将rhel7镜像导入并查看镜像以及分层结构
[root@server1 docker]# cd
[root@server1 ~]# docker load -i rhel7.tar
[root@server1 ~]# docker images
[root@server1 ~]# docker history rhel7:latest
5.创建rhel容器并使用bash方式运行,且在其内配置好yum源
[root@server1 ~]# docker run -it --name vm2 rhel7 bash
bash-4.2# ls
bash-4.2# cd /etc/yum.repos.d/
bash-4.2# ls
bash-4.2# vi dvd.repo
bash-4.2# cat dvd.repo
[dvd]
name=rhel7.3
baseurl=http://172.25.12.250/rhel7.3
gpgcheck=0
bash-4.2# yum repolist
6.下载httpd,但发现在最后会出现报错,即Rpmdb checksum is invalid: dCDPT(pkg checksums): systemd-libs.x86_64 0:219-30.el7 - u,此报错说明索引数据库有问题,在容器的构建中如果出现这个问题时,会非0退出(即没有返回值),重新构建即可(虽然httpd已经成功安装,但是为了之后没有问题,还是重新构建一下
bash-4.2# yum install httpd -y
bash-4.2# rpmdb --rebuilddb
bash-4.2# yum install httpd -y
7.我们查看其id,发现虽然进入容器中是超级用户,但是此超级用户没有权限,只是个空壳
bash-4.2# id
bash-4.2# exit
8.编辑docker的配置文件
[root@server1 ~]# cd /tmp/docker/
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# vim dvd.repo
Dockerfile中的内容如下:
#从哪个镜像中获取
FROM rhel7
#将server1中的dvd.repo复制到容器中的/etc/yum.repos.d/dvd.repo目录下
COPY dvd.repo /etc/yum.repos.d/dvd.repo
#执行rebuilddb命令并下载httpd
RUN rpmdb --rebuilddb && yum install -y httpd
#开启httpd服务
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
dvd.repo中的内容如下:
[dvd]
name=rhel7.3
baseurl=http://172.25.12.250/rhel7.3
gpgcheck=0
9.构建镜像(查看镜像的缓存特性)
[root@server1 docker]# docker build -t rhel7:v1 .
注意:
不能把文件放到根下,因为如果放到根下,容量会非常大
10.查看镜像以及rhel7:v1的分层结构,发现显示的层数内容与配置文件中的内容一样
[root@server1 docker]# docker images
[root@server1 docker]# docker history rhel7:v1
11.将vm1删除,并重新创建一个容器,此时给容器设置端口(80:80中前面的80表示server1的80端口,后面的80表示容器中的80端口)
[root@server1 docker]# docker rm -f vm1
[root@server1 docker]# netstat -antlp
[root@server1 docker]# docker run -d --name apache -p 80:80 rhel7:v1
[root@server1 docker]# netstat -antlp
12.编辑配置文件并重新创建一个测试页index.html
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# vim index.html
[root@server1 docker]# cat index.html
Dockerfile 中的新增加的内容如下:
#将server1中index.html复制到容器中的/var/www/html/index.html文件下
COPY index.html /var/www/html/index.html
13.构建镜像,查看镜像的缓存特性(我们会发现,在v1读写层中已经运行后拥有的层数,此时在v2中使用的是缓存)
[root@server1 docker]# docker build -t rhel7:v2 .
[root@server1 docker]# docker images
14.查看镜像的分层结构以及各个读写层之间关系,会发现每一层都在叠加
[root@server1 docker]# docker history rhel7:v2
[root@server1 docker]# docker history rhel7:v1
[root@server1 docker]# docker history rhel7
15.在浏览器中输入172.25.12.1,发现可以查看到index.html中的内容
16.将容器apache删除并在/tmp/docker目录下重新创建一个目录并将之前的index.html移至新建的目录下
[root@server1 docker]# docker rm -f apache
[root@server1 docker]# mkdir website
[root@server1 docker]# mv index.html website/
[root@server1 docker]# ls
16.创建一个容器,此容器不仅映射了端口,而且设置了挂载
[root@server1 docker]# docker run -d --name apache -p 80:80 -v /tmp/docker/website:/var/www/html rhel7:v2
17.查看容器的详情,可以查看到:“Source”: “/tmp/docker/website”,“Destination”: “/var/www/html”,
[root@server1 docker]# docker inspect apache
18.进入website目录并修改index.html中的内容
[root@server1 docker]# cd website/
[root@server1 website]# vim index.html
[root@server1 website]# cat index.html
修改的内容如下:
www.westos.com
www.westos.com
www.westos.com
www.westos.com
www.westos.com
www.westos.com
www.westos.com
19.在浏览器中刷新,发现此时的内容发生了改变
总结:
1.在删除镜像时,必须先使用rm删除容器,再使用rmi删除镜像
2.需要交互所以需要bash
3.索引数据库有问题,在容器的构建中如果出现这个问题时,会非0退出(即没有返回值)
4.会被限制权限的,虽然显示是超户
5.联网后,会自动从仓库中下载的,docker是有自己的仓库的
6.from从哪个镜像进行构建
7.copy可以将dvd
8.run指运行指令
9.cmd表示运行,在容器启动时启动的指令,只能启动一个
10.从当前目录中获取
11.使用commit无法查看过程
12.做个端口映射
13.不需要在关闭
14.上面两层都没有动过,所以使用缓存即可
(二)指令env的使用和Shell和exec格式区别讲解
1.Shell和exec格式的区别
Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会:
需要改写成以下形式:ENTRYPOINT ["/bin/sh", “-c”, “echo hello, $name”]
Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
2.看下在运行容器时的区别:
docker run --rm busybox:v1
docker run --rm busybox:v1 linux
推荐使用exec格式书写
实验开始:
(1)使用shell格式
1.查看busybox包的大小,发现其是1.4M,说明合适,因为我们要选一个大小比较小的镜像
[root@server1 ~]# du -h busybox.tar
2.编辑dockerfile
[root@server1 ~]# cd /tmp/docker/
[root@server1 docker]# vim Dockerfile
配置文件的内容如下:
FROM busybox
ENV name world
ENTRYPOINT echo "hello,$name"
3.构建镜像,会发现此时构建时出现了问题,原因是没有将镜像导入,导入后重新构建即可
[root@server1 docker]# docker build -t busybox:v1 .
[root@server1 docker]# cd
[root@server1 ~]# docker load -i busybox.tar
[root@server1 ~]# cd -
[root@server1 docker]# docker build -t busybox:v1 .
4.查看在运行容器时显示的内容
[root@server1 docker]# docker run --rm busybox:v1
(2)使用exec格式
1.编辑dockerfile配置文件
[root@server1 docker]# vim Dockerfile
配置文件的内容如下:
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo","hello,$name"]
2.构建一个镜像并运行容器,发现显示的内容无法解析变量
[root@server1 docker]# docker build -t busybox:v2 .
[root@server1 docker]# docker run --rm busybox:v2
(3)使用升级版exec格式
1.编辑dockerfile配置文件
[root@server1 docker]# vim Dockerfile
配置文件的内容如下:
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]
2.构建一个镜像并运行容器,发现可以成功解析变量,说明只要命令使用正确,exec格式也可以成功使用
[root@server1 docker]# docker build -t busybox:v3 .
[root@server1 docker]# docker run --rm busybox:v3
(4)使用shell+exec格式
1.编辑dockerfile配置文件
[root@server1 docker]# vim Dockerfile
配置文件的内容如下:
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
2.构建一个镜像并运行容器,发现可以成功解析变量,说明shell和exec格式可以成功结合
[root@server1 docker]# docker build -t busybox:v4 .
[root@server1 docker]# docker run --rm busybox:v4
#在命令行后加入新的内容,即新添加的内容,因为Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数保持不变(即如果使用了shell,那么cmd命令中的shell就有可能被动态的替换,而使用entrypoint不会被替换)
[root@server1 docker]# docker run --rm busybox:v4 westos
总结:
1.env指定变量
2.expose对外暴露的端口
3.add和copy是一样的,但是功能强大
4.docker引擎会自动分配一个目录
5.创建了一个卷的名称
6.默认的引擎都在/var/lib/docker目录下
7.cmd的命令可以被覆盖(比如加了bash),使用entrypoint不会被覆盖
8.一般不再容器中跑多个服务
9.没有使用中括号是shell模式
10.容器运行之后直接删除
更多推荐
所有评论(0)