Linux运维之docker(二)镜像的创建

  • 构建镜像的两种方式

docker commit :将运行的容器保存成镜像
Dockerfile:自动构建

  • docker commit

使用docker commit 创建镜像分为三步:

运行容器
修改容器
将容器保存为镜像

特点:
效率低、可重复性弱、容易出错
使用者无法对镜像进行审计(看不到镜像中的操作),会存在安全隐患

busybox示例:

运行容器:

[root@server1 images]# docker run -it --name test busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

修改容器:

/ # echo "hello world" > testfile
/ # ls
bin       etc       proc      sys       tmp       var
dev       home      root      testfile  usr

将容器保存为新的镜像:

查看新生成的镜像:无法看新镜像层的操作:

直接运行新生成的镜像容器:

  • Dockerfile 创建镜像
  • Dockerfile的详细介绍

dickerfile 常用指令:

1 、FROM:
用于指定base镜像,本地不存在会从远程仓库进行下载

2、MAINTAINER
MAINTAINER:设置镜像的作者,如用户邮箱等(不是必须的)

3、COPY
把文件从build context复制到镜像
支持两种形式:COPY src dest和COPY [" src" ,"dest "]
src必须指定build context中的文件或目录
dest为容器中的路径

[root@server1 docker]# vim Dockerfile
                FROM busybox
                CPOY Dockerfile  /mnt
[root@server1 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@server1 docker]# ls
backup.tar.gz  Dockerfile
[root@server1 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz  /mnt
[root@server1 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@server1 docker]# docker run -it --name vm3 test:v3
docker: Error response from daemon: No command specified.
See 'docker run --help'.
[root@server1 docker]# docker run -it --name vm3 test:v3 bash
bash-4.2# ls /mnt
usr

5 EXPOSE
如果容器中运行应用服务,则可以包服务端口暴露出去

[root@server1 docker]# vim Dockerfile
FROM rhel7
Add backup.tar.gz  /mnt
EXPOSE 80

[root@server1 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@server1 docker]# vim Dockerfile
FROM rhel7
EXPOSE 80
VOLUME ["/data"]    # 声明数据卷
[root@server1 docker]# docker build -t test:v1 .
[root@server1 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@server1 docker]# docker inspect vm2  # 查看运行容器的信息
"Mounts": [
            {
                "Type": "volume",
                "Name": "280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0",
                "Source": "/var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data",
# Source为容器中声明的数据卷在宿主机上的挂载路径。

在宿主机上在该挂载目录中创建文件,可以在容器中相应的目录中看到:

[root@server1 docker]# cd /var/lib/docker/volumes/280eb155e5ef61cfaf300b8d597f057005cc66fb9af39361b9f1b4e53d5ca2a0/_data
[root@server1 _data]# ls
[root@server1 _data]# touch file1
[root@server1 _data]# ls
file1
#再次连接容器:
[root@server1 _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@server1 docker]# vim Dockerfile
FROM busybox
ENV name world   # 定义变量
ENTRYPOINT echo "hello,$name"    # 设置输出(shell命令行)

[root@server1 docker]# docker build -t test:v2 .   # 创建镜像

[root@server1 docker]# docker run --rm test:v2   # 运行容器
hello,world   # 直接输出,同时对变量进行解析

exec模式:

[root@server1 docker]# vim Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo","hello,$name"]

[root@server1 docker]# docker build -t test:v3 .   # 创建镜像

[root@server1 docker]# docker run --rm test:v3   # 运行容器
hello,$name     # 输出并没有进行变量解析

原因:

这是由于shell格式底层会调用/bin/sh -C执行命令,可以解析变量。但是exec模式不会

[root@server1 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=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
[root@server1 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=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

处理办法:

所以只要指定/bin/sh -C指令解析命令。如下:

[root@server1 docker]# vim Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh","-c","echo hello,$name"]

[root@server1 docker]# docker build -t test:v4 .

[root@server1 docker]# docker run --rm test:v4
hello,world

Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换,在shell格式时ENTRYPOINT会忽略任何CMD和docker run 提供的参数

[root@server1 docker]# docker run --rm test:v2 lala   # shell 模式
hello,world
[root@server1 docker]# docker run --rm test:v3 lala   # exec模式
hello,$name lala

CMD命令在前,会被docker run后存在参数会被覆盖

[root@server1 docker]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo","hello"]
CMD ["WORLD"]

[root@server1 docker]# docker build -t test:v5 .  # 创建镜像

[root@server1 docker]# docker run --rm test:v5   # 运行容器
hello WORLD

[root@server1 docker]# docker run --rm test:v5  world   # 运行容器 后面加参数
hello world   # 显示CMD 指令被后面的参数覆盖

END