前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dockerfile专题 | 如何构造自己的docker镜像

Dockerfile专题 | 如何构造自己的docker镜像

原创
作者头像
叫我阿柒啊
发布2024-08-30 15:59:22
5340
发布2024-08-30 15:59:22
举报
文章被收录于专栏:入门到放弃之路

前言

说起docker,大家都知道是容器。我们从仓库中docker pull拉取镜像(image)到本地,然后docker run指定镜像来启动一个容器(container)。那么,这个容器就开始守护内部的程序。

但是很多时候,我们需要在docker中部署自己的程序,或者因为pull的镜像太大,我们需要基于一个小的镜像来重构,这就需要我们要自己构建docker,而docker的构建步骤是基于Dockerfile来实现的。

Dockerfile

在学习Dockerfile之前,首先弄明白镜像。容器就类似于“虚拟机”,而虚拟机就需要操作系统,这个操作系统就是镜像(image)。

image

通过docker images就可以查看宿主机上已存在的所有镜像。

在上面的镜像中,使用比较多的就是centos,但是centos里面已经预装了很多软件,所以大小为231MB。像alpine、busybox的镜像就比较小,很多命令都需要自己安装,但是实际中也不会过多地去容器中执行很多的命令。

指令

首先文件名必须是Dockerfile,第一行必须使用FROM指令来引入镜像,最后一行是通过CMD或者ENTRYPOINT指令来指定容器中要运行的命令。

构建镜像是由一个基础镜像开始,通过经过各种指令来构造成成我们自己的镜像

  1. FROM:第一行必须是 FORM centos,表示从centos镜像构建容器
  2. ENV key value:设置环境变量
  3. RUN command:在之前的镜像基础上执行指令,并提交为新的镜像
  4. EXPOSE 80:开放80端口,run时需要用 -p来指定映射端口,不指定默认分配
  5. VOLUME /data:声明容器中/data为匿名卷。-v可以将这个匿名卷绑定到宿主机,不指定会自动绑定到/var/lib/docker/volumes
  6. ADD src dest:文件必须和Dockerfile同一目录,除了复制本地文件到容器中外,还有解压缩文件的功能
  7. COPY src dest:文件必须和Dockerfile同一目录,将src目录/文件复制到容器的dest目录
  8. CMD:容器启动时执行的命令
  9. ENTRYPOINT:和CMD一样,指定容器启动执行的命令

上面就是在Dockerfile中常用的命令。看到上面可能会有疑问,CMD 和 ENTRYPOINT不是一样的命令吗?

CMD和ENTRYPOINT

CMD 指令用于为镜像指定一个默认的命令和参数,但该命令可以在运行容器时被指定的命令覆盖。我们还记得最初学习docker时,运行容器时使用docker run,在最后面会加一个/bin/bash,这个/bin/bash就是一个指令,它会覆盖CMD。

代码语言:bash
复制
docker run my-image echo "Hello, World!"

同样,这里,echo "Hello, World!" 将覆盖 Dockerfile 中的 CMD 指令。

而ENTRYPOINT指令用于配置一个容器启动时将始终执行的主命令,就不会有这种被覆盖的问题,它会默认把docker run指定的指令当做自己的参数,同样

代码语言:bash
复制
docker run my-image "Hello, World!"

这里 "Hello, World!" 将作为参数传递给 ENTRYPOINT 中的命令,而不会替换掉它。有时CMD和ENTRYPOINT也会搭配使用,ENTRYPOINT 用于指定固定的命令,而 CMD 用于提供默认参数。这样,可以在运行容器时添加或替换 CMD 的默认参数。

例如我使用下面的Dockerfile构造镜像之后:

代码语言:bash
复制
FROM centos
ENTRYPOINT ["echo"]
CMD ["Hello, World!"]

运行容器时不指定命令,就会输出"Hello, World!",如果我指定命令:

代码语言:bash
复制
docker run my-image "Hello, Docker!"

那么, "Hello, Docker!"就会覆盖CMD指定的 "Hello, World!" ,最后输出 "Hello, Docker!"

Tomcat的Dockerfile

这里我就基于centos镜像,编写Dockerfile,来构造一个Tomcat的镜像。在构造一个镜像之前,我们还需要考虑这个镜像依赖的环境变量、下载的软件包以及开放的命令等等。

如果我们在服务器上搭建一个Tomcat,我们需要下载tomcat,然后配置jdk、开放8080端口,然后在tomcat的bin目录下,执行startup.sh,这样一个tomcat服务就启动成功了。我们要做的就是,把这些操作转换到Dockerfile中。

Dockerfile

首先我下载了tomcat的安装包,在宿主机的/data目录下,同时宿主机的jdk放在了/usr/local下。如何把tomcat和jdk放到镜像中,这时候有的同学就要抢答了:“COPY!”

其实比较好的方案是使用VOLUMN指令,将宿主机的目录挂载到容器中,这样每个容器使用的就是宿主机上的文件,而减少了对磁盘存储的占用。

代码语言:bash
复制
FROM centos
VOLUME /usr/local/jdk
VOLUME /usr/local/tomcat
ENV JAVA_HOME /usr/local/jdk
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
EXPOSE 8080
CMD catalina.sh run

在Dockerfile中,我在/usr/local下一共声明了两个卷:jdk和tomcat,然后在后面的ENV指令中,将这两个卷作为jdk和tomcat的环境变量目录,配置在了PATH中。

然后在CMD中执行catalina.sh run的指令,这里不能使用startup.sh,因为docker容器是为了守护一个进程/命令而存在的,所以必须必须使用前台启动方式

构造镜像

然后构造开始构造镜像:

代码语言:bash
复制
docker build -t="tomcat-aqi" .

构造成功之后,通过docker images可以查看到我们的镜像。

运行容器

根据dockerfile中配置,在docker run命令中,我们要将宿主机中的jdk和tomcat目录,挂载到容器的卷中,然后容器8080端口映射为宿主机的9092。

代码语言:bash
复制
docker run -d --name tomcat-qi -p 9092:8080 \
-v /data/apache-tomcat-8.0.11:/usr/local/tomcat \
-v /usr/local/jdk1.8.0_201:/usr/local/jdk  \
-it tomcat-aqi

在容器运行成功之后,通过docker ps可以查看到进程。

在浏览器中通过服务器的9092的端口,就访问到了容器中的tomcat。

在容器信息中,我们可以看到挂载信息,宿主机上的JDK和tomcat目录已经被挂载到了容器卷中。

也可以看到容器的ENV环境变量和CMD信息。

镜像层

镜像层(Image Layers)是 Docker 镜像的一个重要概念。每个 Docker 镜像实际上是由多层文件系统(Union File System)组成的,每一层都是只读的,称为镜像层。这些层次是镜像的基础,每个层次代表镜像构建过程中的一个步骤或一个命令。

每一层都是一个增量修改,相当于给上一层加上了新的变化。这样,Docker 镜像的每一层都是不可变的。

Docker 通过层来实现缓存机制。例如,如果你修改了 Dockerfile 中的某一行,Docker 只会从该行开始重新构建层,而之前的层都被缓存并且重用。这大大提高了构建速度

减少镜像层数和每层的大小可以优化镜像的体积和传输速度。过多的层数会导致冗余数据的增多和构建时间的增加。我们可以通过将多个 RUN 指令合并为一个,来减少镜像层。

我们在上面的Dockerfile中加入三行RUN指令:

代码语言:bash
复制
RUN ps
RUN echo 1
RUN date

再将三条RUN指令合并:

代码语言:bash
复制
RUN ps && echo 1 && date

分别使用两个Dockerfile构造镜像,从构造过程日志可以看出,指令合并前镜像层为8,合并后为6。

结语

最后讲讲为什么使用centos,而不是alpine镜像。原因就是alpine需要下载相应版本的OpenJDK,不支持我这个oracle的JDK,所以我还是走了捷径,直接使用了centos。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Dockerfile
    • image
      • 指令
        • CMD和ENTRYPOINT
        • Tomcat的Dockerfile
          • Dockerfile
            • 构造镜像
              • 运行容器
              • 镜像层
              • 结语
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档