1.Docker 镜像
1.1 是什么
镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
Docker 镜像是由一系列文件系统叠加而成:
- 1:最底端是一个引导文件系统,也就是 bootfs,当一个容器运行时,它将会装载到内存中,而引导文件系统将会被卸载
- 2:第二层是 root 文件系统,即 rootfs,它位于引导文件系统之上,rootfs 通常是一种或多种操作系统,如 Ubuntu 文件系统
(1)在 linux 引导过程中,root 文件系统起初会只读装载,当引导结束并完成了完整性检查后,会被切换成读写模式
(2)在 Docker 里面,root 文件系统始终都是只读模式,并且利用联合加载技术,在 root 文件系统层上加载更多的只读文件系统
联合加载:指的是一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker 将这样的文件系统称为镜像
1.2 关于 Docker 镜像
- 1:Docker 的镜像都是只读的
- 2:镜像是分层的,一个镜像可以放到另一个镜像顶端,下层的镜像称为父镜像,最底部的镜像称为基础镜像。镜像不能超过 127 层,以从整体上优化镜像的大小。
- 3:从一个镜像启动容器时,Docker 会在该镜像顶层加载一个读写文件系统,我们在 docker 中运行的程序就是在这层执行的。
- 4:当一个 docker 容器启动的时候,读写层初始是空的,当文件系统发生变化时,这些变化都会应用到这一层。
比如:想要修改一个文件,这个文件会从下面的只读层复制到该读写层,该文件的只读版本仍然存在,但是被该文件在读写层中的可读写副本所隐藏。
这种机制也就是写时复制,这是 Docker 如此强大的技术之一。
-
5:Docker 镜像的表示格式:
Image Hub/namespace/image name:tag
Image Hub:存放 image 的仓库地址,如果没有这个部分,表示缺省 docker 官方 hub
Namespace:命名空间,是一个用户或组织中所有镜像命名的集合
image name:镜像的名称
tag:区分同一镜像的不同版本,不写标签默认就是 latest
layer:镜像由一系列层组成,每层都用 64 位的十六进制数表示Image ID:镜像最上层的 layer ID 就是该镜像的 ID
- 6:本地存放:
本地镜像和容器都保存在 docker 宿主机的 /var/lib/docker 目录下,保存在 docker 所采用的存储驱动里面,可能是 aufs 或者 devicemapper。
(1)aufs 的全称是 advanced multi-layered unification filesystem,主要功能是把多个文件夹的内容合并到一起,提供一个统一的视图,使用的操作系统如 Ubuntu、Debian 等
(2)Device Mapper 是 Linux 系统中基于内核的高级卷管理技术框架,而 devicemapper 是 Docker 基于 Device Mapper 提供的一种存储驱动,使用的操作系统如 RHEL、Centos 等
Docker 镜像操作补充
docker commit:提交容器副本,如:docker commit -m=“提交的描述信息”-a=“指定镜像作者”容器 ID 要创建的目标镜像名
docker build:根据 Dockerfile 来创建一个新的镜像,如:docker build -t 要创建的镜像名称 .,最后一个点表示 Dockerfile 文件所在目录,可以指定 Dockerfile 的绝对路径
docker tag:为镜像添加一个新的标签,如:docker tag 源镜像 新镜像名
2 Dockerfile
2.1 是什么
Dockerfile 是用来构建 Docker 镜像的构建文件,是由一系列命令和参数构成的脚本。
2.2 基础知识
- 1:每条指令都必须为大写字母,且后面要跟随至少一个参数
-
2:指令按照从上到下,顺序执行
- 3:# 表示注释
- 4:每条指令都会创建一个新的镜像层,并对镜像进行提交
- 5:Docker 执行 Dockerfile 的大致流程
(1)docker 从基础镜像运行一个容器
(2)执行一条指令,对容器作出修改
(3)执行类似 docker commit 的操作,提交一个新的镜像层
(4)docker 再基于刚提交的镜像运行一个新容器
(5)执行 dockerfile 中的下一条指令,直到所有指令都执行完成
- 6:Docker 会将构建镜像的过程缓存起来,如果不需要缓存,可以在 docker build 的时候指定 –no-cache
2.3 Dockerfile 基本指令
2.3.1 FROM
指定一个已经存在的镜像,也是构建的基础镜像,Dockerfile 的第一条必须是 FROM
2.3.2 MAINTAINER
设置作者,联系邮件
2.3.3 RUN
指定要运行的命令,建议使用数组的格式,也是 exec 的格式,如:
RUN[“apt-get”,”install”,”-y”,”nginx”]
2.3.4 EXPOSE
向容器外部公开容器内的端口
2.3.5 WORKDIR
指定在创建容器的时候,在容器内部设置一个工作目录,entroypoint 和 CMD 指定的程序会在这个目录执行
可以在 docker run 中使用 - w 来覆盖工作目录
2.3.6 USER
指定该镜像以什么样的用户去执行,可以单独指定用户,也可以指定用户和组,格式:USER uid:gid,可以在 docker run 中通过 - u 来覆盖,如果都不指定,默认是 root
2.3.7 CMD
指定一个容器启动时要运行的命令,如果指定了多条 CMD,只有最后一条会执行
例如:CMD[“/bin/bash”,”-l”]
如果在 docker run 后面跟上要执行的命令,会覆盖 Dockerfile 里面的 cmd 指定的命令
2.3.8 ENTROYPOINT
也用来指定一个容器启动时要运行命令
- 1:但是它不会被 docker run 后面的命令覆盖,而是把 docker run 指定的任何参数当作参数传递给 entroypoint
-
2:可以和 CMD 一起用,比如:
ENTROYPOINT[“/usr/sbin/nginx”]
CMD[“-h”]
这样如果 docker run 的时候不覆盖 CMD,那么就是按照/usr/sbin/nginx –h 来运行
如果运行的时候:docker run –it 容器 id –g“daemon off;”
那么实际运行就是:/usr/sbin/nginx –g“daemon off;”了
- 3:如果非要覆盖 entrypoint,可以在 docker run 的时候,设置 –entroypoint 标志
2.3.9 ENV
用来在构建镜像过程中设置环境变量,例如:
ENV MY_PATH /usr/my
这个环境变量可以在后续的任何 RUN 指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,比如:WORKDIR $MY_PATH
可以在 docker run 命令中使用 –e 来指定环境变量,这些变量只在运行时有效
小技巧:
可以在不需要构建缓存的前面,添加一个 ENV 语句,这样,要后面更新的时候,就修改一下这个 ENV 的值
2.3.10 ADD
用来将构建环境下的文件或目录复制到镜像中。
- 1:只能操作构建环境相对的文件或目录,文件源也可以使用 URL 格式
- 2:如果将一个归档文件指定为源文件,docker 会自动解压
- 3:如果目的位置不存在的话,Docker 会自动创建全路径
注意:ADD 会使得构建缓存无效,ADD 后续指令都不能使用之前的构建缓存了
2.3.11 COPY
类似于 ADD,COPY 只做构建上下文中复制文件,而不会去做文件提取和解压的工作
如果源文件是目录,那么这整个目录会被复制到容器中
2.3.12 VOLUME
用来向镜像创建的容器添加卷,一个卷是可以存在于一个或者多个容器内的特定目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化:
-
1:卷可以在容器间共享和重用
- 2:对卷的修改是立即生效的
- 3:对卷的修改不影响镜像
卷可以让我们把数据、数据库或其它内容添加到镜像中,而不是将这些内容提交到镜像中,并且允许我们在多个容器间共享这些内容。
注意:如果删除了最后一个使用卷的容器,内部卷就不见了。
可在 docker run 的时候,使用 - v 来把宿主机的目录映射到容器,这样数据就能一直保存了
2.3.13 ONBUILD
指定当镜像做为其它镜像的基础镜像时,该镜像触发执行的功能。
ONBUILD 在子镜像 build 的时候,在 FROM 之后就先执行,并且只能被执行一次,不会被孙镜像继承
2.3.14 Dockerfile 编写最佳实践
- 1:容器应该是短暂的
- 2:避免安装不必要的包
- 3:每个容器应该只有一个关注点
- 4:最小化层的数量
- 5:对多行参数进行排序
- 6:缓存中间构建的镜像
3 制作自己的镜像示例
3.1 简介
以制作一个 tomcat9 的镜像为例。
3.2 准备工作
下载好要使用的 jdk 和 tomcat,这里下载的是:
jdk-8u144-linux-x64.tar.gz
apache-tomcat-9.0.1.tar.gz
3.3 编写 Dockerfile
FROM ubuntu
MAINTAINER cc
#把 java 与 tomcat 添加到容器中
ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.1 /usr/local/apache-tomcat-9.0.1
#配置 java 与 tomcat 环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.1
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.1
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行 tomcat
# CMD ["/usr/local/apache-tomcat-9.0.1/bin/catalina.sh","run"]
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.1/bin/startup.sh"]
CMD /usr/local/apache-tomcat-9.0.1/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.1/bin/logs/catalina.out
- 使用 Dockerfile 来制作镜像
docker build -t cctomcat9 .,注意后面有个 .,表示在当前路径找 Dockerfile
- 当前路径还有:
apache-tomcat-9.0.1
apache-tomcat-9.0.1.tar.gz
Dockerfile
jdk-8u144-linux-x64.tar.gz
- 启动容器
docker run -i -t -d -p 9080:8080 --name myt9 -v /ccdockermake/tomcat9/test:/usr/local/apache-tomcat-9.0.1/webapps/test -v /tomcat9logs/:/usr/local/apache-tomcat-9.0.1/logs --privileged=true cctomcat9
4. 错误解决
centos 7 Docker 启动一个 web 服务 但是启动时 报 WARNING: IPv4 forwarding is disabled. Networking will not work.
4.1:解决办法
编辑 /usr/lib/sysctl.d/00-system.conf
添加如下代码:net.ipv4.ip_forward=1
重启 network 服务:systemctl restart network
查看是否修改成功:sysctl net.ipv4.ip_forward
如果返回为“net.ipv4.ip_forward = 1”则表示成功了
关于 web 应用放的位置
静态引入:可以把 web 应用直接 copy 到容器中,分发方便
动态引入:就是如上这样把宿主机上的目录挂载到容器,方便调试
4.2 使用 docker commit 来制作镜像
1:先把 tomcat9 镜像运行起来
2:进入运行中的容器:docker exec -it 容器 id /bin/bash,当然,先通过 docker ps 获取容器号
3:进入运行起来的 tomcat 容器,删除掉 webapps 里面的东西,
然后再把自己的 server.xml 从宿主机拷贝到容器中,如:
docker cp ./server.xml 容器 id:/usr/local/apache-tomcat-9.0.1/conf/server.xml
4:制作镜像
docker commit -m=“remove default webapps”-a=“cc”容器 id cctomcat:9.0