1 了解镜像
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。
但注意, 镜像不包含任何动态数据( /proc、/sys,其中,/proc里面装的主要是内核参数,在内核运行状态不同时里面的值是不一样的,而/sys目录则包含了系统资源的管理信息,这两个目录中的数据都是动态生成的) ,因此,其内容在构建好之后一般是不会变的。这里,第一,你要知道什么是动态数据,第二,将来我们要自己装一个linux操作系统,你想把这个linux做成一个容器镜像,其实很简单,就是把linux里面所有的文件目录打包一份就行了,但是打包的时候会把/proc和/sys这两个目录排除。(因此, 容器镜像不包含内核,容器共用宿主机的内核)
2 镜像的制作
2.1 通过对系统打包的方式制作镜像
1)最小化安装一个操作系统
2)将此系统文件打包,把装的一个系统做成一个容器镜像,也就是把根文件系统打个包就行了(除了/proc和/sys之外)
bash
[root@node02 ~]# tar -cvf --numeric-owner --exclude=/proc --exclude=/sys /data/centos7u2.tar /
3)将打包文件拷贝到运行容器的主机上
bash
[root@node02 ~]# scp centos7u2.tar 192.168.1.72:/root
4)利用打包文件生成镜像
bash
[root@node02 ~]# docker import centos7u2.tar docker.io/centos7u2:latest
[root@node02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos7u2 latest 1e1148e4cc2c 30 seconds ago 987 MB
5)使用自己生成的镜像创建容器做测试
bash
[root@node02 ~]# docker run -itd --name c1 docker.io/centos7u2 /bin/bash
2.2 基于Dockerfile文件制作镜像
1)编写dockerfile文件
bash
[root@node02 ~]# cat /root/test01
FROM local-test/centos7.2:v1
RUN yum install -y httpd && yum install -y vsftpd
解释:
FROM:用于指定一个基础镜像
RUN:执行任务,建议同一个任务的多条指令使用&&连接多个命令完成
2)构建镜像
bash
[root@node02 ~]# docker build -t centos7.2-httpd:v2 -f test01 /root
参数说明:
-t:用于指定镜像名称、标记
-f:指定dockerfile名称
3)查看镜像
bash
[root@node02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos7.2-httpd v2 2cdfd7a685f6 2 minutes ago 1.08 GB
3 Dockerfile指令说明
3.1 FROM
FROM < image >
用于指定基础镜像
3.2 MAINTAINER
MAINTAINER < name >
用于指定镜像的作者信息,当执行docker inspect指令时会有输出 。
3.3 RUN
RUN < command >
或者
RUN ["command","arg1","arg2"]
用于执行基础镜像支持的任何指令;
例如:
RUN yum install -y net-tools
RUN ["yum","install","-y","net-tools"]
3.4 CMD && ENTRYPOINT
3.4.1 CMD
CMD < command > < arg1 > < arg2 >
或者
CMD ["command","arg1","arg2"]
用于指定容器启动时执行的操作;
注意:一个dockerfile中只能有一条 CMD 指令,如果有多条则仅执行最后一条;
bash
# 使用CMD指令
FROM ubuntu
CMD ["echo", "Hello World"]
3.4.2 ENTRYPOINT
ENTRYPOINT 和 CMD 指令的用法很相似:
ENTRYPOINT < command > < arg1 > < arg2 >
或者
ENTRYPOINT ["command","arg1","arg2"]
用于指定容器启动时执行的操作;
注意:一个dockerfile中只能有一条 ENTRYPOINT指令,如果有多条则仅执行最后一条;
bash
# 使用ENTRYPOINT指令
FROM ubuntu
ENTRYPOINT ["echo", "Hello World"]
另外,ENTRYPOINT指令还可以与CMD指令配合使用,此时,CMD指令后跟的不再是完整的可执行命令,而仅是作为ENTRYPOINT指令后的参数使用,如下所示:
bash
# ENTRYPOINT 和 CMD 指令配合使用
FROM ubuntu
ENTRYPOINT ["cat"]
CMD ["-n","/etc/passwd"]
3.4.3 CMD 和 ENTRYPOINT 的区别
区别:
如果在运行docker run命令时指定了参数,那么,将会覆盖CMD中指定的参数,而ENTRYPOINT指令不会被覆盖,而是被附加到docker run命令的参数之前。
总结来说:CMD用于定义默认的容器启动命令,可以被覆盖,而ENTRYPOINT用于定义容器启动的主要命令,不会被覆盖。
案例:
使用 Dockerfile 构建 centos 镜像,在 Dockerfile 中使用 CMD 和 ENTRYPOINT 。当 docker run + 参数 的时候进行 CMD 和 ENTRYPOINT 的测试,CMD指定的参数是否会被覆盖,以及 ENTRYPOINT 指定的参数是否会附加到docker run命令的参数之前。
【测试CMD】
1)编写dockerfile文件
$ vim dockerfile-centos-test
FROM centos
CMD ["ls","-a"]
2)构建镜像
$ docker build -f dockerfile-centos-test -t cmd-test:0.1 .
3)运行镜像
$ docker run cmd-test:0.1
可以看到,列出了所有目录。
4)这个时候我们在docker run 的时候追加一个命令参数 -l
$ docker run cmd-test:0.1 -l
可以看到,出现了错误,在CMD的情况下,加 -l 替换了dockerfile中的 CMD ["ls","-l"],但是由于 -l 不是命令,所以就报错了。
5)我们将 docker run 的命令参数 -l 改为 ls
$ docker run cmd-test:0.1 ls
可以看到,这个时候就执行成功了。
【测试 ENTRYPOINT】
1)编写dockerfile文件
$ vim dockerfile-centos-test
FROM centos
ENTRYPOINT ["ls","-a"]
2)构建镜像
$ docker build -f dockerfile-centos-test -t cmd-test:0.1 .
3)运行镜像
$ docker run cmd-test:0.1
4)这个时候追加一个命令 -l (使之成为 ls -al )
$ docker run cmd-test:0.1 -l
总结一下:CMD的情况下,docker run的参数 -l 替换了CMD的 ls -a。而ENTRYPOINT的情况下,-l 参数追加到了 ls -a 的后面,使之变成了ls -al。
3.5 ARG
ARG < key >=< value >
Docker 1.9 版本 后新加入的指令,ARG定义的变量只有在构建image时有效,建立完成后变量消失;
3.6 USER
USER < name >
用于设置启动容器的用户,默认为root
3.7 EXPOSE
EXPOSE < port1 > < port2 > ...
用于设置容器启动时,要映射到物理机的端口;容器启动后,会将该端口映射到物理机上的随机端口;
3.8 ENV
ENV < key > < value >
用于为容器设置环境变量,可以使用docker inspect查看;也可以通过docker run --env < key >=< value >设置或修改环境变量;(该变量设置后,后续的RUN指令都可以使用该变量)
3.9 ADD && COPY
3.9.1 ADD
ADD < src > < dest >
用于将src指定的文件复制到容器的目录
例如:
ADD /tmp/nginx-1.13.4.tar.gz /tmp/
1)所有拷贝到容器中的文件及目录权限为0755,uid及gid均为0;
2)src如果是一个目录,那会将该目录下所有文件拷贝到容器中,不包括目录;
3)如果src是文件且dest不以/结束,dest会被识别为文件,src中的内容会把dest文件内容覆盖;
4)如果src是文件且dest以/结束,则会将src文件拷贝到dest目录;;
如果源文件是一个tar压缩包的话,压缩格式为gzip,bzip2以及xz的情况下,ADD指令将会自动解压缩这个压缩文件到目标路径中,在某些情况下这个自动解压缩的功能非常有用。
3.9.2 COPY
COPY < src > < dest >
用于复制本地主机的src文件(为Dockerfile所在目录的相对路径、文件或者目录)到容器的dest(dest路径不存在时,会自动创建)。
此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留,比如读、写、执行权限、文件变更时间等。(这个特性对于镜像定制很有用,特别是构建相关文件都在使用 Git 进行管理的时候)
3.9.3 ADD 和 COPY 的区别
共同点:
都可以将主机上的资源加入到Dockerfile制作的镜像中。
不同点:
官方建议:
1)尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已;
2)需要自动解压缩的场合,再使用ADD;
另外,需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则:所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
3.10 WORKDIR
WORKDIR < path >
用于切换目录,类似于cd命令;(对RUN, CMD, ENTRYPOINT指令生效)
3.11 VOLUME
VOLUME ["mount_point"]
用于创建一个本机或者为其他容器使用的挂载点,用于数据的持久化保存 。
例如:
FROM base VOLUME ["/tmp/data"]
通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点,但值得注意的是通过VOLUME 指令创建的挂载点,无法指定主机上对应的目录,而是自动生成的(可以通过docker inspect查看)。