面试官:你说你精通 Docker,那你来详细说说 Dockerfile 吧(下)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 面试官:你说你精通 Docker,那你来详细说说 Dockerfile 吧(下)

3、ENTRYPOINT


3.1、执行时机


容器创建时执行,而不是镜像构建时执行。


3.2、解释说明


在容器启动的时候执行此命令,且Dockerfile中只有最后一个ENTRYPOINT会被执行,推荐用EXEC格式。


3.3、举例


ENTRYPOINT ["ps","-ef"]


4、代码演示


4.1、执行时机演示


FROM centos
RUN ["echo", "image building!!!"]
CMD ["echo", "container starting..."]


docker build -t chentongwei.com/test-docker-run .


构建镜像的过程中发现我们RUN的image building!!! 输出了,所以RUN命令是在镜像构建时执行。而并没有container starting…的输出。


image.png


docker run chentongwei.com/test-docker-run


结果:container starting...,足以发现CMD命令是在容器启动的时候执行。


4.2、CMD和ENTRYPOINT演示


ENTRYPOINT和CMD可以共用,若共用则他会一起合并执行。如下Demo:


FROM centos
RUN ["echo", "image building!!!"]
ENTRYPOINT ["ps"]
CMD ["-ef"]


# 构建镜像
docker build -t chentongwei.com/docker-run .
# 启动容器
docker run chentongwei.com/docker-run


输出结果:


UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:02 ?        00:00:00 ps -ef


他给我们合并执行了:ps -ef,这么做的好处在于如果容器启动的时候添加额外指令,CMD会失效,可以理解成我们可以动态的改变CMD内容而不需要重新构建镜像等操作。


比如


docker run chentongwei.com/docker-run -aux


输出结果:


USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.0  0.0  46340  1692 ?        Rs   13:02   0:00 ps -aux


结果直接变成了 ps -aux,CMD命令不执行了。但是ENTRYPOINT一定执行,这也是CMD和ENTRYPOINT的区别之一。


四、实战


1、部署应用到tomcat


1.1、准备工作


# 在服务器上创建test-dockerfile文件夹
mkdir test-dockerfile
# 进入test-dockerfile目录
cd test-dockerfile
# 创建需要部署到tomcat的应用
mkdir helloworld
# 在helloworld目录下创建index.html写上hello dockerfile
cd helloworld/
vim index.html


效果如下图:


image.png


1.2、Dockerfile


# 在test-dockerfile目录下创建Dockerfile文件,注意大写D,没有后缀。
touch Dockerfile



在Dockerfile里写上如下内容


FROM tomcat:latest
MAINTAINER baidu.com
WORKDIR /usr/local/tomcat/webapps
ADD helloworld ./helloworld


逐行解释:


第一行:因为我们要部署应用到tomcat上,所以需要从远程仓库里拉取tomcat作为基础镜像。


第二行:描述性东西,还可以LABEL XXX XXX 添加更详细的注释信息。


第三行:cd到/usr/local/tomcat/webapps,发现没有这个目录,我就自动创建出来,然后在cd进去


为什么是这个目录呢?因为当我们制作完镜像把容器run起来的时候tomcat的位置是在/usr/local/tomcat,加个/webapps是因为我们要将我们的应用程序扔到webapps下才能跑。如果懵,继续往下看就懂了。


第四行:tomcat有了,tomcat的webapps我们也cd进去了,那还等啥?直接把我们的应用程序拷贝到webapps下就欧了。所以ADD命令宿主机上的helloworld文件夹下的内容拷贝到当前目录(webapps,上一步刚cd进来的)的helloworld文件夹下。


1.3、制作镜像


docker build -t baidu.com/test-helloworld:1.0.0 .


. 代表当前目录。这些命令不懂的看上面的【三、Dockerfile命令】,都是上面提到的。没新知识。


命令执行后的结果


[root@izm5e3qug7oee4q1y4opibz test-dockerfile]# docker build -t baidu.com/test-helloworld:1.0.0 .
Sending build context to Docker daemon  3.584kB
Step 1/4 : FROM tomcat:latest
 ---> 1b6b1fe7261e
Step 2/4 : MAINTAINER baidu.com
 ---> Running in ac58299b3f38
Removing intermediate container ac58299b3f38
 ---> 5d0da6398f7e
Step 3/4 : WORKDIR /usr/local/tomcat/webapps
 ---> Running in 1c21c39fc58e
Removing intermediate container 1c21c39fc58e
 ---> 9bf9672cd60e
Step 4/4 : ADD helloworld ./helloworld
 ---> 6d67c0d48c20
Successfully built 6d67c0d48c20
Successfully tagged baidu.com/test-helloworld:1.0.0


好像分了1/2/3/4步呢?这是啥意思。这是镜像分层的概念,下面说。现在只看到SuccessFully就哦了。


再查看下我们的镜像真实存在了吗?


docker images



完美


image.png


1.4、启动容器


docker run -d -p 8100:8080  baidu.com/test-helloworld:1.0.0
# 然后docker ps查看容器是否存在
docker ps


浏览器访问:http://服务器ip:8100/helloworld/index.html,很完美。这个helloworld就是我们Dockerfile里自己的应用程序。


image.png


1.5、进入容器


docker exec -it 730f9e144f68 /bin/bash


image.png


疑问1:怎么进入容器后直接在webapps目录下,这就是因为我们这个镜像是用Dockerfile制作的,Dockerfile上面我们自己WORKDIR到webapps目录下的呀。


答疑1:我们ls下可以看到Dockerfile里的helloworld应用就在这里


root@730f9e144f68:/usr/local/tomcat/webapps# ls
helloworld


答疑2:Dockerfile里WORKDIR /usr/local/tomcat/webapps了,为啥是这个目录也很清晰了。容器里的tomcat就在这


root@730f9e144f68:/usr/local/tomcat/webapps# pwd
usr/local/tomcat/webapps


2、从0制作Redis镜像


一般没人制作Redis镜像,Redis有官方的docker镜像,docker pull一下就行。这里是为了演示上面的命令,从0到1的过程。


2.1、准备工作


1.去官网下载Redis的源码包,因为我们演示的是Redis从无到有的过程。



2.准备Redis的配置文件redis-6379.conf


2.2、Dockerfile


# 将Redis运行在centos上
FROM centos
# 安装Redis所需要的基础库
RUN ["yum", "install", "-y", "gcc", "gcc-c++", "net-tools", "make"]
# 将Redis目录放到/usr/local
WORKDIR /usr/local
# 别忘了ADD命令自带解压缩的功能
ADD redis-4.0.14.tag.gz .
WORKDIR /usr/local/redis-4.0.14/src
# 编译安装Redis
RUN make && make install
WORKDIR /usr/local/redis-4.0.14
# 将配置文件仍到Redis根目录
ADD redis-6379.conf .
# 声明容器中Redis的端口为6379
EXPOSE 6379
# 启动Redis  redis-server redis-6379.conf
CMD ["redis-server", "redis-6379.conf"]


2.3、制作镜像&&启动容器


# 制作镜像
docker build -t chentongwei.com/docker-redis .
# 查看
docker images
# 启动容器
docker run -p 6379:6379 chentongwei.com/docker-redis


上面三套小连招执行完后redis就起来了,可以redis-cli去链接了。也可以docker exec进入容器去查看。


3、用docker部署jar包


FROM openjdk:8-jdk-alpine:latest
ADD target/helloworld-0.0.1-SNAPSHOT.jar /helloworld.jar
ENTRYPOINT ["java","-jar","/helloworld.jar"]


然后build成镜像再run启动容器,很简单粗暴。


五、补充:镜像分层的概念


1、Dockerfile


FROM tomcat:latest
MAINTAINER baidu.com
WORKDIR /usr/local/tomcat/webapps
ADD helloworld ./helloworld


2、镜像分层


就拿上面的Dockerfile来build的话,执行过程是如下的:


Sending build context to Docker daemon  3.584kB
Step 1/4 : FROM tomcat:latest
 ---> 1b6b1fe7261e
Step 2/4 : MAINTAINER baidu.com
 ---> Running in ac58299b3f38
Removing intermediate container ac58299b3f38
 ---> 5d0da6398f7e
Step 3/4 : WORKDIR /usr/local/tomcat/webapps
 ---> Running in 1c21c39fc58e
Removing intermediate container 1c21c39fc58e
 ---> 9bf9672cd60e
Step 4/4 : ADD helloworld ./helloworld
 ---> 6d67c0d48c20
Successfully built 6d67c0d48c20
Successfully tagged baidu.com/test-helloworld:1.0.0


会发现我们Dockerfile文件内容一共四行,执行过程也是Step 1/2/3/4四步,这就知道了Dockerfile内容的行数决定了Step的步骤数。


那么每一步都代表啥呢?


其实每一步都会为我们创建一个临时容器,这样做的好处是如果下次再构建这个Dockerfile的时候,直接从cache里读出已有的容器,不重复创建容器,这样大大节省了构建时间,也不会浪费资源重复创建容器。比如如下:


FROM tomcat:latest
MAINTAINER baidu.com
WORKDIR /usr/local/tomcat/webapps
ADD helloworld ./helloworld
ADD helloworld ./helloworld2


啥也没动,就是多部署一份helloworld且在容器内部改名为helloworld2,接下来看执行过程


Step 1/5 : FROM tomcat:latest
 ---> 1b6b1fe7261e
Step 2/5 : MAINTAINER baidu.com
 ---> Using cache
 ---> 5d0da6398f7e
Step 3/5 : WORKDIR /usr/local/tomcat/webapps
 ---> Using cache
 ---> 9bf9672cd60e
Step 4/5 : ADD helloworld ./helloworld
 ---> Using cache
 ---> 6d67c0d48c20
Step 5/5 : ADD helloworld ./helloworld2
 ---> 4e5ffc24522f
Successfully built 4e5ffc24522f
Successfully tagged baidu.com/test-helloworld:1.0.1


首先可以发现如下:


1.Step变成了5步。


2.前四步骤用了缓存Using Cache,并没有重复创建容器。Step 1 没有Using Cache是因为它是从本地仓库直接拉取了tomcat:latest当作基础镜像,run的时候会创建容器。


3.第五步重新创建了临时容器。


END



相关文章
|
11月前
|
存储 关系型数据库 MySQL
美团面试:MySQL为什么 不用 Docker部署?
45岁老架构师尼恩在读者交流群中分享了关于“MySQL为什么不推荐使用Docker部署”的深入分析。通过系统化的梳理,尼恩帮助读者理解为何大型MySQL数据库通常不使用Docker部署,主要涉及性能、管理复杂度和稳定性等方面的考量。文章详细解释了有状态容器的特点、Docker的资源隔离问题以及磁盘IO性能损耗,并提供了小型MySQL使用Docker的最佳实践。此外,尼恩还介绍了Share Nothing架构的优势及其应用场景,强调了配置管理和数据持久化的挑战。最后,尼恩建议读者参考《尼恩Java面试宝典PDF》以提升技术能力,更好地应对面试中的难题。
|
9月前
|
Kubernetes Docker 容器
Kubernetes与Docker参数对照:理解Pod中的command、args与Dockerfile中的CMD、ENTRYPOINT。
需要明确的是,理解这些都需要对Docker和Kubernetes有一定深度的理解,才能把握二者的区别和联系。虽然它们都是容器技术的二个重要组成部分,但各有其特性和适用场景,理解它们的本质和工作方式,才能更好的使用这些工具,将各自的优点整合到生产环境中,实现软件的快速开发和部署。
351 25
|
12月前
|
NoSQL Java Linux
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
522 76
|
Java 应用服务中间件 Linux
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
本文主要讲解了Docker的安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库以及Docker容器虚拟化与传统虚拟机比较。
13680 38
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
|
数据库 Docker 容器
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。Dockerfile定义了构建镜像所需的所有指令,包括基础镜像选择、软件安装、文件复制等,极大提高了开发和部署的灵活性与一致性。掌握Dockerfile的编写,对于提升软件开发效率和环境管理具有重要意义。
170 9
|
应用服务中间件 nginx Docker
Docker镜像-基于DockerFile制作编译版nginx镜像
这篇文章介绍了如何基于Dockerfile制作一个编译版的nginx镜像,并提供了详细的步骤和命令。
1299 17
Docker镜像-基于DockerFile制作编译版nginx镜像
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
648 4
|
Docker 容器
docker中使用Dockerfile自动创建数据卷
【10月更文挑战第12天】
275 5
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
368 4
|
应用服务中间件 Linux nginx
Docker镜像-基于DockerFile制作yum版nginx镜像
本文介绍了如何使用Dockerfile制作一个基于CentOS 7.6.1810的yum版nginx镜像,并提供了详细的步骤和命令。
365 20