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