Dockerfile是一个包含用于组合映像的命令的文本文档。可使用在命令行中调用任何命令。 Docker经过读取 Dockerfile 中的指令自动生成映像。docker build 命令用于从 Dockerfile 构建映像。能够在 docker build 命令中使用 -f 标志指向文件系统中任何位置的Dockerfile。html
例如:docker build -f /path/to/a/Dockerfilemysql
Dockerfile 通常分为四部分:基础镜像信息、维护者信息、镜像操做指令和容器启动时执行指令,## 为 Dockerfile 中的注释信息。linux
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。注意:以#字符开头,被视为注释。能够在Docker文件中使用RUN(执行)、CMD(命令)、FROM(指定基本的映像信息)、EXPOSE、ENV等指令。nginx
格式: web
FROM <image> FROM <image>:<tag> FROM <image>@<digest>sql
示例:docker
FROM mysql:5.6 ##注意:tag或digest是可选的,若是不使用这两个值时,会使用latest版本的基础镜像shell
格式:数据库
MAINTAINER <name>ubuntu
示例:
MAINTAINER wangfang MAINTAINER wang@qq.com MAINTAINER wangfang <wang@qq.com>
RUN用于在镜像容器中执行命令,具备两种命令执行的方式:
(1)shell执行:RUN <command>
(2)exec执行:RUN ["executable", "param1", "param2"] 示例:RUN ["/etc/execfile", "arg1", "arg1"]
格式:
ADD <src>... <dest> ADD ["<src>",... "<dest>"] ##用于支持包含空格的路径
示例:
ADD hom* /mydir/ ##添加全部以"hom"开头的文件
ADD hom?.txt /mydir/ ## ? 替代一个单字符。例如:"home.txt"
ADD test relativeDir/ ## 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ ##添加 "test" 到 /absoluteDir/
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先) CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数) CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"] ##注意:CMD不一样于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"] ##注意:ENTRYPOINT与CMD很是相似,不一样的是经过 docker run 执行的命令不会覆盖ENTRYPOINT,而 docker run 命令中指定的任何参数,都会被当作参数再次传递给ENTRYPOINT。Dockerfile中只容许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令
格式:
ENV <key> <value> ##<key>以后的全部内容均会被视为其<value>的组成部分,所以,一次只能设置一个变量
ENV <key>=<value> ... ##能够设置多个变量,每一个变量为一个"<key>=<value>"的键值对,若是<key>中包含空格,可使用\来进行转义,也能够经过""来进行标示;另外,反斜线也能够用于续行
示例:
ENV myName wangfang ENV myDog Rourou The Dog ENV myCat=kitty
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443 EXPOSE 8080 EXPOSE 11211/tcp 11211/udp ##注意:EXPOSE并不会让容器的端口访问到主机。要使其可访问,须要在 docker run 运行容器时经过 -p 来发布这些端口,或经过 -p 参数来发布EXPOSE导出的全部端口
格式:
WORKDIR /path/to/workdir ## WORKDIR至关于linux中的命令 cd
示例:
WORKDIR /a (这时工做目录为/a) WORKDIR b (这时工做目录为/a/b) WORKDIR c (这时工做目录为/a/b/c)
注意:经过WORKDIR设置工做目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用 docker run 运行容器时,能够经过 -w 参数覆盖构建时所设置的工做目录。
格式:
volume ["/data"]
示例:
volume ["/avr/log/message"]
volume /var/log
volume /var/log /etc/passwd
==========================================================================
ENTRYPOINT 容器启动后执行的命令,让容器执行表现的像一个可执行程序同样,与CMD的区别是:ENTRYPOINT 不会被 docker run 覆 盖 , 会把 docker run 后面的参数,如:$name 等,看成传递给 ENTRYPOINT 指令的参数。Dockerfile 中只能指定一个 ENTRYPOINT,若是指定了不少,只有最后一个有效。docker run 命令的 -entrypoint 参数能够把指定的参数继续传递给 ENTRYPOINT。
下面进行相应的测试,利用结果感受这两个参数的不一样:
docker load -i busybox.tar ##导入一个镜像
cd /tmp/docker/
mkdir test
cd test/
pwd
/tmp/docker/test
vim Dockerfile
FROM busybox
ENV name world
CMD echo "hello,$name"
docker build -t busybox:v1 . ##建立镜像
docker run --rm busybox:v1 ##利用镜像建立新的容器
hello,world
vim Dockerfile
FROM busybox
ENV name world
CMD ["/bin/echo","hello,$name"]
docker build -t busybox:v2 .
docker run --rm busybox:v2
hello,$name
vim Dockerfile
FROM busybox
ENV name world
CMD ["/bin/sh","-c","echo hello, $name"] ##这个命令在底层实际执行过程当中,调用 /bin/sh -c echo "hello world"
docker build -t busybox:v3 .
docker run --rm busybox:v3
hello, world
vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
docker build -t busybox:v4 .
docker run --rm busybox:v4
hello world
docker run --rm busybox:v4 westos
hello westos
==========================================================================
docker load -i rhel7.tar
pwd
/tmp/docker
vim Dockerfile
FROM rhel7 ##源镜像是rhel7,最好将名为rhel7的镜像放在本地
ENV HOSTNAME server1
COPY dvd.repo /etc/yum.repos.d/dvd.repo ##仓库没有yum源,将真机的yum源cp到容器里
RUN rpmdb --rebuilddb && yum install -y httpd && yum clean all ##执行命令安装httpd并清除yum缓存,rpmdb 命令用于初始化和重建rpm数据库,--rebuilddb:从已安装的包头文件,反向重建RPM数据库
EXPOSE 80 ##定义端口为80
CMD ["/usr/share/httpd","-D","FOREGROUND"] ### 打开apach服务, -D 是全局文件/etc/sysconfig/httpd中的打开参数
vim yum.repo
[rhel7.3]
name=rhel7.3
baseurl=http://172.25.254.1/rhel7.3 ##这里是网络yum源,本地的yum源用的是 file:/// 格式。
gpgcheck=0
以前都是用公共仓库中的镜像,直接用命令search 寻找相应的镜像,而后进行相应的拉取,最后直接利用镜像建立容器就能够了。如今使用的Dockerfile,就至关因而要用最基础的镜像配置(自定义)咱们本身的镜像,而后也能够上传到私有仓库或者共有仓库当中。就至关于用刚才编写的 Dockerfile 文件所用的基础的镜像,在基础的镜像上添加了许多的新的应用,就好比这里添加的HTTP的功能,而后将这个新的添加了功能的这个容器封装成新的镜像,而后用新封装的镜像去建立容器,这样,这个建立的容器就能够,具备HTTP的服务。
docker build -t rhel7:v1 . (注意后面 有个点表示当前目录) ##使用当前目录的 Dockerfile 建立镜像,标签为 rhel7:v1
docker run -d --name vm1 rhel7:v1 ##利用刚才新建立的封装的镜像建立须要HTTP的容器。新的镜像就至关于一个支持HTTP的镜像
docker inspect vm1 ##查看新建立的容器vm1的信息,如:IP(172.17.0.2)
cd /tmp/docker/
ls
Dockerfile dvd.repo
vim index.html
www.westos.org
docker container cp index.html vm1:/var/www/html
curl 172.17.0.2 ##能够正常访问使用
www.westos.org
vim Dockerfile
FROM rhel7
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb && yum clean all && yum install -y httpd
EXPOSE 80
VOLUME ["var/www/html"] ##将主机上的某一个目录或者路径下的文件挂载到docker容器上
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
docker build -t rhel7:v2 . ##封装新的有挂载的镜像 rhel7:v2
此时能够看到 rhel7:v2比 rhel7:v1多了一层: 利用 docker history 容器名 查看容器的每一层的实际的内容
mkdir webdata
mv index.html webdata/
ls
Dockerfile webdata yum.repo
docker rm -f vm1
docker run -d --name vm1 -v /tmp/docker/webdata:/var/www/html rhel7:v2 ##若是指定挂载的路径,source就是指定的。若是没有指定的话,就像下面的操做同样,直接利用镜像建立了容器,挂载的目录路径是默认的。能够用 inspect 查看
a8203a3b35eeeec170b7283fbbda136cffebc180a41c49891d3dd80c99f0e8ed
curl 172.17.0.2 ##能够正常的访问
www.westos.org
直接在数据卷中修改:docker rm -f vm1 docker run -d --name vm1 rhel7:v2
查看vm1的数据卷的位置:
进入数据卷位置并编写发布文件并测试:
cd /var/lib/docker/volumes/f03725ca02f048a96dc78ed02f3c9b1c29b198458d99a0765e7d51d56d22def9/_data
cp /tmp/docker/webdata/index.html .
ls
index.html
curl 172.17.0.2
www.westos.org
echo hello,world >> index.html
cat index.html
www.westos.org
hello,world
curl 172.17.0.2
www.westos.org
hello,world
docker rm -f vm1 ##由于设置的不一样,须要将以前的容器删除。
docker run -d --name vm1 -v /tmp/docker/webdata:/data:ro rhel7:v2 ##指定了docker挂载的目录路径,并且设置了只读挂载 ro
docker inspect vm1 ##找到source对应的数据卷位置
/var/lib/docker/volumes/267d70d0fec9229a426c4e14f83b614ae4bc5acdbc2723862e0af006a78a2ec9/_data
docker volume rm f03725ca02f048a96dc78ed02f3c9b1c29b198458d99a0765e7d51d56d22def9 ##删除以前的数据卷
docker exec -it vm1 bash
bash-4.2# cd data/
bash-4.2# ls
index.html
bash-4.2# rm -fr index.html
rm: cannot remove 'index.html': Read-only file system ##删除文件被拒,显示只读Read-only
bash-4.2# cat index.html ##能够正常读取
www.westos.org
ls
Dockerfile nginx-1.15.8.tar.gz test webdata yum.repo
vim Dockerfile ## 没有优化以前的Dockerfile文件
FROM rhel7
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make ##解决依赖性,相关的应用的下载
ADD nginx-1.15.8.tar.gz /mnt ##ADD比COPY更强大,若是文件是可识别的压缩文件,会帮忙解压
WORKDIR /mnt/nginx-1.15.8 ##至关于 cd 到刚才解压之后的目录里面,而后执行下面的操做
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc ##关闭debug日志
RUN ./configure --prefix=/usr/local/nginx ##源码编译生产相应的makefile
RUN make
RUN make install
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v3 .
docker rm -f vm1
docker run -d --name vm1 rhel7:v3
docker inspect vm1 ##查看 source 的绝对路径,和容器vm1的分配到的IP
/var/lib/docker/volumes/2e9222ac2ddb8c79ea4391a9c4e6105dad6065cfcf2aa0f25c29273b9036769c/_data
cd /var/lib/docker/volumes/2e9222ac2ddb8c79ea4391a9c4e6105dad6065cfcf2aa0f25c29273b9036769c/_data
ls
50x.html index.html
echo "wangfang" > index.html
cat index.html
wangfang
curl 172.17.0.2 #能够正常访问
wangfang
vim Dockerfile
FROM rhel7
COPY yum.repo /etc/yum.repos.d/yum.repo
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all
ADD nginx-1.15.8.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.8
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --prefix=/usr/local/nginx &> /dev/null
RUN make &> /dev/null
RUN make install &> /dev/null
RUN rm -fr /mnt/nginx-1.15.8
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v4 .
Successfully built fba2f9ad94cd
Successfully tagged rhel7:v4
vim Dockerfile
FROM rhel7
COPY yum.repo /etc/yum.repos.d/yum.repo
ADD nginx-1.15.8.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.8
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx &> /dev/null && make &> /dev/null && make install &> /dev/null && rm -fr /mnt/nginx-1.15.8
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v5 .
docker images rhel7 ##镜像有减少,可是减少的不太明显
(1)先将上面的 FROM rhel7 as build 利用 docker build 封装成标签为 latest 的镜像,而后下面的 FROM 会使用上面的标签的镜像进行接着封装镜像。就至关于新封装的镜像,只有141-140=1MB的大小。对于nginx之中,安装过程当中会有一些输出的过程、二进制文件、安装相应的gcc等的依赖。到最后都用不到,可以使用到的就是那个1MB的安装好的,只须要将这1MB独自安装成镜像
vim Dockerfile
FROM rhel7 as build
COPY yum.repo /etc/yum.repos.d/yum.repo
ADD nginx-1.15.8.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.8
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx &> /dev/null && make &> /dev/null && make install &> /dev/null && rm -fr /mnt/nginx-1.15.8
FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v6 .
docker load -i distroless.tar
docker load -i nginx.tar
vim Dockerfile
FROM nginx as base ##https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG Asia/Shanghai
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base
COPY --from=base /opt /
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
docker build -t rhel7:v7 .
docker run -d --name vm1 rhel7:v7
docker run -d --name vm1 rhel7:v7
在网页的页面上输入:172.17.0.2