Dockerfile详解

223 阅读9分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

用来干什么?

dockerfile是用来构建docker镜像的文件,命令参数脚本。

构建步骤:

  • 编写一个 dockerfile 文件
  • docker build构建成为一个镜像
  • docker run运行镜像
  • docker push发布镜像(DockerHub、阿里云镜像仓库)

查看别人的dockerfile

image.png

image.png

FROM scratch

官方说明:该镜像是一个空的镜像,可以用于构建busybox等超小镜像,可以说是真正的从零开始构建属于自己的镜像。要知道,一个官方的ubuntu镜像有60MB+,CentOS镜像有70MB+

scratch不可用被pull

很多官方的镜像都是基础包,很多功能都没有,我们通常会自己搭建自己的镜像。

构建Dockerfile

基础知识

  • 每个保留关键字(指令)都必须是大写字母
  • 执行从上到下顺序执行
  • #表示注释
  • 每一层指定都会创建提交一个新的镜像层,并提交。

image.png

  • dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件。Docker镜像逐渐成为企业交付的标准。

  • Dockerfile:构建文件,定义了一些步骤,源代码

  • Dockerimages:通过dockerfile构建生成镜像,最终发布和运行的产品

  • Docker容器: 容器就是镜像运行起来提供的服务器

指令

指令说明
FROM基础镜像,第一行必须是FROM(除注释)
MAINTAINER镜像是谁写的,姓名+邮箱
RUN镜像构建运行时候需要运行的命令
ADD添加文件到镜像内
WORKDIR镜像的工作目录
VOLUME挂载的目录
EXPOST暴露端口配置
CMD指定容器启动时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD当构建一个被继承 Dockerfile 这个是时候就会运行 ONBUILD的指令,触发指令
COPY类似ADD,将我们的文件拷贝到镜像中
ENV构建的时候设置环境变量

实战测试

构建自己的ubuntu

# 编写文件
$ vim ubuntu/Dockerfile
# 基础镜像
FROM ubuntu
# 作者信息
MAINTAINER 万恶的沫白<bcjy1229@163.com>

# 环境变量
ENV MYPATH /usr/local
# 工作目录
WORKDIR $MYPATH

# 构建运行的命令
RUN apt update
RUN apt install vim -y
RUN apt install net-tools

# 对外暴露的端口
EXPOSE 80

# 指定容器启动时运行的命令
CMD echo $MYPATH
CMD echo "------end-------"
CMD /bin/bash



# 构建镜像
# -f dockerfile 文件路径
# -t 镜像名:[tag]
$ docker build -f ubuntu/Dockerfile -t myubuntu:1.0 .
...
Successfully built 42691d166ea8
Successfully tagged myubuntu:1.0

# 运行我们的镜像,并测试我们加入进去的指定是否正确
$ docker run -it myubuntu:1.0
$ pwd
/usr/local
$ vim test

我们可以列出本地镜像的变更历史

$ docker history myubuntu:1.0
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
42691d166ea8   9 minutes ago    /bin/bash -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
0f5a535e3e24   9 minutes ago    /bin/bash -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
235e476881da   9 minutes ago    /bin/bash -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
1183c754beae   9 minutes ago    /bin/bash -c #(nop)  EXPOSE 80                    0B        
cd0475e10509   9 minutes ago    /bin/bash -c apt install net-tools                1.52MB    
46da59e6cabc   9 minutes ago    /bin/bash -c apt install vim -y                   68.2MB    
5ec6fc02d873   13 minutes ago   /bin/bash -c apt update                           30.4MB    
207d7e63bc7d   19 minutes ago   /bin/bash -c #(nop) WORKDIR /usr/local            0B        
8bd1c0e26d61   19 minutes ago   /bin/bash -c #(nop)  ENV MYPATH=/usr/local        0B        
3b83db470d0f   19 minutes ago   /bin/bash -c #(nop)  MAINTAINER 万恶的沫白<bcj…        0B        
1318b700e415   6 weeks ago      /bin/bash -c #(nop)  CMD ["bash"]                 0B        
<missing>      6 weeks ago      /bin/bash -c #(nop) ADD file:524e8d93ad65f08a0…   72.8MB  

通过上述方式,就可以看其他的镜像是怎么做的

CMDENTRYPOINT 区别

  • CMD
# 编写dockerfile 文件
$ vim ubuntu/Dockerfile-cmd
FROM ubuntu
CMD ["ls","-a"]
# 构建
$ docker build -f ubuntu/Dockerfile-cmd -t ubuntu-cmd:1.0 .
# 运行,发现ls-a 命令生效
$ docker run ubuntu-cmd:1.0
.
..
.dockerenv
bin
boot
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 追加一个命令 -l 就是 ls -al
$ docker run ubuntu-cmd:1.0 -l
# -l 命令 替换了 ["ls", "-a"] 命令,-l 不是命令所以报错
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled 
# 需要完整命令全部替换
$ docker run ubuntu-cmd:1.0 ls -al
total 56
drwxr-xr-x   1 root root 4096 Sep 13 14:57 .
drwxr-xr-x   1 root root 4096 Sep 13 14:57 ..
-rwxr-xr-x   1 root root    0 Sep 13 14:57 .dockerenv
lrwxrwxrwx   1 root root    7 Jul 23 17:35 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Apr 15  2020 boot
drwxr-xr-x   5 root root  340 Sep 13 14:57 dev
drwxr-xr-x   1 root root 4096 Sep 13 14:57 etc
drwxr-xr-x   2 root root 4096 Apr 15  2020 home
lrwxrwxrwx   1 root root    7 Jul 23 17:35 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Jul 23 17:35 lib32 -> usr/lib32
lrwxrwxrwx   1 root root    9 Jul 23 17:35 lib64 -> usr/lib64
lrwxrwxrwx   1 root root   10 Jul 23 17:35 libx32 -> usr/libx32
drwxr-xr-x   2 root root 4096 Jul 23 17:35 media
drwxr-xr-x   2 root root 4096 Jul 23 17:35 mnt
drwxr-xr-x   2 root root 4096 Jul 23 17:35 opt
dr-xr-xr-x 341 root root    0 Sep 13 14:57 proc
drwx------   2 root root 4096 Jul 23 17:38 root
drwxr-xr-x   5 root root 4096 Jul 23 17:38 run
lrwxrwxrwx   1 root root    8 Jul 23 17:35 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Jul 23 17:35 srv
dr-xr-xr-x  13 root root    0 Sep 13 14:57 sys
drwxrwxrwt   2 root root 4096 Jul 23 17:38 tmp
drwxr-xr-x  13 root root 4096 Jul 23 17:35 usr
drwxr-xr-x  11 root root 4096 Jul 23 17:38 var

  • ENTRYPOINT
# 编写dockerfile 文件
$ vim ubuntu/Dockerfile-entrypoint
FROM ubuntu
ENTRYPOINT ["ls","-a"]
# 构建
$ docker build -f ubuntu/Dockerfile-entrypoint -t ubuntu-entrypoint:1.0 .
# 运行,发现ls-a 命令生效
$ docker run ubuntu-entrypoint:1.0
.
..
.dockerenv
bin
boot
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 追加命令查看运行结果,是直接拼接在 ENTRYPOINT 命令后面
$ docker run ubuntu-entrypoint:1.0 -l
total 56
drwxr-xr-x   1 root root 4096 Sep 13 14:56 .
drwxr-xr-x   1 root root 4096 Sep 13 14:56 ..
-rwxr-xr-x   1 root root    0 Sep 13 14:56 .dockerenv
lrwxrwxrwx   1 root root    7 Jul 23 17:35 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Apr 15  2020 boot
drwxr-xr-x   5 root root  340 Sep 13 14:56 dev
drwxr-xr-x   1 root root 4096 Sep 13 14:56 etc
drwxr-xr-x   2 root root 4096 Apr 15  2020 home
lrwxrwxrwx   1 root root    7 Jul 23 17:35 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Jul 23 17:35 lib32 -> usr/lib32
lrwxrwxrwx   1 root root    9 Jul 23 17:35 lib64 -> usr/lib64
lrwxrwxrwx   1 root root   10 Jul 23 17:35 libx32 -> usr/libx32
drwxr-xr-x   2 root root 4096 Jul 23 17:35 media
drwxr-xr-x   2 root root 4096 Jul 23 17:35 mnt
drwxr-xr-x   2 root root 4096 Jul 23 17:35 opt
dr-xr-xr-x 342 root root    0 Sep 13 14:56 proc
drwx------   2 root root 4096 Jul 23 17:38 root
drwxr-xr-x   5 root root 4096 Jul 23 17:38 run
lrwxrwxrwx   1 root root    8 Jul 23 17:35 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Jul 23 17:35 srv
dr-xr-xr-x  13 root root    0 Sep 13 14:56 sys
drwxrwxrwt   2 root root 4096 Jul 23 17:38 tmp
drwxr-xr-x  13 root root 4096 Jul 23 17:35 usr
drwxr-xr-x  11 root root 4096 Jul 23 17:38 var

Dockerfile中很多命令都很相似,我们需要了解他们的区别。

TOMCAT

  • 准备镜像文件(tomcatjdk压缩包)
$ mkdir tomcat
$ wget -P tomcat/ https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.70/src/apache-tomcat-8.5.70-src.tar.gz

# 这块使用的是openjdk 13 版本,现在oracle下载挺麻烦的
$ wget -P tomcat/ https://download.java.net/openjdk/jdk13/ri/openjdk-13+33_linux-x64_bin.tar.gz

# 新建一个readme.md 文件
$ touch tomcat/readme.md

  • 编写dockerfile,官方推荐命名Dockerfile,build会自动寻找这个文件,就不需要-f指令了
FROM ubuntu

MAINTAINER 万恶的沫白<bcjy1229@163.com>

# 复制
COPY readme.md /usr/local/readme.md

# ADD 命令会自动解压
ADD apache-tomcat-8.5.70-src.tar.gz /usr/local/
ADD openjdk-13+33_linux-x64_bin.tar.gz /usr/local/

# 构建运行的命令
RUN apt update
RUN apt install vim -y
RUN apt install net-tools

# 环境变量
ENV MYPATH /usr/local
# 工作目录
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk-13
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.70-src 
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.70-src
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-8.5.70-src/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.70-src/bin/cataline.out
  • 构建dockerfile
# 切换到Dockerfile目录内
$ cd tomcat/
# build 会自动找到Dockerfile 文件
$ docker build -t mytomcat:1.0 .
Step 1/17 : FROM ubuntu
 ---> 1318b700e415
Step 2/17 : MAINTAINER 万恶的沫白<bcjy1229@163.com>
 ---> Using cache
 ---> 3b83db470d0f
Step 3/17 : COPY readme.md /usr/local/readme.md
 ---> b6b9675a0e91
Step 4/17 : ADD apache-tomcat-8.5.70-src.tar.gz /usr/local/
 ---> a48391d80602
Step 5/17 : ADD openjdk-13+33_linux-x64_bin.tar.gz /usr/local/
 ---> 6d62b3ba173a
Step 6/17 : RUN apt update
 ---> Running in d9aa46bebfad
...
Step 7/17 : RUN apt install vim -y
 ---> Running in a5508380dd5e
...
Step 8/17 : RUN apt install net-tools
 ---> Running in 326f554a9ee5
...
Step 9/17 : ENV MYPATH /usr/local
 ---> Running in 952b410ab010
Removing intermediate container 952b410ab010
 ---> e707f81bc5b4
Step 10/17 : WORKDIR $MYPATH
 ---> Running in 8dd948af01b3
Removing intermediate container 8dd948af01b3
 ---> caf20ab15b73
Step 11/17 : ENV JAVA_HOME /usr/local/jdk-13
 ---> Running in f63dd76d3cc2
Removing intermediate container f63dd76d3cc2
 ---> 1279e811878f
Step 12/17 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
 ---> Running in 1a262572cd81
Removing intermediate container 1a262572cd81
 ---> 103ed5e9bab6
Step 13/17 : ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.70-src
 ---> Running in 25103bfce833
Removing intermediate container 25103bfce833
 ---> 10b88a4bafda
Step 14/17 : ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.70-src
 ---> Running in cc397ce9da3f
Removing intermediate container cc397ce9da3f
 ---> 16cb9a628043
Step 15/17 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
 ---> Running in 4aaaf5fcee14
Removing intermediate container 4aaaf5fcee14
 ---> 1405b496012a
Step 16/17 : EXPOSE 8080
 ---> Running in 80f2c6b14f51
Removing intermediate container 80f2c6b14f51
 ---> 84f592791304
Step 17/17 : CMD /usr/local/apache-tomcat-8.5.70-src/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.70-src/bin/cataline.out
 ---> Running in 2d519815484a
Removing intermediate container 2d519815484a
 ---> b83d4e94f683
Successfully built b83d4e94f683
Successfully tagged mytomcat:1.0

  • 启动运行镜像
$ docker run -d -p 9090:8080 --name mytomcat -v /home/zbc/tomcat/test:/usr/local/apache-tomcat-8.5.70-src/webapps/test -v /home/zbc/tomcat/logs/:/usr/local/apache-tomcat-8.5.70-src/logs mytomcat:1.0 
5a7f6b285654a961ed3799b3488ad6d450a294489ddd211f8c676b74ca9e78ec

出现问题需要改进

而且构建镜像不算很好,没有很好的利分层技术

发布镜像

$ docker login --help

Usage:  docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username


# 登录账号
$ docker login -u bcjy1229
# 写密码
Password: 
WARNING! Your password will be stored unencrypted in /home/zbc/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

  • 在我们的服务器提交自己的镜像
$ docker push mytomcat:1.0
The push refers to repository [docker.io/library/mytomcat]
65d322d8e64d: Preparing 
17253f5b73dc: Preparing 
41a908891f5a: Preparing 
fe17c332a35e: Preparing 
3465caa6e326: Preparing 
dbc9c14f1cf1: Waiting 
7555a8182c42: Waiting 
denied: requested access to the resource is denied
# 最后发现被拒绝了,因为dockerhub已经有很多重名的tag

# 我们重新打一个tag,必须以自己的用户名开头 username/镜像名:版本号
$ docker tag mytomcat:1.0 bcjy1229/tomcat:1.0
The push refers to repository [docker.io/bcjy1229/tomcat]
65d322d8e64d: Pushed 
17253f5b73dc: Pushed 
41a908891f5a: Pushed 
fe17c332a35e: Pushed 
3465caa6e326: Pushed 
dbc9c14f1cf1: Pushed 
7555a8182c42: Pushed 
1.0: digest: sha256:fadfcef81b5812168fbbb8c9910a724ff529c36fe6457ae0f43f1354b620355c size: 1794

提交的时候也是按照镜像分层来提交的。