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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容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



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
17天前
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
43 3
|
1月前
|
Docker 容器
docker中使用Dockerfile自动创建数据卷
【10月更文挑战第12天】
19 5
|
1月前
|
消息中间件 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
42 4
|
2月前
|
应用服务中间件 nginx Docker
Docker镜像-基于DockerFile制作编译版nginx镜像
这篇文章介绍了如何基于Dockerfile制作一个编译版的nginx镜像,并提供了详细的步骤和命令。
439 17
Docker镜像-基于DockerFile制作编译版nginx镜像
|
2月前
|
应用服务中间件 Linux nginx
Docker镜像-基于DockerFile制作yum版nginx镜像
本文介绍了如何使用Dockerfile制作一个基于CentOS 7.6.1810的yum版nginx镜像,并提供了详细的步骤和命令。
137 20
|
2月前
|
Docker 容器
7-13|docker build -t image-name:tag path/to/Dockerfile 这个命令具体什么意思
7-13|docker build -t image-name:tag path/to/Dockerfile 这个命令具体什么意思
|
3月前
|
Docker 容器
在Docker中,Dockerfile有哪些常见指令?
在Docker中,Dockerfile有哪些常见指令?
|
3月前
|
缓存 Docker 容器
在Docker中,docker commit生成的镜像和dockerfile生成镜像有什么区别?
在Docker中,docker commit生成的镜像和dockerfile生成镜像有什么区别?
|
3月前
|
缓存 开发者 Docker
Dockerfile是Docker容器化过程中的核心组件,它允许开发者以一种可重复、可移植的方式自动化地构建Docker镜像
【8月更文挑战第19天】Dockerfile是构建Docker镜像的脚本文件,含一系列指令定义镜像构建步骤。每条大写指令后跟至少一个参数,按序执行,每执行一条指令即生成新的镜像层。常用指令包括:FROM指定基础镜像;RUN执行构建命令;EXPOSE开放端口;CMD指定容器启动行为等。优化策略涉及减少镜像层数、选择轻量基础镜像、利用缓存及清理冗余文件。示例:基于Python应用的Dockerfile包括设置工作目录、复制文件、安装依赖等步骤。掌握Dockerfile有助于高效自动化构建镜像,加速应用部署。
34 1
|
3月前
|
NoSQL Linux MongoDB
Docker 解析:使用 Dockerfile 自动构建镜像
Docker 解析:使用 Dockerfile 自动构建镜像
135 0