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的异同
先说结论:
相同点:
- 两者都是在容器运行时会执行的命令
- 执行时两者优先级是等价的, 只有最后一条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的编写的主要内容,如果未能解决你的问题,请参考以下文章