构建镜像的两种方式
docker commit :将运行的容器保存成镜像
Dockerfile:自动构建
docker commit
使用docker commit 创建镜像分为三步:
- 运行容器
- 修改容器
- 将容器保存为镜像
特点:
效率低、可重复性弱、容易出错
使用者无法对镜像进行审计(看不到镜像中的操作),会存在安全隐患
以镜像busybox为例进行说明:
- 运行容器:
[root@toto6 images]# docker run -it --name test busybox
/ # ls
bin dev etc home proc root sys tmp usr var
- 修改容器:
/ # echo "hello toto" > testfile
/ # ls
bin etc proc sys tmp var
dev home root testfile usr
- 将容器保存为新的镜像:
[root@toto6 images]# docker commit test busybox:v2
sha256:0cdf20286e297b35345970340031e9ec0ad49128f790e82ec348f22470c8cd0e
- 查看新生成的镜像:无法看新镜像层的操作
IMAGE CREATED CREATED BY SIZE COMMENT
0cdf20286e29 About a minute ago sh 46B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
直接运行新生成的镜像容器:
[root@toto6 images]# docker run -it --name test busybox:v2
/ # ls
bin etc proc sys tmp var
dev home root testfile usr # 里面保存了之前操作的数据。
Dockerfile 创建镜像
根据Dockerfile中的内容,通过使用docker bulid指令,自动创建镜像,也是基于docker commit的层层构建得出。
Dockerfile文件名称,是docker默认的,在u不特殊指定的情况下,一般都是从该文件中读取创建信息。并且在创建的过程中,docker会将该文件所在目录中的所有内容发送给docker引擎。所以建创建一个空来目录来存放Dockerfile文件。
使用Dockerfile创建镜像
查看已经存在的镜像
[root@toto6 images]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
创建空目录以及Dockerfile文件
[root@toto6 images]# mkdir /docker
[root@toto6 images]# cd /docker/
[root@toto6 docker]# vim Dockerfile
FROM busybox # 以已经存在的busybox进行为base镜像
RUN echo 'hello world' # 新加的操作,每一个RUN产生一个新的镜像层
RUN echo 'westos linux'
创建新的镜像:. 表示Dockerfile所在的路径
[root@toto6 docker]# docker build -t busybox:v2 .
Sending build context to Docker daemon 2.048kB # 将目录中的所有内容发送给docker引擎
Step 1/3 : FROM busybox #第一层
---> 59788edf1f3e
Step 2/3 : RUN echo 'hello world' # 第二层
---> Running in 9e201f6f8641
hello world
Removing intermediate container 9e201f6f8641
---> 4dc2056e315e
Step 3/3 : RUN echo 'westos linux' # 第三层
---> Running in d957a3a99acf
westos linux
Removing intermediate container d957a3a99acf
---> 8fed8fc9f3f2
Successfully built 8fed8fc9f3f2
Successfully tagged busybox:v2 # 创建成功
成功之后再次查看镜像,已经成功生成镜像
[root@toto6 docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox v2 8fed8fc9f3f2 59 seconds ago 1.15MB
busybox latest 59788edf1f3e 9 months ago 1.15MB
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
查看新生成的镜像分层结构:
能清楚的看到每一层镜像进行的操作,使用者可以对镜像进行审计
[root@toto6 docker]# docker history busybox:v2
IMAGE CREATED CREATED BY SIZE COMMENT
8fed8fc9f3f2 9 minutes ago /bin/sh -c echo 'westos linux' 0B
4dc2056e315e 9 minutes ago /bin/sh -c echo 'hello world' 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
当不修改刚才的Dockerfile的基础上再次添加内容创建镜像的时候
[root@toto6 docker]# vim Dockerfile
FROM busybox
RUN echo 'hello world'
RUN echo 'westos linux'
RUN echo toto > totofile # 添加一条新的语句
再上一次的基础上构建新的镜像
[root@toto6 docker]# docker build -t busybox:v3 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM busybox
---> 59788edf1f3e
Step 2/4 : RUN echo 'hello world'
---> Using cache # 和上一次一致,使用存在的cache
---> 4dc2056e315e
Step 3/4 : RUN echo 'westos linux'
---> Using cache # 和上一次一致,使用存在的cache
---> 8fed8fc9f3f2
Step 4/4 : RUN echo toto > totofile
---> Running in d611a8f1892c # 打开一个新的容器运行新加的操作
Removing intermediate container d611a8f1892c # 运行完成之后释放自己新建的容器
---> 41b1abbffebf #提交新建的镜像层
Successfully built 41b1abbffebf
Successfully tagged busybox:v3 # 镜像创建成功
查看新生成的镜像分层结构:
在Dockerfile文件中,每一个RUN语句都会生成一个新的镜像层。
[root@toto6 docker]# docker history busybox:v3
IMAGE CREATED CREATED BY SIZE COMMENT
41b1abbffebf 4 minutes ago /bin/sh -c echo toto > totofile 5B
8fed8fc9f3f2 31 minutes ago /bin/sh -c echo 'westos linux' 0B
4dc2056e315e 31 minutes ago /bin/sh -c echo 'hello world' 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
Dockerfile的详细介绍
dickerfile 常用指令:
1 、FROM:
用于指定base镜像,本地不存在会从远程仓库进行下载
2、MAINTAINER
MAINTAINER:设置镜像的作者,如用户邮箱等(不是必须的)
3、COPY
把文件从build context复制到镜像
支持两种形式:COPY src dest和COPY [" src" ,"dest "]
src必须指定build context中的文件或目录
dest为容器中的路径
[root@toto6 docker]# vim Dockerfile
FROM busybox
CPOY Dockerfile /mnt
[root@toto6 docker]# docker run -it --name vm1 test:v1
/ # ls
bin dev etc home mnt proc root sys tmp usr var
4 、ADD
用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可自动下载URL并拷贝到镜像
DD html.tar /var/www ##解压
ADD http://ip/html.tar /var/www ##下载
[root@toto6 docker]# ls
backup.tar.gz Dockerfile
[root@toto6 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz /mnt
[root@toto6 docker]# docker build -t test:v3 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM rhel7
---> 0a3eb3fde7fd
Step 2/2 : Add backup.tar.gz /mnt
---> d8b34bccc29a
Successfully built d8b34bccc29a
Successfully tagged test:v3
[root@toto6 docker]# docker run -it --name vm3 test:v3
docker: Error response from daemon: No command specified.
See 'docker run --help'.
[root@toto6 docker]# docker run -it --name vm3 test:v3 bash
bash-4.2# ls /mnt
usr
5 EXPOSE
如果容器中运行应用服务,则可以包服务端口暴露出去
[root@toto6 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz /mnt
EXPOSE 80
[root@toto6 docker]# docker history test:v4
IMAGE CREATED CREATED BY SIZE COMMENT
125f2a6e4982 10 seconds ago /bin/sh -c #(nop) EXPOSE 80 0B
d8b34bccc29a 4 minutes ago /bin/sh -c #(nop) ADD file:a6708d65f40d03475… 0B
0a3eb3fde7fd 5 years ago 140MB Imported from -
6 、VOLUME
声明数据卷,通常指定应用数据挂载点
VOLUME [ “/var/www/html”] :该路径为容器中的路径。如果路径不存在,启动容器的时候会自动创建
- 一般VOLUME指定挂载点,没有此路径就会新建路径。
- 在运行docker宿主机上,可以根据命令docker inspect 容器名的具体信息,可以查看封装容器,声明的数据卷,Source会存在此容器目录挂接到本地_data目录。
- 由于自动挂载的路径很长,不太方便记,也可以在运行的时候指定挂载路径
[root@toto6 docker]# vim Dockerfile
FROM rhel7
EXPOSE 80
VOLUME ["/data"] # 声明数据卷
[root@toto6 docker]# docker build -t test:v1 .
[root@toto6 docker]# docker run -it --name vm2 test:v1 bash
bash-4.2# ls
bin data etc lib media opt root sbin sys usr
boot dev home lib64 mnt proc run srv tmp var # 容器中生成了data目录
#使用ctrl + pq 保证容器正常运行退出交互式界面。
[root@toto6 docker]# docker inspect vm2 # 查看运行容器的信息
"Mounts": [
{
"Type": "volume",
"Name": "280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0",
"Source": "/var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data",
# Source为容器中声明的数据卷在宿主机上的挂载路径。
在宿主机上在该挂载目录中创建文件,可以在容器中相应的目录中看到:
[root@toto6 docker]# cd /var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data
[root@toto6 _data]# ls
[root@toto6 _data]# touch file1
[root@toto6 _data]# ls
file1
#再次连接容器:
[root@toto6 _data]# docker attach vm2
bash-4.2# ls /data
file1
上面声明数据卷,并没有指定在宿主机上的挂载点。该挂载点由docker自动分配。还可以自己指定数据卷的挂载。
docker run -it --name vm3 -v /opt/data:/data test:v1 ##:前为物理机挂载目录,:后为docker挂载目录
7 、WORKDIR
为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在也会自动创建
8 、RUN
RUN 在容器中运行命令并创建新的镜像层,常用于安装软件包:每个run 都会多一层
9 、ENV:
设置环境变量,变量可以被后续的指令使用
10 、CMD 与 ENTRYPOINT
设置容器启动后执行的命令,但是CMD会被docker run 后面的命令覆盖,但ENTRYPOINT不会
Dockerfile中只能指定一个ENTRYPOINT,如果指定过多则只有最后一个有效
docke run后面的参数可以传递给ENTRYPOINT指令当作参数;
shell模式:
[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto # 定义变量
ENTRYPOINT echo "hello,$name" # 设置输出(shell命令行)
[root@toto6 docker]# docker build -t test:v2 . # 创建镜像
[root@toto6 docker]# docker run --rm test:v2 # 运行容器
hello,toto # 直接输出,同时对变量进行解析
exec模式
[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto
ENTRYPOINT ["/bin/echo","hello,$name"]
[root@toto6 docker]# docker build -t test:v3 . # 创建镜像
[root@toto6 docker]# docker run --rm test:v3 # 运行容器
hello,$name # 输出并没有进行变量解析
原因:
这是由于shell格式底层会调用/bin/sh -C执行命令,可以解析变量。但是exec模式不会,
[root@toto6 docker]# docker history test:v2
IMAGE CREATED CREATED BY SIZE COMMENT
b7801a7de9d6 7 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
c3ee45017cfb 7 minutes ago /bin/sh -c #(nop) ENV name=toto 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
[root@toto6 docker]# docker history test:v3
IMAGE CREATED CREATED BY SIZE COMMENT
57b3bcebd5b4 2 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/echo" "… 0B
c3ee45017cfb 7 minutes ago /bin/sh -c #(nop) ENV name=toto 0B
59788edf1f3e 9 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
处理办法:
所以只要指定/bin/sh -C指令解析命令。如下:
[root@toto6 docker]# vim Dockerfile
FROM busybox
ENV name toto
ENTRYPOINT ["/bin/sh","-c","echo hello,$name"]
[root@toto6 docker]# docker build -t test:v4 .
[root@toto6 docker]# docker run --rm test:v4
hello,toto
Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换,在shell格式时ENTRYPOINT会忽略任何CMD和docker run 提供的参数
[root@toto6 docker]# docker run --rm test:v2 lala # shell 模式
hello,toto
[root@toto6 docker]# docker run --rm test:v3 lala # exec模式
hello,$name lala
CMD命令在前,会被docker run后存在参数会被覆盖
[root@toto6 docker]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo","hello"]
CMD ["WORLD"]
[root@toto6 docker]# docker build -t test:v5 . # 创建镜像
[root@toto6 docker]# docker run --rm test:v5 # 运行容器
hello WORLD
[root@toto6 docker]# docker run --rm test:v5 toto # 运行容器 后面加参数
hello toto # 显示CMD 指令被后面的参数覆盖