Docker | 第五章:构建自定义镜像

前言

上一章节,主要是介绍了下Dockerfile的一些常用命令的说明。我们知道,利用Dockerfile可以构建一个新的镜像,比如运行Java环境,就需要一个JDK环境的镜像,但直接使用公共的镜像时,一般上大小都比较大。所以本章节就主要结合Dockerfile文件及commit方式,构建属于自己的镜像,同时对镜像进行压缩和优化,同时也是对Dockerfile知识的一个实践。

  • 利用Dockerfile构建自定义镜像

    • 选定基础镜像
    • 准备JRE版本
    • 编写Dockerfile
    • 实践:运行SpringBoot的jar包
  • 利用commit命令构建自定义镜像
  • 镜像文件压缩技巧
    • 选择一个精简的基础镜像
    • 串联RUN命令
    • 删除多余文件及命令安装包等
  • 总结
  • 最后
  • 老生常谈

利用Dockerfile构建自定义镜像

作为一个java后端开发,这里就直接以构建一个Oracle官方jre环境来示例。

选定基础镜像

由于在Linux中,JVM主要是调用系统的C语言库,Oracle的官方JRE,使用的是libc,也就是glibc,这意味着你要运行任何Java程序,都需要先装好glibc。所以我们直接去https://hub.docker.com找一个基于glibc的基础镜像(当然了,大家也可直接选定比如CensOS这些Linux的发行版本了)。

我们之类直接选择默认排在第一个的alpine-glibc作为我们的基础镜像,比较这个大小也才12M左右呀!

题外话:大家作为实验性质时,为了获取更小的基础镜像,可以选择alpine这个基础镜像,比较这个只有5M大小,够精简了!

准备JRE版本

这里我们直接去Oracle官网选择jre版本,这里选择的是jre-8u181-linux-x64版本(由于对linux命令不是很熟悉,为了不必要的时间浪费,这里直接下载了镜像了,熟悉的各位可以直接使用wget进行下载的)。

编写Dockerfile

 # 基础镜像
 FROM frolvlad/alpine-glibc
 LABEL MAINTAINER oKong <[email protected]>

 # 将JRE添加至镜像中,add 命令在源文件为压缩文件时,会自动解压的
 ADD jre-8u181-linux-x64.tar.gz /opt/docker/java/jre8

# 设置JAVA环境变量
# 这里需要注意下,解压后有个目录的,为jre1.8.0_181,一开始没注意,启动时报了:exec: "java": executable file not found in $PATH: unknown 后才发现。
ENV JAVA_HOME /opt/docker/java/jre8/jre1.8.0_181
ENV CLASSPATH=$JAVA_HOME/bin
ENV PATH=.:$JAVA_HOME/bin:$PATH

# 这里无实际意义,只是在容器启动时,输出jre版本信息,验证是否安装成功
CMD ["java","-version"]

利用build命令,构建镜像,同时指定tag

  docker build -t lqdev.cn/jre8:0.1 .

注意:后面有个.的。

Sending build context to Docker daemon  81.19MB
Step 1/7 : FROM frolvlad/alpine-glibc
 ---> d3bc626306a1
Step 2/7 : LABEL MAINTAINER oKong <[email protected]>
 ---> Running in e788d29cd1e1
Removing intermediate container e788d29cd1e1
 ---> 5d95db4ae169
Step 3/7 : ADD jre-8u181-linux-x64.tar.gz /opt/docker/java/jre8
 ---> 0f4bb83df722
Step 4/7 : ENV JAVA_HOME /opt/docker/java/jre8/jre1.8.0_181
 ---> Running in 57a1e1ef00ed
Removing intermediate container 57a1e1ef00ed
 ---> 6f2b543a91b7
Step 5/7 : ENV PATH ${PATH}:${JAVA_HOME}/bin
 ---> Running in 2d75c88f97fb
Removing intermediate container 2d75c88f97fb
 ---> 92a7a0f9926c
Step 6/7 : WORKDIR /opt/docker/java/jre8/jre1.8.0_181
 ---> Running in 7b9a69efc980
Removing intermediate container 7b9a69efc980
 ---> 158c08c995c3
Step 7/7 : CMD ["java","-version"]
 ---> Running in 9ab517f8292a
Removing intermediate container 9ab517f8292a
 ---> 9c8606ac315a
Successfully built 9c8606ac315a
Successfully tagged lqdev.cn/jre8:0.1

然后查看下镜像列表,

  docker images

说明已经构建成功了,我们来运行下:

 docker run -it -d --name myfirstjre  lqdev.cn/jre8:0.1

查看下容器列表:

 docker ps -a

由于Dockerfile中使用CMD命令覆盖了原本的/bin/sh,容器已启动就停止了。所以我们看下日志,就知道是否jre安装成功。

docker logs -f c6873a97ff49

输出了版本信息了,说明已经安装成功了。

实践:运行SpringBoot的jar包

现在我们就可以基于这个jre镜像进行实际的jar包部署了。

Dockerfile文件方式:

# 基于我们自定义构建的镜像
FROM lqdev.cn/jre8:0.1

VOLUME /opt/tmp
# 这是jar 可自行选择,这里直接使用了原先讲解springboot十四章节:基于Docker部署时的jar包
ADD chapter-14-0.0.1-SNAPSHOT.jar app.jar

# -Djava.security.egd=file:/dev/./urandom 可解决tomcat可能启动慢的问题
# 具体可查看:https://www.cnblogs.com/mightyvincent/p/7685310.html
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

# 对外端口
EXPOSE 8080

然后构建新镜像,并运行,同时查看日志输出

  docker run -it -d --name springboot  lqdev.cn/springboot:0.1

日志控制台:

运行的容器列表:

说明我们已经成功了,jar也启动了。现在访问下部署的jar服务:

利用commit命令构建自定义镜像

第三章讲解Docker常用命令时,有说到,利用commit可从容器中构建一个新的镜像。所以这里简单讲解下利用此命令进行自动镜像的构建过程。

构建思路:我们启动一个基础镜像,同时运行,然后我们进入容器,下载所需要的jre版本,并配置其环境变量。之后退出容器进行保存操作。这里就不直接下载了,我们直接拷贝jre到容器里

启动基础镜像:

   docker run -it -d --name commitImages  frolvlad/alpine-glibc

拷贝jre到容器中。

docker cp /opt/docker/java/jre-8u181-linux-x64.tar.gz b0d354b9453a:/opt/docker/java/jre8

这里会提示,说目录不存在,可利用exec命令,进入容器创建目录下,这里就不演示了。

No such container:path: b0d354b9453a:/opt/docker/java

现在我们进入容器:

 docker exec -it b0d354b9453a /bin/sh

进入,/opt/docker/java/jre8目录,进行常规linux下的jre安装:

  cd /opt/docker/java/jre8
  # 解压
  tar -xzvf jre-8u181-linux-x64.tar.gz
  # 配置环境变量,vi /etc/profile 末尾加入
  export JAVA_HOME=/opt/docker/java/jre8/jre1.8.0_181
  export CLASSPATH=$JAVA_HOME/bin
  export PATH=.:$JAVA_HOME/bin:$PATH
  # 生效配置
  source /etc/profile
  # 验证是否成功
  java -version
  输出:
  java version "1.8.0_181"
  Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
  Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
  # 这里有个坑,生效配置后退出容器后又失效了,搜索了后,把环境变量放在### ~/.bashrc 或者在~/.bashrc里面加一句source /etc/profile 但是还是未生效。。。。我放弃了。。 直接写个sh脚本启动 时加入吧。。

  

然后我们退出容器,利用commit命令进行构建新镜像:

docker commit b0d354b9453a lqdev.cn/jre8:0.2

然后查看:

运行jar,验证下是否正常,这里直接在启动的时候拷贝jar到镜像。

docker run -it -d -p 1234:8080 -v /opt/docker/java:/opt/docker/java/app.jar --name springboot2 lqdev.cn/jre8:0.2

然后进入容器运行下java 命令

# 进入容器
docker exec -it 583d0f387555 /bin/sh
# 生效配置
source etc/profile
# 运行jar
nohup java  -Djava.security.egd=file:/dev/./urandom -jar /opt/docker/java/app.jar >log.txt &

退出后,访问宿主的1234端口服务,就能看见部署成功了:

其实比较好的做法是:创建一个sh脚本,脚本里设置了环境生效命令及java命令即可,大家可自行尝试下,这里就不演示了。

镜像文件压缩技巧

上一章节,我们利用Dockerfilecommit的方式生成镜像。现在我们看下,镜像文件大小:

两种方式,commit还多了80M多。这里我们本着精简的原则,对镜像大小进行优化下。

首先,镜像文件是按镜像层(Layers)进行叠加的。总的来说就是:每一条指令都会创建一个镜像层,继而会增加整体镜像的大小。

选择一个精简的基础镜像

一个基础镜像的大小直接决定了新镜像的大小,所以可以选择尽量小的精简的镜像。本文就使用了alpine-glibc作为基础镜像,大小12.8M。

串联RUN命令

多个RUN时,可通过 && 和 / 支持将命令串联在一起

# 举例
RUN yum -y install java-1.7.0-openjdk-devel && yum clean all

很多镜像大部分都是通过此方式进行RUN方式编写的。官网:https://hub.docker.com/里面的大部分镜像都是如下写法

删除多余文件及命令安装包等

比如jre包中就有很多的文档及说明文件是非必要的,这些就可以删除了。以下只是个参考,大家可以自行删减,可以在Dockerfile编写时,解压后,使用RUN命令进行操作也可以直接把压缩包里删除后在拷贝:

rm -rf COPYRIGHT LICENSE README release THIRDPARTYLICENSEREADME-JAVAFX.txtTHIRDPARTYLICENSEREADME.txt Welcome.html
#删除其他无用文件
rm -rf     lib/plugin.jar            lib/ext/jfxrt.jar            bin/javaws            lib/javaws.jar            lib/desktop            plugin            lib/deploy*            lib/*javafx*            lib/*jfx*            lib/amd64/libdecora_sse.so            lib/amd64/libprism_*.so            lib/amd64/libfxplugins.so            lib/amd64/libglass.so            lib/amd64/libgstreamer-lite.so            lib/amd64/libjavafx*.so            lib/amd64/libjfx*.so

对比下,确实少了很多了。

当然对于大小不关心的,也就无需理会了,毕竟现在存储空间都很大的,也就可能传输的时候慢点,哈哈~

参考资料

镜像优化的大家可看看以下几篇文章或者自行搜索下相关资料:

  1. https://blog.csdn.net/qq_36763896/article/details/53293088
  2. https://my.oschina.net/shyloveliyi/blog/1627020
  3. https://blog.csdn.net/chenyufeng1991/article/details/78766123

总结

本章节主要是介绍如何利用Dockerfile或者commit方式构建自定义镜像。通过这两种方式,我们就能根据自己的实际业务需要进行个性化改造、优化,最终构建一个通用镜像。在构建自己的镜像时,尽量还是选择自己熟悉的、稳定的基础环境镜像进行构建,毕竟出了问题找起来也熟门熟路点。通常,运维部门或者实施部门,制定的镜像属于资产,一般不会上送至Docker远程仓库的,有了镜像,我们就需要有个地方去存储。下一章节,就重点讲解下如何构建私有仓库,管理自己的镜像文件!

最后

若文中有错误或者遗漏之处,还望指出,共同进步!

老生常谈

  • 个人QQ:499452441
  • 微信公众号:lqdevOps

个人博客:http://blog.lqdev.cn

原文地址:https://www.cnblogs.com/okong/p/docker-five.html

时间: 2024-10-11 10:10:00

Docker | 第五章:构建自定义镜像的相关文章

五十四.自定义镜像及仓库、持久化存储 、 Docker网络架构

1. 制作自定义镜像(base基础镜像,搭建共性环境) 基于centos镜像使用commit创建新的镜像文件 基于centos镜像使用Dockerfile文件创建一个新的镜像文件 1.1 使用镜像启动容器 1)在该容器基础上修改yum源 docker_images]# docker run -it centos 345 /]# rm -rf /etc/yum.repos.d/* 345 /]# vi /etc/yum.repos.d/dvd.repo [dvd] name=dvd baseurl

Dockerfile详解,以及构建自定义镜像

Dockerfile使用 前面的操作我们一直下载下载官方已经构建好的镜像,直接下载后就可以run,如果我们想要在镜像中添加自己的应用,比如在tomcat中添加自己的app,构建一个自定义的镜像,那么我们应该怎么做,这个时候就用到了Dockerfile.Dockerfile是由一系列命令和参数构成的脚本,Docker可以根据这个脚本基于某个基础镜像创建一个新的定制化的镜像,大大提高了我们部署的效率,使用Dockfile最终的结果是帮助我们定制化自己的镜像. Dockerfile初体验 下面就基于t

commit构建自定义镜像

对容器的修改以及保存 启动并进入容器:docker run -it centos:7 /bin/bash 对容器做某些操作修改 构建镜像: docker commit  镜像id  mycentos:v1 docker commit -a "XD" -m "mkdir /home/xdclass" 镜像id mcentos:v1 -a:标注作者      -m:说明注释 原文地址:https://www.cnblogs.com/weisunblog/p/122355

第十四章 构建自定义的同步工具

14.1 状态依赖性管理 基于先检查后执行的状态依赖性操作在多线程下常常发生一些我们不希望的结果.因此有必要对状态依赖操作进行管理, 构成前提条件的状态变量必须有对象的锁来保护,从而使他们在测试前提条件的同事保持不变. 如果条件尚未满足, 则必须释放锁. 下次测试前提条件之前则必须重新获取锁.之后再进行前提条件的测试 重试的实现方式 : 自旋等待. 在条件不成立时一直询问, 直到条件成立. 会消耗大量的CPU时间 休眠. 如果条件不成立, 则休眠一段时间, 休眠过后继续测试条件是否成立. 响应性

docker使用centos7系统构建oraclejdk镜像

FROM centos:7.4.1708 MAINTAINER huqiang:2018/10/12 ENV JAVA_VERSION=8 JAVA_UPDATE=191 JAVA_BUILD=12 JAVA_PATH=2787e4a523244c269598db4e85c51e0c JAVA_HOME="/usr/lib/jvm/default-jvm" RUN yum install wget ca-certificates unzip -y && cd "

Docker 第五章 容器网络

ip netns 虚拟化网络都是基于netns实现 ip-netns - process network namespace management #管理网络名称空间工具 网络命名空间在逻辑上是网络堆栈的另一个副本,具有自己的路由,防火墙规则和网络设备. 默认情况下,进程从其父级继承其网络命名空间.最初,所有进程共享相同的默认网络名称空间 来自init进程. SYNOPSIS top #用法 ip [ OPTIONS ] netns { COMMAND | help } ip netns [ l

构建自定义docker镜像,上传至docker hub

docker 优势 (外部参考) Docker 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后 发布到任何流行的Linux机器上,便可以实现虚拟化.Docker改变了虚拟化的方 式,使开发者可以直接将自己的成果放入Docker中进行管理.方便快捷已经是 Docker的最大优势,过去需要用数天乃至数周的任务,在Docker容器的处理下,只需要数秒就能完成. 安装docker(请参考外部链接) [Ubuntu Docker 安装](http://www.runoob.com/dock

Docker之创建自定义镜像

简单介绍 之前使用docker run或者docker pull使用了Docker Hub上面已经构建好的的镜像,当然也可以自己基于基础镜像自定义镜像. 实际操作 1.可以使用docker run或者docker pull进行镜像的拉取和运行. 2.使用docker search ×××指令进行查找镜像 指令:sudo docker search fedora 结果 这里展示了有关fedora的镜像,显示了镜像名称,描述,星级,是否为官方以及是否自动构建信息. 3.构建镜像 构建镜像可以使用两个

Docker 构建私有镜像仓库(6)

title: Docker 构建私有镜像仓库(6) date: 2018-12-18 08:47:27 tags: Docker categories: Docker copyright: true --- Docker是基于Go语言实现的开源容器项目,Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口,Docker诞生于2013年年初,最初发起者是dotCloud公司.