一、引言
Docker镜像是一个只读的Docker容器模板,含有启动Docker容器所需的文件系统结构及其内容,因此是启动一个Docker容器的基础。镜像的结构原理图大致分为四层:共享的内核层、基础镜像层、定制镜像层、可写容器层。
- 共享的内核层:每个Docker容器运行时都共享宿主机的内核,这样可以大大减少内存的开销。
- 基础镜像层:base镜像提供的是最小的linux发行版,其实就是linux的根/文件系统。
- 定制镜像层:基于基础镜像进行定制化,添加或删除某些内容,形成新的镜像。
- 可写容器层:当一个容器被运行时,实际上会在这最后一层上运行,因此这一层是可以写的,能对容器进行动态的改变。
采用分层结构的最大好处是“共享资源”,不同的镜像使用同一个镜像层的时候,文件系统便可以实现资源共享,只需要备份一次,节省空间。
二、镜像结构
自定义 Docker 镜像有很多用途,以下是一些主要的应用场景:
一致性环境:通过自定义镜像,您可以确保您的应用在不同的环境中(开发、测试、生产等)运行在完全一致的环境中。这可以避免"在我机器上可以运行"的问题。
快速部署:自定义镜像包含了运行应用所需的所有依赖,这使得部署过程变得非常快速和简单。只需运行一个命令,就可以在任何安装了 Docker 的机器上启动应用。
版本控制和回滚:每个 Docker 镜像都有一个唯一的标签,这使得版本控制变得非常简单。如果新版本的应用有问题,您可以很容易地回滚到旧版本的镜像。
微服务架构:在微服务架构中,每个服务都可以有自己的 Docker 镜像。这使得每个服务可以独立地更新和扩展,而不会影响其他服务。
持续集成/持续部署(CI/CD):在 CI/CD 管道中,自定义镜像可以用于构建、测试和部署应用。这使得整个开发过程更加自动化,提高了开发效率。
Ⅰ. 基本结构
Dockerfile 是一个文本文件,它包含了一组用户可以调用来创建镜像的指令。以下是 Dockerfile 的基本结构:
-
FROM:指定基础镜像,所有操作都基于这个基础镜像。例如:
FROM ubuntu:18.04
-
LABEL:为镜像添加元数据及声明镜像的作者或者维护者的信息。
-
RUN:在镜像中运行命令,这些命令会在新的层上创建新的镜像。例如:
RUN apt-get update
-
CMD:提供容器默认的可执行程序,可以包含可执行程序,也可以省略,如果省略,则必须在运行时通过命令行指定。例如:
CMD ["executable","param1","param2"]
-
EXPOSE:声明运行时容器提供服务的网络端口。例如:
EXPOSE 8080
-
ENV:设置环境变量。例如:
ENV myName="John Doe" myDog=Rex\ The\ Dog
-
ADD 和 COPY:将文件从 Docker 主机复制到 Docker 镜像中。ADD 有自动解压缩功能,COPY 则更为直接明了。
-
ENTRYPOINT:配置容器启动后执行的命令,并且不会被 docker run 提供的参数覆盖。
-
VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保存的数据等。
-
WORKDIR:设置工作目录,所有后续的操作(CMD、ENTRYPOINT、COPY 和 ADD)都会在这个目录下进行。
-
USER:设置运行容器时的用户名或 UID。
-
ONBUILD:当构建一个被继承的 Dockerfile 时运行命令,该指令添加到镜像中,稍后触发。
-
MAINTAINER :用于声明镜像的作者或者维护者的信息,它可以为使用者提供一种联系镜像创建者的方式。
【注意i】MAINTAINER 从 Docker 1.13.0 开始,这个指令已经被标记为已废弃,推荐使用
LABEL
指令来替代。
如:
MAINTAINER John Doe <john.doe@example.com>
如:
LABEL maintainer="John Doe <john.doe@example.com>"
LABEL
指令可以用于添加更多的元数据到镜像中,比如版本号、构建日期等等。
这些指令在 Dockerfile 中按照从上到下的顺序执行。每个指令都会在镜像上创建一个新的层,然后提交。
案例:
# 基于官方的 JDK 镜像
FROM openjdk:8-jdk
# 设置环境变量
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
# 安装 MySQL
RUN apt-get update && apt-get install -y mysql-server
# 安装 Tomcat
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME
RUN curl -O https://downloads.apache.org/tomcat/tomcat-8/v8.5.61/bin/apache-tomcat-8.5.61.tar.gz \
&& tar -xvf apache-tomcat-8.5.61.tar.gz \
&& rm apache-tomcat-8.5.61.tar.gz
# 暴露端口
EXPOSE 8080
# 启动 Tomcat
CMD ["catalina.sh", "run"]
这个 Dockerfile 会创建一个包含 JDK、MySQL 和 Tomcat 的 Docker 镜像。在构建镜像时,它会先从 Docker Hub 下载官方的 JDK 镜像作为基础镜像,然后安装 MySQL,接着下载并安装 Tomcat,最后设置启动命令为启动 Tomcat。
请注意,这只是一个基础示例,实际使用时可能需要根据具体需求进行修改和优化。例如,可能需要添加更多的环境变量,或者调整安装命令以适应特定的应用需求。
Ⅱ. 常用命令
以下是您提到的 Dockerfile 指令的详细解释:
RUN:用于执行后面跟着的命令行命令。有两种格式:
RUN <command>
(shell 格式)和RUN ["executable", "param1", "param2"]
(exec 格式)。ENV:用于设置环境变量。这些变量以
<key>=<value>
的形式存在,可以在容器中被脚本或程序调用。COPY:将来自 Dockerfile 所在目录的文件或目录复制到容器中的一个新位置。
ADD:与 COPY 类似,但是 ADD 允许后面的源参数是一个 URL,或者在源文件是一个 tar 文件的情况下,可以自动解压缩这个 tar 文件。
EXPOSE:用于声明容器运行时监听的网络端口。
WORKDIR:用于设置 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令的工作目录。
ONBUILD:当镜像被用作其他 Dockerfile 的基础镜像时,ONBUILD 指令将会被触发执行。
USER:用于设置接下来的 RUN、CMD 和 ENTRYPOINT 指令运行时的 UID。
VOLUME:用于在容器中创建一个挂载点,用于连接 Docker 主机和容器的文件系统。
容器启动时自动执行指令:
CMD 和 ENTRYPOINT 都是 Dockerfile 中用于指定容器启动时运行的命令的指令,但它们的用法和目的有所不同。
-
CMD:CMD 指令用于提供容器运行时的默认命令及其参数。在启动容器时,我们可以覆盖这些默认的参数。CMD 在 Dockerfile 中只应被定义一次,如果定义了多次,只有最后一次的定义会生效。CMD 有两种格式:
如果 Dockerfile 中同时存在 CMD 和 ENTRYPOINT,CMD 中的参数会被添加到 ENTRYPOINT 中,作为其参数。
CMD ["executable","param1","param2"]
(exec 格式,推荐)CMD command param1 param2
(shell 格式)
-
ENTRYPOINT:ENTRYPOINT 的目的也是让容器以应用程序或服务的形式运行。与 CMD 不同,我们在启动容器时不能覆盖 ENTRYPOINT 指令提供的命令,但可以添加额外的参数。ENTRYPOINT 有两种格式:
如果我们既想让容器以应用程序或服务的形式运行,又想让这些应用或服务接受参数,那么最好的做法是使用 ENTRYPOINT 和 CMD 一起使用,让 ENTRYPOINT 指定应用程序,而让 CMD 指定默认参数。
ENTRYPOINT ["executable", "param1", "param2"]
(exec 格式,推荐)ENTRYPOINT command param1 param2
(shell 格式)
三、自定义镜像
Ⅰ. 基本镜像
首先进入虚拟机并且用MobaXterm这个工具连接,进入后先查看docker的服务/进程有没有开:
输入命令:systemctl status docker (查看docker的服务/进程)
以下是没有开启状态:
以下是开启状态:
创建一个文件夹,来存放创建后的镜像,并且创建并编写 Dockerfile 文件。
创建文件夹:mkdir soft (名称soft,可以自己修改)
进入文件夹:cd soft/
创建并编辑Dockerfile文件:vim Dockerfile (文件名称不用改)
进入文件后,按 i 进入编辑模式,然后将以下粘贴上,在按Esc退出编辑模式,输入 :wq
保存编写内容并且退出文件。
在Dockerfile文件中编写:
#1.指定基础镜像,并且必须是第一条指令 FROM centos #2.指明该镜像的作者和其电子邮件 MAINTAINER CloudJun "jun737x@163.com" #3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录 WORKDIR /test #4.将文件从Docker主机复制到Docker镜像中 COPY spring.jar /test
创建编写完成后,通过 docker build 命令来创建镜像。
命令:
docker build -t spring:v1
创建语句 docker build -t ,创建后这个镜像的名称spring,这个镜像的版本为 v1 ( 版本可以自己定义,如:0.1,1.0,v1,v2都可以),其中的
.
表示在当前目录创建
再查看镜像:docker images
进入:docker run -it spring:v1 (spring为镜像名称,后面的:v1是需要进入镜像的哪个版本)
之后看看当前目录是不是自己在Dockerfile文件中所设置的,及带进来的jar包是否存在
查看当前路径:pwd
查看文件:ls
Ⅱ. 进阶镜像
以上的镜像是不可以jar包中的项目运行的,因为镜像中没有jdk配置。
首先,需将本地的属于Linux的jdk和jre的压缩包拖到创建的文件夹中
如图:
以下我们来进行完善以上的缺陷:
以下配置jdk,可以运行jar包项目
输入命令,编辑Dockerfile文件:vim Dockerfile ,将原来的编写全部删除。
删除:进入后先将输入键到第一行,再输入数字(输入的数字是看不到的如:12),再按两下 d ,就会删除12行已编写的内容,当然输入13或者14就删除13或者14行,可以根据自己想删除多少行来进行输入
将以下编写的内容粘贴到Dockerfile文件中,按Esc退出编辑模式,输入 :wq 保存编写内容并且退出文件。
#1.指定基础镜像,并且必须是第一条指令 FROM centos #2.指明该镜像的作者和其电子邮件 MAINTAINER CloudJun "jun737x@163.com" #3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录 WORKDIR /test #4.将文件从Docker主机将jdk及jar包复制到Docker镜像中,自动将jdk的压缩包进行解压 COPY spring.jar /test ADD jdk-8u221-linux-x64.tar.gz /test #5.将jdk解压后配置环境变量 ENV JAVA_HOME=/test/jdk1.8.0_221 ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV PATH=$JAVA_HOME/bin:$PATH #6.容器启动时,需要执行的命令(执行jar包) CMD java -jar spring.jar
如图(粘贴进去后全部注释了,可以手动删除前面的#解除注释):
创建镜像:
docker build -t spring:v2
再查看镜像:
docker images
进入容器:
docker run -it spring:v2
(这里会自动启动jar包)
已可以通过:
docker run -itd spring:v2
(在后台运行)
再进入:docker exec -it 24696887b11eeb7ea229221e94f7b0cac03526551854319db80aef21b2d12ca4 bash
( 其中bash前面是运行后的编号,根据运行后的编号进入到该容器中)
查看jar及解压后的jdk,还可以输入命令查看jdk环境:echo $JAVA_HOME
以下配置jre,可以运行jar包项目及优化储存
输入命令,编辑Dockerfile文件:vim Dockerfile ,将原来的编写全部删除。
将以下编写的内容粘贴到Dockerfile文件中,按Esc退出编辑模式,输入 :wq 保存编写内容并且退出文件。
#1.指定基础镜像,并且必须是第一条指令 FROM centos #2.指明该镜像的作者和其电子邮件 MAINTAINER CloudJun "jun737x@163.com" #3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录 WORKDIR /test #4.将文件从Docker主机jre包复制到Docker镜像中,自动将jdk的压缩包进行解压 COPY spring.jar /test ADD jre-8u391-linux-x64.tar.gz /test #5.将jre解压后配置环境变量 ENV JAVA_HOME=/test/jre1.8.0_391 ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV PATH=$JAVA_HOME/bin:$PATH #6.容器启动时,需要执行的命令(执行jar包) CMD java -jar spring.jar
创建镜像:
docker build -t spring:v3
再查看镜像:
docker images
运行:
docker run -itd spring:v3
虽然储存的减少可能很小,但是当需要量上来是时候也是节省了大量的储存空间的。
Ⅲ. 完善镜像
需要将储存控制到很少可以使用这个镜像jeanblanchard/alpine-glibc,这个镜像所需的储存很少,而通过这个镜像自定义出来的镜像也会少很多。
首先需要下载这个镜像:
docker pull jeanblanchard/alpine-glibc
再查看镜像的信息:
docker images
可以看到所需的储存空间很少。
然后我们将指定的镜像修改为这个镜像将Dockerfile文件,再次镜像编辑为以下内容。
#1.指定基础镜像,并且必须是第一条指令 FROM jeanblanchard/alpine-glibc #2.指明该镜像的作者和其电子邮件 MAINTAINER CloudJun "jun737x@163.com" #3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录 WORKDIR /test #4.将文件从Docker主机jre包复制到Docker镜像中,自动将jdk的压缩包进行解压 COPY spring.jar /test ADD jre-8u391-linux-x64.tar.gz /test #5.将jre解压后配置环境变量 ENV JAVA_HOME=/test/jre1.8.0_391 ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV PATH=$JAVA_HOME/bin:$PATH #6.容器启动时,需要执行的命令(执行jar包) CMD java -jar spring.jar
创建镜像:
docker build -t spring:v4
再查看镜像:
docker images
现在这样的需要的储存空间就相对少了一半,更加的节省了资源空间。
现在映射端口运行:
docker run -itd --name s1 -p 8080:8080 spring:v4
之后在主机浏览器中访问虚拟机IP的访问路径:IP地址:8080
四、镜像上传仓库
首先需要在我们的阿里云账号中开启镜像仓库,点击用户左边的控制器,点击容器镜像服务ACR,点击实例列表,在其中点击创建个人版本的,企业版要米,创建后需要设置密码。
容器镜像服务 (aliyun.com)
之后将以上的登入凭证复制粘贴到虚拟机中执行命令,前面的$不用复制进去,之后会镜像密码的输入,是自己设置的容器镜像服务密码,以下说明登入成功:
创建仓库:在实例列表中点击命名空间——>之后创建命名空间即可
如图:
之后创建一个仓库,仓库名称可以自己取
有其中的之后也可以绑定到账号中去,这里没有就可以选择本地仓库
之后将需要上传推送到仓库的镜像取个别名,在将这个镜像绑定为阿里云的仓库,阿里云仓库在镜像仓库的第三部的将镜像推送到Registry中有命令。
第一个命令为登入,第二个命令为绑定阿里云仓库,第三个命令为上传推送到仓库
现在我们将虚拟机中共的镜像删除,删除后可以在次重阿里仓库中拉取下来。
删除:
docker rmi
镜像名:v1 (v1版本号)
拉取下载命令:
docker pull
仓库中的创建名称:v1