基础篇 Dockerfile
内容概述
Dockerfile 可以认为是Docker 镜像的描述文件,是由一系列命令和参数构成的脚本。主要作用是**用来构建docker 镜像的构建文件 **。
# 1. DockerFile
构建步骤:
- 编写一个dockerfile 文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(DockerHub、阿里云镜像仓库)
可以查看一下官方怎么做的,docker hub 官方文档:https://hub.docker.com/_/centos (opens new window)
# 1.1 DockerFile 简介
基础知识:
- 每个保留关键字(指令)都必须是大写字母
- 执行从上到下顺序执行
#表示注释- 每一个指令都会创建提交一个新的镜像层,并提交

DockerFile 是面向开发的,发布项目、作镜像,就需要编写DockerFile 文件。
Docker 镜像逐渐成为企业交付的标准,必须要掌握!
步骤:开发,部署,运维。。。。缺一不可
DockerFile:构建文件,定义了一切的步骤,类似开发的源代码
DockerImage:通过DockerFile 构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务器
# 1.2 DockerFile 解析过程

# 1.3 DockerFile 保留命令
官方说明:https://docs.docker.com/engine/reference/builder/ (opens new window)
| 保留字 | 作用 |
|---|---|
| FROM | 基础镜像,当前镜像是基于哪个镜像的 第一个指令必须是FROM |
| MAINTAINER | 镜像维护者信息,姓名+邮箱地址,如:zhangsan<zhangsan@qq.com> |
| RUN | 构建镜像时需要运行的指令 |
| EXPOSE | 当前容器对外暴露出的端口号 |
| WORKDIR | 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点 |
| ENV | 用来在构建镜像过程中设置环境变量 |
| ADD | 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar包 |
| COPY | 类似于ADD,拷贝文件和目录到镜像中 将从构建上下文目录中<原路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置 |
| VOLUME | 容器数据卷,用于数据保存和持久化工作 |
| ONBUILD | 用于设置当此镜像作为其他镜像的基础镜像时,所执行的构建操作 |
| CMD | 指定一个容器启动时要运行的命令 Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换 |
| ENTRYPOINT | 指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及其参数 |
# FROM
基于哪个镜像进行构建新的镜像,在构建时会自动从docker hub 拉取base 镜像 必须作为Dockerfile 的第一个指令出现
语法:
FROM <image>
FROM <image>[:<tag>] # 使用版本不写为latest
FROM <image>[@<digest>] # 使用摘要
2
3
# MAINTAINER
- 镜像维护者的姓名和邮箱地址[废弃]
- 语法:
MAINTAINER <name>
# RUN
RUN 指令将在当前映像之上的新层中执行任何命令并提交结果,生成的提交映像将用于Dockerfile 中的下一步。
语法:
RUN <command> (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
RUN echo hello
RUN ["executable", "param1", "param2"] (exec form)
RUN ["/bin/bash", "-c", "echo hello"]
2
3
4
5
# EXPOSE
用来指定构建的镜像在运行为容器时对外暴露的端口
语法:
EXPOSE 80/tcp # 如果没有显示指定则默认暴露都是tcp
EXPOSE 80/udp
2
# CMD
用来为启动的容器指定执行的命令,在Dockerfile 中只能有一条CMD 指令。如果列出多个命令,则只有最后一个命令才会生效。
注意: Dockerfile中只能有一条CMD指令。如果列出多个命令,则只有最后一个命令才会生效。
语法:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
2
3
# WORKDIR
用来为Dockerfile 中的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令设置工作目录。如果WORKDIR 不存在,即使它没有在任何后续Dockerfile 指令中使用,它也将被创建。
注意:WORKDIR指令可以在Dockerfile 中多次使用。如果提供了相对路径,则该路径将与先前WORKDIR 指令的路径相对
语法:
WORKDIR /path/to/workdir
WORKDIR /a
WORKDIR b
WORKDIR c
2
3
4
5
# ENV
用来为构建镜像设置环境变量。这个值将出现在构建阶段中所有后续指令的环境中。
语法:
ENV <key> <value>
ENV <key>=<value> ...
2
# ADD
用来从context上下文复制新文件、目录或远程文件url,并将它们添加到位于指定路径的映像文件系统中。
语法:
ADD hom* /mydir/ # 通配符添加多个文件
ADD hom?.txt /mydir/ # 通配符添加
ADD test.txt relativeDir/ # 可以指定相对路径
ADD test.txt /absoluteDir/ # 也可以指定绝对路径
ADD url # RUL 添加
2
3
4
5
# COPY
用来将context 目录中指定文件复制到镜像的指定目录中。
语法:
COPY src dest
COPY ["<src>",... "<dest>"]
2
# VOLUME
容器数据卷,用来定义容器运行时可以挂在到宿主机的目录。
语法:
VOLUME ["/data"]
# ENTRYPOINT
用来指定容器启动时执行命令和CMD 类似。
语法:
["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
2
ENTRYPOINT指令,往往用于设置容器启动后的第一个命令,这对一个容器来说往往是固定的。CMD指令,往往用于设置容器启动的第一个命令的默认参数,这对一个容器来说可以是变化的。
# ONBUILD
单发指令,指定的命令在构建镜像时并不执行,当构建一个被继承Dockerfile 时就会运行ONBUILD 的指令,即在它的子镜像中执行。
语法:
ONBUILD <其它指令>
# 1.3 Dockerfile 构建

Docker Hub 中99% 镜像都是从这个基础镜像过来的FROM search,然后配置需要的软件和配置来进行构建的。

# 1.4 镜像历史变更信息
docker history 镜像ID
利用这个命令,我们平时拿到一个镜像,可以研究一下它是怎么做的,学下别人的镜像构建!
# 1.5 CMD 和 ENTRYPOINT 区别详解
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替换
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
2
# CMD
# step 1:编写dockerfile文件
[root@ibytehorizon dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
# step 2:构建镜像
[root@ibytehorizon dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
Sending build context to Docker daemon 3.072 kB
step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : CMD ls -a
---> Running in ce51153e17f2
---> d789f3b53533
Removing intermediate container ce51153e17f2
Successfully built d789f3b53533
# step 3:run 运行,发现ls -a 命令生效
[root@ibytehorizon dockerfile]# docker run d789f3b53533
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
# step 4:想追加一个命令 -l
[root@ibytehorizon dockerfile]# docker run d789f3b53533 -l
container_linux.go:247: starting container process caused "exec: \"-l\": executable file not found in $PATH"
docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"-l\": executable file not found in $PATH".
# 分析:cmd的情况下 -l 替换了["ls","-a"]命令,-l 不是命令所以报错,要用"ls -al"
[root@ibytehorizon dockerfile]# docker run d789f3b53533 ls -al
total 0
drwxr-xr-x 1 root root 46 Feb 24 06:27 .
drwxr-xr-x 1 root root 46 Feb 24 06:27 ..
-rwxr-xr-x 1 root root 0 Feb 24 06:27 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Feb 24 06:27 dev
drwxr-xr-x 1 root root 66 Feb 24 06:27 etc
drwxr-xr-x 2 root root 6 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# ENTRYPOINT
# step 1:编写dockerfile文件
[root@ibytehorizon dockerfile]# more dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
# step 2:构建镜像
[root@ibytehorizon dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .
Sending build context to Docker daemon 4.096 kB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : ENTRYPOINT ls -a
---> Running in ef556bdc97b6
---> d1819419faf8
Removing intermediate container ef556bdc97b6
Successfully built d1819419faf8
# step 3:运行run
[root@ibytehorizon dockerfile]# docker run d1819419faf8
.
..
.dockerenv
bin
dev
etc
# step 4:追加命令是直接拼接在entrypoint 命令的后面
[root@ibytehorizon dockerfile]# docker run d1819419faf8 -l
total 0
drwxr-xr-x 1 root root 46 Feb 24 06:31 .
drwxr-xr-x 1 root root 46 Feb 24 06:31 ..
-rwxr-xr-x 1 root root 0 Feb 24 06:31 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Feb 24 06:31 dev
drwxr-xr-x 1 root root 66 Feb 24 06:31 etc
drwxr-xr-x 2 root root 6 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 2. 实战案例
# 2.1 案例一:DIY 自己的centos 镜像
# 1、编写dockerfile 文件
[root@ibytehorizon dockerfile]# cat dockerfile-centos
FROM centos
MAINTAINER zhangshh<123456@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
# 2、通过文件构建镜像
# 命令:docker build -f dockerfile 文件路径 -t 镜像名:[tag] .
[root@ibytehorizon dockerfile]# docker build -f dockerfile-centos -t mycentos:0.1 .
Successfully built 1f340416b729
Successfully tagged mycentos:0.1
# 3、测试运行
[root@ibytehorizon dockerfile]# docker run -it mycentos:0.1
[root@aff57c457bd3 local]# pwd
/usr/local
[root@aff57c457bd3 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe11:3 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 648 (648.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
注意: 第一步编写dockerfile文件内容可能会报错,可能会出现超时、官网镜像版本不存在等问题,可以使用以下内容替换:
FROM centos:7 # 指定centos7 版本
MAINTAINER zhangshh<12345678@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 由于centos7 停止服务,这里使用阿里云提供的centos7 镜像
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum makecache
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
对比:之前的原生的centos 工作目录默认是根目录,没有vim、ifconfig 等命令,我们自己的镜像有了这些。
[root@ibytehorizon ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 09f78379ee8a 2 days ago 1.23GB
centos latest 5d0da3dc9764 3 years ago 231MB
[root@ibytehorizon ~]# docker run -it 09f78379ee8a /bin/bash
[root@46ebeea468cb local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 9 bytes 766 (766.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@46ebeea468cb local]# vim
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2.2 案例二:Dockerfile 制作Tomcat 镜像
step 1:准备镜像文件:Tomcat 压缩包、jdk的压缩包
step 2:编写dockerfile 文件,官方命名
Dockerfile,build会自动去寻找这个文件,就不需要-f 进行指定
PS:Tomcat、jdk、dockerfile在同一目录下。
[root@ibytehorizon ceshi]# vi Dockerfile
FROM centos
MAINTAINER zhangshh<1234@qq.com>
COPY readme.txt /usr/local/readme.txt
# ADD 会直接解压压缩包到指定目录
ADD jdk-8u281-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.43-src.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 环境变量配置
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.43
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.43
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.43/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.43/bin/logs/catalina.out
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
step 3:构建镜像
# docker build -t diytomcat .
step 4:启动镜像
[root@ibytehorizon ceshi]# docker run -d -p 9090:8080 -v /home/ceshi/tomcat/test:/usr/local/apache-tomcat-9.0.43-src/webapps/test -v /home/ceshi/tomcat/logs/:/usr/local/apache-tomcat-9.0.43-src/logs --name tomcat1 diytomcat
d1d0629cd3698106e125e276d8e42e419bfea0846cce10125f6615af85b19d0d
[root@ibytehorizon ~]# docker exec -it d1d0629cd3698106e /bin/bash
[root@d1d0629cd369 local]# ls
apache-tomcat-9.0.43-src etc include lib libexec sbin src
bin games jdk1.8.0_281 lib64 readme.txt share
[root@d1d0629cd369 local]#
2
3
4
5
6
7
step 5:访问测试
# 1、宿主机上进行端口访问
[root@ibytehorizon logs]# curl localhost:9090
# 2、通过网页访问 http://ip:9090
2
3
step 6:发布项目(由于做了卷挂载,直接在本地编写项目就可以发布了!)
1、本地/home/ceshi/tomcat/test目录下创建WEB.INF文件(数据卷,本地修改同步)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>
2
3
4
5
6
7
8
2、本地/home/ceshi/tomcat/test目下创建index.jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello,lili</title>
</head>
<body>
Hello World!<br/>
<%
System.out.println("-----my test logs-----");
%>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3、访问测试
http://ip:8787/test
# 3. 发布镜像
# 3.1 发布到Docker Hub
step 1:注册自己的账号,Docker Hub (opens new window)
step 2:确定这个账号可以登录使用
step 3:在我们的服务器上提交自己的镜像
[root@ibytehorizon ~]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker registry
Options:
--help Print usage
-p, --password string Password
-u, --username string Username
# 登录
[root@ibytehorizon ~]# docker login -u zhangshh
Password:
Login Succeeded
2
3
4
5
6
7
8
9
10
11
12
13
14
step 4:登录后就可以提交镜像,就是一步 docker push
# push 自己的镜像到服务器上
[root@ibytehorizon ~]# docker push diytomcat_test
The push refers to a repository [docker.io/library/diytomcat_test]
b4d7618edb5e: Preparing
587f278d6960: Preparing
55414205cbe5: Preparing
2a6d9faf7bf2: Preparing
2653d992f4ef: Preparing
denied: requested access to the resource is denied #拒绝
# push 镜像的问题
[root@ibytehorizon ~]# docker push zhangshh/diytomcat_test:1.0
The push refers to a repository [docker.io/zhangshh/diytomcat_test]
An image does not exist locally with the tag: zhangshh/diytomcat_test
# 解决,增加一个tag
[root@ibytehorizon ~]# docker tag 07111f717529 zhangshh/tomcat:1.0
[root@ibytehorizon ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat_test latest 07111f717529 17 hours ago 640 MB
zhangshh/tomcat 1.0 07111f717529 17 hours ago 640 MB
# docker push上去即可,自己发布的镜像尽量带上版本号
[root@ibytehorizon ~]# docker push zhangshh/tomcat:1.0
The push refers to a repository [docker.io/zhangshh/tomcat]
b4d7618edb5e: Pushed
587f278d6960: Pushed
55414205cbe5: Pushed
2a6d9faf7bf2: Pushed
2653d992f4ef: Pushed
1.0: digest: sha256:0350fbd1fd19a121de1fcda6e56976c77803cff0a7e838ae158c1ce1d90a6510 size: 1373
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
值得注意的是,提交的时候也是按照镜像的层级来进行提交的!
# 3.2 发布到阿里云镜像服务
step 1:登录阿里云
step 2:找到容器镜像服务
step 3:创建命名空间

step 4:创建容器镜像

5、浏览阿里云信息

[root@ibytehorizon ~]# docker tag 07111f717529 registry.cn-chengdu.aliyuncs.com/zhangshh/zhangshh-test:1.0
[root@ibytehorizon ~]# docker push registry.cn-chengdu.aliyuncs.com/zhangshh/zhangshh-test:1.0
The push refers to a repository [registry.cn-chengdu.aliyuncs.com/zhangshh/zhangshh-test]
b4d7618edb5e: Pushed
587f278d6960: Pushed
55414205cbe5: Pushed
2a6d9faf7bf2: Pushed
2653d992f4ef: Pushed
1.0: digest: sha256:0350fbd1fd19a121de1fcda6e56976c77803cff0a7e838ae158c1ce1d90a6510 size: 1373
2
3
4
5
6
7
8
9
阿里云容器镜像就参考官方地址,有完整的教程!
# 4. Dockerfile 打包镜像

# 4.1 docker save
保存打包镜像,当你需要把自己的镜像打包发给别人时候可以使用这个命令。
$ docker save 镜像名 -o 镜像名.tar
[root@ibytehorizon ~]# docker save --help
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Options:
--help Print usage
-o, --output string Write to a file, instead of STDOUT
[root@ibytehorizon ~]# docker save -o mycentos.tar mycentos:0.1
[root@ibytehorizon ~]# ll
-rw------- 1 root root 290237440 Feb 26 15:37 mycentos.tar
2
3
4
5
6
7
8
9
10
11
12
# 4.2 docker load
加载镜像,当别人打包镜像发给你,你需要使用该镜像文件时候使用该命令。
$ docker load -i 文件.tar
示例:
[root@ibytehorizon ~]# docker load --help
Usage: docker load [OPTIONS]
Load an image from a tar archive or STDIN
Options:
--help Print usage
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output
[root@ibytehorizon ~]# docker load -i mycentos.tar
Loaded image: mycentos:0.1
2
3
4
5
6
7
8
9
10
11