Docker-基础004-DockerFile的编写

Posted gcxblogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker-基础004-DockerFile的编写相关的知识,希望对你有一定的参考价值。

学习内容总结来自B站UP主"遇见狂神说"的Docker教学视频: https://www.bilibili.com/video/BV1og4y1q7M4

DockerFile

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

构建步骤:

  • 编写dockerfile文件
  • docker build 构建成一个镜像
  • docker run 运行镜像创建容器
  • docker push 发布镜像

创建dockerfile

创建规则

  • 每个保留关键字必须时大写字母

  • 命令从上往下依次执行

  • 每执行一个命令都会创建提交一个新的镜像层

  • # 表示注释

技术图片

常用命令关键字

  • FROM 指定基础镜像, 可以理解为继承的父类
  • MAINTAINER 维护者/作者信息, 一般格式为姓名加邮箱
  • RUN 创建镜像时会运行的命令
  • ADD 添加需要的压缩文件, 创建时会自动解压, 如tomcat压缩包
  • WORKDIR 工作目录, 设置进入容器时所在的路径
  • VOLUME 挂载容器卷
  • EXPOSE 指定对外暴露的端口
  • CMD 指定容器启动时会运行的命令, 只有最后一个命令会生效, 且会被docker run后面的命令替代
  • ENTRYPOINT 指定容器启动时会运行的命令, 只有最后一个命令会生效, 但不会被docker run后面的命令替代, 而是会拼接上后面的命令
  • ONBUILD 一个触发器, 当该dockerfile构建的镜像A被其他dockerfile构建的镜像B继承时, 那么在构建B的过程中, 首先会执行这个ONBUILD命令, 且只会对子镜像生效, 对孙子镜像不会生效
  • COPY 类似ADD命令, 将文件拷贝到镜像中
  • ENV 构建镜像时设置环境变量

简单测试

Docker Hub中大部分镜像都是继承了 scratch 这个基础镜像 FROM scratch然后配置需要的软件和配置来进行构建

1.编写dockerfile创建自己的centos

  • 官方的centos中缺少一些常用命令, 如 vim/ifconfig等, 我们加上这些指令
  • 官方的centos的工作目录为根目录/, 我们改成/usr/local
FROM centos
MAINTAINER alex<g1242556827@163.com>

RUN yum -y install vim
RUN yum -y install net-tools

ENV MYPATH /usr/local
WORKDIR $MYPATH

VOLUME /home/test

EXPOSE 80

CMD echo "-----success-----"
CMD echo $MYPATH
CMD /bin/bash

2.使用dockerfile构建镜像

# docker build -f dockerfile路径 -t 镜像名:[tag] .
docker build -f dockerfile02 -t alex/centos .
# docker history 镜像名 查看镜像历史记录
docker history alex/centos

技术图片

3.运行镜像创建容器

docker run -it alex/centos

可以看到进入容器终端端后的当前路径为dockerfile中设置的工作目录/usr/local

ifconfig命令也可以使用

技术图片

CMD与ENTRYPOINT的异同

先说结论:

相同点:

  1. 两者都是在容器运行时会执行的命令
  2. 执行时两者优先级是等价的, 只有最后一条CMD命令或者最后一条ENTRYPOIN命令会被执行, 即:
    • 若只有两条CMD命令, 则最后一条CMD命令会被执行
    • 若只有两条ENTRYPOINT命令, 则最后一条ENTRYPOINT命令会被执行
    • 若有一条CMD命令, 有一条ENTRYPOINT命令, 则最后一条ENTRYPOINT命令会被执行, 反之亦然

不同点:

当在执行docker run 镜像名 额外命令时, 在后面添加了额外的命令, 那么:

  • 对于CMD来说, 这条额外命令会替换掉CMD的命令, 也就是说不会执行CMD命令了, 只会执行run 后额外的命令

  • 对于ENTRYPOINT来说, 这条额外的命令会追加到ENTRYPOINT后面, 最后执行的是两者拼接后的命令

测试结论

  • 测试相同点:

两条CMD命令

# 编写dockerfile test01
FROM centos
CMD echo "11111111111"
CMD echo "22222222222"

# 构建镜像
docker build -f test01 -t test01 .

# 运行镜像
(root@Aliyun-Alex:/home/test)# docker run test01
22222222222

# 发现只执行了最后一个命令

两条ENTRYPOINT命令

# 编写dockerfile test02
FROM centos
ENTRYPOINT echo "11111111111"
ENTRYPOINT echo "22222222222"

# 构建镜像
docker build -f test02 -t test02 .

# 运行镜像
(root@Aliyun-Alex:/home/test)# docker run test02
22222222222

# 发现也只执行了最后一个命令

一条CMD一条ENTRYPOINT命令

# 编写dockerfile test03
FROM centos
CMD echo "11111111111"
ENTRYPOINT echo "22222222222"

# 构建镜像
docker build -f test03 -t test03 .

# 运行镜像
(root@Aliyun-Alex:/home/test)# docker run test03
22222222222

# 发现也只执行了最后一个命令
  • 测试不同点

CMD会被替换

# 编写dockerfile test04
FROM centos             
CMD ["ls", "-a"]

# 构建镜像
docker build -f test04 -t test04 .

# 运行镜像, 后面附加命令 echo "aa"
(root@Aliyun-Alex:/home/test)# docker run test04 echo "aa"
aa

# 发现CMD的命令并没有执行, 而只执行了run后面的命令 echo "aa" 
# 运行镜像, 后面附加命令 -l
(root@Aliyun-Alex:/home/test)# docker run test04 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: "-l": executable file not found in $PATH": unknown.

# 发现CMD的命令并没有执行, 而只执行了run后面的命令 -l, 而 -l不是有效的命令

ENTRYPOINT会拼接命令

# 编写dockerfile test05
FROM centos             
ENTRYPOINT ["ls", "-a"]

# 构建镜像
docker build -f test05 -t test05 .

# 运行镜像, 后面附加命令 -l
(root@Aliyun-Alex:/home/test)# docker run test05 -l
total 0
drwxr-xr-x   1 root root   6 Jul 29 04:03 .
drwxr-xr-x   1 root root   6 Jul 29 04:03 ..
-rwxr-xr-x   1 root root   0 Jul 29 04:03 .dockerenv
lrwxrwxrwx   1 root root   7 May 11  2019 bin -> usr/bin
drwxr-xr-x   5 root root 340 Jul 29 04:03 dev
drwxr-xr-x   1 root root  66 Jul 29 04:03 etc
drwxr-xr-x   2 root root   6 May 11  2019 home
lrwxrwxrwx   1 root root   7 May 11  2019 lib -> usr/lib
lrwxrwxrwx   1 root root   9 May 11  2019 lib64 -> usr/lib64
drwx------   2 root root   6 Jun 11 02:35 lost+found
drwxr-xr-x   2 root root   6 May 11  2019 media
drwxr-xr-x   2 root root   6 May 11  2019 mnt
drwxr-xr-x   2 root root   6 May 11  2019 opt
dr-xr-xr-x 135 root root   0 Jul 29 04:03 proc
dr-xr-x---   2 root root 162 Jun 11 02:35 root
drwxr-xr-x  11 root root 163 Jun 11 02:35 run
lrwxrwxrwx   1 root root   8 May 11  2019 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 May 11  2019 srv
dr-xr-xr-x  13 root root   0 Jul 29 04:03 sys
drwxrwxrwt   7 root root 145 Jun 11 02:35 tmp
drwxr-xr-x  12 root root 144 Jun 11 02:35 usr
drwxr-xr-x  20 root root 262 Jun 11 02:35 var

# 发现没有报错, -l被拼接到了ENTRYPOINT的命令后面, 最终执行的是 ls -a -l

实战: Dockerfile制作tomcat镜像

1.准备tomcat和jdk压缩包

技术图片

  • apache-tomcat-9.0.37.tar.gz
  • jdk-8u261-linux-x64.tar.gz

2.编写dockerfile

推荐把dockerfile命令为Dockerfile(官方命名), 这样在build时可以不用写-f参数

# 基础镜像
FROM centos
# 作者信息
MAINTAINER alex<g1242556827@163.com>

# 复制readme文件
COPY readme.txt /usr/local/readme.txt
# 添加需要的压缩文件
ADD apache-tomcat-9.0.37.tar.gz /usr/local
ADD jdk-8u261-linux-x64.tar.gz /usr/local

# 安装一些命令
RUN yum -y install vim
RUN yum -y install net-tools

# 设置工作目录
ENV MYPATH /usr/local
WORKDIR $MYPATH

# 配置java环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar

# 配置tomcat环境变量
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.37
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.37

# 配置PATH环境变量
ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin

# 暴露端口
EXPOSE 8080

# 运行容器时运行的命令
CMD /usr/local/apache-tomcat-9.0.37/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.37/bin/logs/catalina.out

3.运行镜像创建容器

# 运行容器
docker run -d -p 8000:8080 --name mytomcat01 -v /home/alex/docker/test/mytomcat/webapps/test:/usr/local/apache-tomcat-9.0.37/webapps/test -v /home/alex/docker/test/mytomcat/logs:/usr/local/apache-tomcat-9.0.37/logs mytomcat

# 进入容器终端, 可以看到当前目录为/usr/local, 解压的tomcat和jdk都在这里
(root@Aliyun-Alex:/home/alex)# docker exec -it mytomcat01 bash
[root@b5f127b76459 local]# ls
aegis                 etc      jdk1.8.0_261  libexec     share
apache-tomcat-9.0.37  games    lib           readme.txt  src
bin                   include  lib64         sbin

# 进入tomcat的webapps目录, 可以看到默认的一些文件
[root@b5f127b76459 apache-tomcat-9.0.37]# cd webapps/
[root@b5f127b76459 webapps]# ls
ROOT  docs  examples  host-manager  manager  test

这里我有一个疑惑, 就是在前面运行容器时, 如果挂载的路径是 -v 主机/webapps:容器/webapps即只到webapps层, 那么进入容器后发现webapps下面是空的, 并没有ROOT docs examples host-manager manager这些文件, 浏览器访问8000端口也是404找不到页面

技术图片

但是如果挂载到webapps/test这一层, 就有了这些文件, 8000端口也能正常访问到tomcat网页, 对tomcat不是很熟, 不知道是不是因为webapps下面没有项目的原因.

技术图片

4.发布简单项目(由于做了卷挂载, 可以直接在本地编写项目)

创建web.xml文件

(root@Aliyun-Alex:/home/alex/docker/test/mytomcat)# cd test/
(root@Aliyun-Alex:/home/alex/docker/test/mytomcat/test)# mkdir WEB-INF
(root@Aliyun-Alex:/home/alex/docker/test/mytomcat/test)# cd WEB-INF/
(root@Aliyun-Alex:/home/alex/docker/test/mytomcat/test/WEB-INF)# nvim web.xml

# web.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>

创建index.jsp文件

(root@Aliyun-Alex:/home/alex/docker/test/mytomcat/test/WEB-INF)# cd ..
(root@Aliyun-Alex:/home/alex/docker/test/mytomcat/test)# nvim index.jsp

# index.jsp文件如下:
<html>
<head><title>Hello World</title></head>
    <body>
        Hello World!<br/>
        <%
        System.out.println("---------my test web logs----------");
        %>
    </body>
</html>

测试

访问http://47.102.114.90:8000/test/查看结果

技术图片

查看日志信息

cd /home/alex/docker/test/mytomcat/logs
vim catalina.out

可以看到访问后打印出来的信息

技术图片

项目部署成功!

以上是关于Docker-基础004-DockerFile的编写的主要内容,如果未能解决你的问题,请参考以下文章

全面分析 Spring 的编程式事务管理及声明式事务管理

全面分析 Spring 的编程式事务管理及声明式事务管理

Android音频开发:音频数据的编解码

全面分析 Spring 的编程式事务管理及声明式事务管理

shell编程基础必知

如何确定文本文件的编码表