目录
④为什么docker中centos7镜像大小只有200M上下
一、Dockerfile介绍
dockerfile是一个文本文件,其中包含了一条条指令(instruction),用于构建镜像。每一条指令构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建。虽然在dockerhub中官方提供的很多镜像已经能满足我们的所有服务,但总归有足够个性化的功能是其覆盖不到的,这就体现出dockerfile编写的必要性,它就相当于“创意工坊”,让编写者可以根据不同的使用环境、方向,不同的功能需求,制定编写个性化的,不尽相同的dockerfile,并在这个镜像基础上搭建运行容器
构建过程
编写dockerfile文件 ===》“docker build”构建镜像 ===》“docker run”运行容器
①dockerfile原理(镜像分层)
(1)Dockerfile中的每个指令都会创建一个新的镜像层(是一个临时的容器,执行完后将不再存在,再往后进行重新的创建与操作)
(2)镜像层将被缓存和复用(后续的镜像层将基于前面的一层,每一层都会有下面几层的缓存)
(3)当dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了(后续操作必然更改前面的镜像层),那么对应的镜像层缓存就会失效(自动销毁)
(4)某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效(第一层不成功,那么第二层也不成功,相当于地基)
(5)容器的修改并不会影响镜像,如果在某一层中添加一个文件,在下一层中删除它,镜像中依然会包含该文件
②镜像结构
container:容器层
images:镜像层
rootfs:基础层
(root file system) 内核空间
-
在bootfs之上(base images, 例如centos、ubuntu)
-
包含的就是典型Linux 系统中的/dev, /proc, /bin, /etc 等标准目录和文件
-
rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等
bootfs:内核层
(boot file system) 内核空间
1.主要包含bootloader和kernel
2.bootloader主要引导加载kernel, Linux刚启 动时会加载bootfs文件系统,在Docker 镜像的最底层是bootfs
3.这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会把临时创建的bootfs这个文件系统删掉
4.在linux操作系统中,linux加载bootfs时会将rootfs设置为read-only,系统自检后会将只读改为读写,让我们可以在操作系统中进行操作
③Dockerfile结构
基础镜像信息(Linux发行版:centos ubantu suse debian alpine redhat)
维护者信息(docker search可查看)
镜像操作指令(tar yum make)
容器启动时执行指令(cmd[“/root/run.sh”] 、entrypoint都是系统启动时,第一个加载的程序/脚本/命令)
④为什么docker中centos7镜像大小只有200M上下
因为docker镜像只有rootfs和其他镜像层,共用宿主机的linux内核(bootfs),因此很小
bootfs + rootfs :作用是加载、引导内核程序 + 挂载使用linux 操作系统(centos ubantu)等等一些关键的目录文件
就是说bootsfs用内核的,rootfs用自己的
对于一个精简的os,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Rost的kernel,自己只需要提供rootfs就行了。所以对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,所以不同的发行版可以公用bootfs
二、Dockerfile命令
①FROM
基本上都会出现在DockerFile的第一行。代表你目前的镜像来自于哪,它的基础镜像是什么。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
②MAINTAINER和USER
MAINTAINER
指定维护者信息
MAINTAINER <name>
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要临时获取管理员权限可以使用 gosu,而不推荐 sudo
USER
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。 镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户
③RUN
在所基于的镜像上执行命令,并提交到新的镜像中;分为
在 shell 终端中运行命令,如 /bin/sh -c;
使用 exec 执行,如RUN [“/bin/bash”, “-c”, “echo $HOME”]
shell
RUN <command>
exec
RUN ["executable","param1","param2"]
④CMD和ENTRYPOINT
CMD
指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时候指定了运行的命令(如/bin/bash),则会覆盖掉 CMD 指定的命令
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
ENTRYPOINT
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效
ENTRYPOINT ["executable", "param1", "param2"]
#(可执行文件, 优先)
ENTRYPOINT command param1 param2
#(shell内部命令)
4.1CMD、ENTRYPOINT
cmd 是容器环境启动时默认加载的命令 entrypoint 是容器环境启动时第一个加载的命令程序/脚本程序 init
如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式;如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略
⑤EXPOSE
容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。
EXPOSE <port> [<port>...]
*:EXPOSE并不会让容器的端口访问到主机,要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。
如果没有暴露端口,后期也可以通过-p 8080:80方式映射端口,但是不能通过-P形式映射
⑥ENV
指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。
ENV <key> <value>
#<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value>...
#可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来
#进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
例:
ENV myname ljp
ENV myname ljp ljp2
ENV myname=ljp
⑦ADD和COPY
ADD
该命令将复制指定的src到容器中的 。 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(并自动解压为目录)
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
#用于支持包含空格的路径
例:
ADD nginx-1.22.0.tar.gz Test/
COPY
复制本地主机的 (为 Dockerfile 所在目录的相对路径)到容器中的 。当使用本地目录为源目录时,推荐使用 COPY。
⑧VOLUME
相当于运行容器时的-v
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
VOLUME /path /dir
例:
VOLUME /log/messages /container/logs
卷可以容器间共享和重用
修改卷后会立即生效
对卷的修改不会对镜像产生影响
卷会一直存在,直到没有任何容器在使用它
⑨WORKDIR
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。
可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径
如第一次WORKDIR /test,此时工作目录为/test
第二次WORKDIR test1,此时工作目录为/test/test1/
在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
WORKDIR /path/to/workdir
三、dockerfile构建一个Tomcat镜像
mkdir /mysql
mv mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz /mysql/
mv mysql_data.tar.gz /mysql/
①编写dockerfile
FROM centos:7
MAINTAINER paullyu@foxmail.com
ADD apache-tomcat-9.0.16.tar.gz /usr/local
COPY jdk-8u201-linux-x64.rpm /usr/local
WORKDIR /usr/local
RUN mv apache-tomcat-9.0.16 tomcat && rpm -ivh jdk-8u201-linux-x64.rpm
ENV JAVA_HOME /usr/java/jdk1.8.0_201-amd64
ENV CLASS_PATH $JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
基础镜像centos:7,维护者信息
解压缩tomcat的tar包到/use/local,复制jdk的rpm包进/usr/local
定义工作目录 /usr/local,tomcat解压后目录改名,rpm安装jdk
指定JAVA变量
EXPOSE端口号8080
容器运行命令,开启tomcat
②创建镜像并运行
创建镜像
[root@ljp tomcat]# ls
apache-tomcat-9.0.16.tar.gz dockerfile jdk-8u201-linux-x64.rpm
[root@ljp tomcat]# docker build -t tomcat:test
基于创建的镜像运行容器
docker run -itd --name tomcat -p 9090:8080 tomcat:test
netstat -natp | grep 9090
tcp 0 0 0.0.0.0:9090 0.0.0.0:* LISTEN 16701/docker-proxy
tcp6 0 0 :::9090 :::* LISTEN 16707/docker-proxy
docker ps -a
③网页浏览tomcat
http://192.168.116.22:9090