制作Docker镜像 |
您所在的位置:网站首页 › docker开发环境镜像制作 › 制作Docker镜像 |
目录一、Docker构建镜像的原理1、镜像分层原理2、Docker的镜像结构3、分层存储原理4、构建命令与层的关系5、最终镜像的创建二、docker commit 构建镜像1、使用场景2、手动制作yum版的nginx镜像2.1、启动一个centos容器,安装好常用的软件以及nginx2.2、关闭nginx后台运行2.3、自定义web页面2.4、提交为镜像2.5、从自己的镜像启动容器三、DockerFile1、什么是DockerFile2、DockerFile构建镜像过程四、DockerFile的常用指令1、FROM1.1、指令格式1.2、示例2、ARG2.1、指令格式2.2、作用域2.3、预定义ARG2.4、示例3、LABEL3.1、指令格式3.2、示例3.3、多个标签3.4、单行多标签3.5、多行多标签(推荐)3.6、查看镜像标签4、EXPOSE4.1、指令格式4.2、示例:同时监听TCP和UDP协议的端口5、ENV5.1、指令格式5.2、示例5.3、持续性5.4、注意事项6、ADD6.1、指令格式6.2、选项6.3、示例1、通配符匹配2、相对路径3、绝对路径4、特殊字符处理7、COPY7.1、指令格式7.2、选项7.3、COPY --from7.4、COPY --chown 和 COPY --chmod7.5、COPY --link8、USER8.1、指令格式8.2、示例9、WORKDIR9.1、指令格式9.2、示例10、VOLUME10.1、指令格式10.2、示例10.3、注意事项11、ENTRYPOINT11.1、指令格式11.2、示例12、RUN12.1、指令格式12.2、示例:缓存Go包12.3、示例:缓存apt包12.4、示例:访问GitLab13、CMD13.1、指令格式13.2、注意事项五、DockerFile制作镜像(制作nginx镜像)1、下载centos镜像2、创建对应目录3、进入指定目录下载源码包4、编写DockerFile4.1、解析5、构建镜像6、测试验证六、镜像上传1、阿里云仓库1.1、注册账户1.2、创建个人版实例1.3、设置Registry登录密码1.4、创建镜像仓库1.5、登录阿里云Docker Registry1.6、将镜像推送到Registry2、Docker Hub上传镜像
一、Docker构建镜像的原理
1、镜像分层原理
Docker镜像是由一系列只读的层(layers)组成的,每个层代表了一组文件系统的更改。这些更改可以是添加文件、删除文件、修改文件等操作。镜像的最底层通常是一个基础镜像,比如基于CentOS、Ubuntu、Alpine等操作系统。往上每一层代表了Dockerfile中每个指令的执行结果。重要的是,每一层都是不可变的,一旦创建就不会被修改,新的更改会在其上新建一层。 2、Docker的镜像结构docker的分层镜像结构如图所示,镜像的最底层必须是一个启动文件系统(bootfs)的镜像层。bootfs的上层镜像称为根镜像(rootfs)或者基础镜像(Base Image),它一般是操作系统,比如centos、debian或者Ubuntu。 用户的镜像必须构建在基础镜像之上。如图所示,emacs镜像层就是在基础镜像上安装emacs创建出来的镜像,在此基础上安装apache又创建了新的镜像层。利用这个新的镜像层启动的容器里运行的是一个已经安装好emacs和apache的Debian系统。 3、分层存储原理Docker镜像采用UnionFS(联合文件系统,如AUFS、OverlayFS等)实现分层存储。UnionFS允许将多个文件系统层次叠加以形成一个单一的合并视图。对于Docker镜像来说,每个层都是只读的,除了最顶层的可写层(在容器运行时创建)。 基础层:通常是操作系统层,包含最低级别的文件和库。 中间层:由Dockerfile中的每个指令生成,每个层都是对前一层的增量修改。 读写层(容器层):容器运行时,会在镜像的顶部添加一个可写的层,用于保存容器运行时的所有改动。 4、构建命令与层的关系 在Dockerfile中,每个RUN、COPY、ADD等指令执行后,都会在现有镜像基础上添加一个新的只读层。 如果指令没有导致文件系统的变化(例如,执行一个检查系统状态的命令但不改变任何文件),Docker可能不会创建新的层。 重复的构建步骤可以通过Docker的缓存机制避免重复执行,从而加速构建过程。 5、最终镜像的创建构建过程的最后,Docker将所有这些层组合起来,并为这个组合赋予一个唯一的ID,这就是最终的Docker镜像。这个镜像可以被打上标签(tag),便于识别和后续的拉取、推送操作。 二、docker commit 构建镜像 1、使用场景 构建临时的测试镜像; 容器被入侵后,使用docker commit,基于被入侵的容器构建镜像,从而保留现场,方便以后追溯。 2、手动制作yum版的nginx镜像 2.1、启动一个centos容器,安装好常用的软件以及nginx [root@localhost ~]# docker run -it --name centos-v1 centos:7 bash [root@95ef0464ffb2 /]# yum install -y epel-release [root@95ef0464ffb2 /]# yum install -y nginx [root@95ef0464ffb2 /]# yum install -y wget vim pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop 2.2、关闭nginx后台运行 [root@95ef0464ffb2 /]# sed -i '/^pid \/run\/nginx.pid;$/a daemon off;' /etc/nginx/nginx.conf [root@95ef0464ffb2 /]# egrep -v "^$|^#" /etc/nginx/nginx.conf | head -5 user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; daemon off; 2.3、自定义web页面 [root@95ef0464ffb2 /]# echo 'hello yum_nginx' > /usr/share/nginx/html/index.html 2.4、提交为镜像 docker commit -m "my first nginx image v1" centos-v1 centos_nginx:v1DockerFile 是一个用于自动构建 Docker 镜像的文本文件,其中包含了用户可以给出的所有构建镜像所需的指令和参数。 这个文件按照从上至下的顺序定义了一系列构建镜像的步骤,每个指令通常对应于镜像中的一个层。 DockerFile 的设计使得镜像的创建过程高度可编程、可重复及可共享,有利于实现持续集成和持续部署(CI/CD)的工作流程。 2、DockerFile构建镜像过程1、首先,创建一个目录用于存放应用程序以及构建过程中使用到的各个文件等; 2、然后,在这个目录下创建一个Dockerfile文件,一般建议Dockerfile的文件名就是Dockerfile; 3、编写Dockerfile文件,编写指令,如,使用FROM 指令指定基础镜像,COPY指令复制文件,RUN指令指定要运行的命令,ENV设置环境变量,EXPOSE指定容器要暴露的端口,WORKDIR设置当前工作目录,CMD容器启动时运行命令,等等指令构建镜像; 4、Dockerfile编写完成就可以构建镜像了,使用docker build -t 镜像名:tag . 命令来构建镜像,最后一个点是表示当前目录,docker会默认寻找当前目录下的Dockerfile文件来构建镜像,如果不使用默认,可以使用-f参数来指定dockerfile文件,如:docker build -t 镜像名:tag -f /xx/xxx/Dockerfile ; 5、使用docker build命令构建之后,docker就会将当前目录下所有的文件发送给docker daemon,顺序执行Dockerfile文件里的指令,在这过程中会生成临时容器,在临时容器里面安装RUN指定的命令,安装成功后,docker底层会使用类似于docker commit命令来将容器保存为镜像,然后删除临时容器,以此类推,一层层的构建镜像,运行临时容器安装软件,直到最后的镜像构建成功。 四、DockerFile的常用指令官方文档 1、FROM指定基础镜像,必须为第一个命令 1.1、指令格式 FROM [--platform=] [AS ] FROM [--platform=] [:] [AS ] FROM [--platform=] [@] [AS ] FROM指令用于指定基础镜像 –platform选项可用在FROM多平台镜像的情况下指定平台。例如,linux/amd64、lunux/arm64、windows/amd64。 AS name表示为构建阶段命令,在后续FROM和COPY --from=name说明中可以使用这个名词,引用此阶段构建的映像。 tag或digest值是可选的。如果您省略其中任何一个,构建器默认使用latest标签。如果找不到指定tag,构建起将返回错误。 为了保证镜像精简,可以选用体积较小的Alpin或Debian作为基础镜像 1.2、示例 ARG CODE_VERSION=latest FROM base:${CODE_VERSION} CMD /code/run-app FROM extras:${CODE_VERSION} CMD /code/run-extras 2、ARG定义创建镜像过程中使用的变量 ARG是唯一可以位于FROM指令之前的指令 2.1、指令格式 ARG [=]是变量名,[=]是可选的默认值。 2.2、作用域ARG变量的定义从其在Dockerfile中的定义行开始生效,并在构建阶段结束时失效。 要在多个构建阶段使用相同的ARG,每个阶段都需要重新声明ARG。 2.3、预定义ARGDocker预定义了一系列ARG变量,如HTTP_PROXY、HTTPS_PROXY等,这些可以在构建时不需在Dockerfile中声明,直接通过命令行的--build-arg使用。 2.4、示例 FROM busybox ARG user1 ARG buildno=1在这个例子中,user1没有默认值,而buildno的默认值是1。 3、LABEL为生成的镜像添加元数据标签信息 这些元数据以键值对的形式存在 3.1、指令格式 LABEL = = = ... 键(key):应当是唯一的标识符,用于描述标签的内容类别。 值(value):与键相关联的具体数据内容,可以包含任何字符串,包括空格。如果值中需要包含空格或特殊字符,应使用双引号包围并适当使用转义字符(如\)。 3.2、示例 LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines." 3.3、多个标签可以在单行或多行上指定多个标签,尽管这样做在Docker 1.10版本后不再减少最终镜像的大小,但仍然是一种组织代码的可选方式 3.4、单行多标签 LABEL multi.label1="value1" multi.label2="value2" other="value3" 3.5、多行多标签(推荐) LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3"使用双引号而非单引号:当值中包含环境变量插值等需要解析的元素时,必须使用双引号,因为单引号会阻止变量展开。 如果基础镜像(即FROM指令指定的镜像)中已经包含了某些标签,那么这些标签会被继承。如果有相同键的标签在新镜像的Dockerfile中被重新定义,那么新定义的值将覆盖原有的值。 3.6、查看镜像标签 docker image inspect --format='{{json .Config.Labels}}' myimage { "com.example.vendor": "ACME Incorporated", "com.example.label-with-value": "foo", "version": "1.0", "description": "This text illustrates that label-values can span multiple lines.", "multi.label1": "value1", "multi.label2": "value2", "other": "value3" } 4、EXPOSE声明镜像内服务监听的端口 文档作用:EXPOSE主要是为了提供一种文档记录的方式,帮助理解容器设计意图中哪些端口需要被外部访问。它不改变容器的实际行为,也不直接导致端口暴露给宿主机或其他网络服务。 TCP与UDP:默认情况下,如果没有指定协议,EXPOSE认为端口使用TCP协议。你也可以明确指定端口为UDP,如EXPOSE 80/udp。若需同时支持TCP和UDP,需分别声明两次:EXPOSE 80/tcp 和 EXPOSE 80/udp。 运行时覆盖:尽管Dockerfile中指定了EXPOSE,但在运行容器时,可以通过docker run的-p标志灵活地重写这些设置,比如映射到不同的宿主机端口,或者更改协议。 4.1、指令格式 EXPOSE [/...] 4.2、示例:同时监听TCP和UDP协议的端口 EXPOSE 80/tcp EXPOSE 80/udp docker run -p 80:80/tcp -p 80:80/udp ... 5、ENV用于设置环境变量 5.1、指令格式 ENV = ... 设置环境变量:允许为后续构建阶段中的所有指令设置环境变量,变量名是,变量值是。这些环境变量可以在后续的RUN、CMD等指令中通过引用,支持环境变量替换。 嵌套解析:环境变量的值可以包含或引用其他环境变量,并且支持使用引号和反斜杠来包含空格或特殊字符,但引号会被移除,除非转义。 5.2、示例 ENV MY_NAME="John Doe" ENV MY_DOG=Rex\ The\ Dog ENV MY_CAT=fluffy ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \ MY_CAT=fluffy #批量设置 5.3、持续性 持久化:通过ENV设置的环境变量不仅在构建阶段有效,还会保留在从该镜像创建的容器中。你可以使用docker inspect查看这些值,通过docker run --env =来覆盖它们。 继承性:在多阶段构建中,子阶段会继承父阶段设置的环境变量。 5.4、注意事项副作用:环境变量的持久性可能导致意料之外的行为变化。例如,设置DEBIAN_FRONTEND=noninteractive会改变apt-get的行为,可能给镜像的使用者带来混淆。 构建时使用:如果环境变量只在构建过程中需要,而在最终镜像中不需要,可以考虑在单独的命令中设置,如: RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...使用ARG:或者,可以使用ARG指令来设置构建时的变量,这些变量不会保存在最终的镜像中。 6、ADD用于将文件、目录或远程文件URL添加到镜像的文件系统中 6.1、指令格式 ADD [OPTIONS] ... ADD [OPTIONS] ["", ""] 可以是本地路径、通配文件、目录或URL。支持通配符(如*?、)。URL要求绝对路径必须指向文件。 目标路径,绝对或相对于当前WORKDIR。指定目录。如果 结尾是/且是URL,Docker会根据URL中的文件名来命名解压,解压后的文件保存在指定的目录中。 6.2、选项--keep-git-dir: 保留远程Git仓库中的.git目录。 --checksum: 验证资源的校验签。 --chown: 设置文件权限。 --link:硬链接处理。 --exclude:排除模式匹配的文件或目录。 6.3、示例 1、通配符匹配 ADD hom* /mydir/ #添加以"hom"开头的所有文件到mydir目录中 ADD hom?.txt /mydir/ #单字符匹配 2、相对路径是相对路径,它会相对于当前的WORKDIR ADD test.txt relativeDir/ #将test.txt添加到relativeDir内 3、绝对路径若以斜杠开头,它是绝对路径。 ADD test.txt /absoluteDir/ #将test.txt添加到absoluteDir根目录下 4、特殊字符处理如果文件名包含如方括号等特殊字符,需要按照Go语言规则转义路径 ADD arr[[]0].txt /mydir/ 7、COPY编写Dockerfile的时候copy宿主机文件到镜像中。 7.1、指令格式 COPY [OPTIONS] ... COPY [OPTIONS] ["", ... ""] 7.2、选项 --from=:从之前的构建阶段或指定的镜像中拷贝文件,而非当前构建上下文。 --chown=::设置拷贝文件的用户和组所有权。 --chmod=:设置拷贝文件的权限模式。 --link[=]:启用链接层机制,使得文件独立于前序层,优化缓存使用。 --parents[=]:保留源路径中的父目录结构。 --exclude=:排除符合指定模式的文件或目录 7.3、COPY --from允许从一个已有的镜像、构建阶段或者其他命名的上下文中复制文件 FROM alpine AS build COPY . . RUN apk add clang RUN clang -o /hello hello.c FROM scratch COPY --from=build /hello /在一个多阶段构建中,可以指定从名为build的构建阶段复制文件 COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf #也可以直接从其他镜像复制文件,比如从官方的Nginx镜像中复制配置文件 7.4、COPY --chown 和 COPY --chmod COPY [--chown=:] [--chmod=...] ... COPY --chown=55:mygroup files* /somedir/ COPY --chown=bin files* /somedir/ COPY --chown=1 files* /somedir/ COPY --chown=10:11 files* /somedir/ COPY --chown=myuser:mygroup --chmod=644 files* /somedir/ 7.5、COPY --link COPY [--link[=]] ... # syntax=docker/dockerfile:1 FROM alpine COPY --link /foo /bar相当于 FROM alpine # 第一个构建 FROM scratch COPY /foo /bar # 第二个构建,并将两个镜像的所有层合并在一起 8、USER用于设置后续当前构建阶段中默认使用的用户名(或 UID)以及可选的用户组(或 GID)。 如果所指定的用户没有主组,那么镜像(或之后的指令)将会以根组(root group)的身份运行。 8.1、指令格式 USER [:] USER [:] 8.2、示例 FROM microsoft/windowsservercore # 在容器中创建 Windows 用户 RUN net user /add patrick # 为后续指令设置用户 patrick USER patrick 9、WORKDIR用于为 Dockerfile 中随后的 RUN, CMD, ENTRYPOINT, COPY, 和 ADD 指令设置工作目录。 如果指定的工作目录不存在,即使之后的 Dockerfile 指令未使用到它,也会被创建。 9.1、指令格式 WORKDIR /path/to/workdir 9.2、示例 WORKDIR /a WORKDIR b WORKDIR c RUN pwdDockerfile 中可以多次使用 WORKDIR 指令。如果给出的是相对路径,它将是相对于前一个 WORKDIR 指令的路径。 最后的 pwd 命令的输出将是 /a/b/c。 10、VOLUME创建一个数据卷挂载点 10.1、指令格式 VOLUME ["/data"] 10.2、示例 FROM ubuntu RUN mkdir /myvol RUN echo "hello world" > /myvol/greeting VOLUME /myvol这个 Dockerfile 将生成一个镜像,使得执行 docker run 时会在 /myvol 创建一个新的挂载点,并将 greeting 文件复制到新创建的卷里。 10.3、注意事项 在基于 Windows 的容器上,容器内卷的目标必须是: 一个不存在或为空的目录 除了 C: 以外的其他驱动器 若在 Dockerfile 中声明卷后,有任何构建步骤修改了卷内的数据,这些更改将会被丢弃。 列表解析遵循 JSON 数组格式。你需要使用双引号(")而不是单引号(')来包围文本。 宿主机目录是在容器运行时声明的:由于宿主机目录(即挂载点)依附于特定宿主机,为了保持镜像的可移植性(因为无法确保特定的宿主机目录在所有宿主机上都存在),你不能在 Dockerfile 中直接从宿主机挂载目录。VOLUME 指令不支持指定宿主机目录参数。你需要在创建或启动容器时指定挂载点。 11、ENTRYPOINT指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数 每个DockerFile中只能有一个ENTRYPOINT,当指定多个时只有最后一个起效 11.1、指令格式 ENTRYPOINT ["executable", "param1", "param2"] #exec形式 ENTRYPOINT command param1 param2 #shell形式 11.2、示例 FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]当你运行这个容器时,可以看到top是唯一的进程: docker run -it --rm --name test top -H 12、RUN运行指定命令 每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像层 当命令较长时可以使用\来换行 12.1、指令格式 RUN [OPTIONS] ... #shell形式 RUN [OPTIONS] [ "", ... ] #exec形式 12.2、示例:缓存Go包 # syntax=docker/dockerfile:1 FROM golang RUN --mount=type=cache,target=/root/.cache/go-build \ go build ... 12.3、示例:缓存apt包 # syntax=docker/dockerfile:1 FROM ubuntu RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt update && apt-get --no-install-recommends install -y gcc 12.4、示例:访问GitLab # syntax=docker/dockerfile:1 FROM alpine RUN apk add --no-cache openssh-client RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts RUN --mount=type=ssh \ ssh -q -T [email protected] 2>&1 | tee /hello # "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here # with the type of build progress is defined as `plain`. eval $(ssh-agent) ssh-add ~/.ssh/id_rsa (Input your passphrase here) docker buildx build --ssh default=$SSH_AUTH_SOCK . 13、CMDCMD指令用来指定启动容器时默认执行的命令 13.1、指令格式 CMD ["executable","param1","param2"] #相当于执行executable param1 param2 CMD ["param1","param2"] #提供给ENTRYPOINT的默认参数 CMD command param1 param2 #在默认的shell中执行,提供给需要交互的应用每个Dockerfile 只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行 13.2、注意事项如果使用CMD为ENTRYPOINT指令提供默认参数,那么CMD和ENTRYPOINT指令都应该以exec形式指定。 RUN实际上运行一个命令并提交结果;CMD在构建时不执行任何操作,但指定了镜像的预期命令。 五、DockerFile制作镜像(制作nginx镜像) 1、下载centos镜像 docker pull centos:7 2、创建对应目录 mkdir -pv dockerfile/{web/{nginx,apache},system/{centos,ubuntu}}阿里云容器镜像服务 1.1、注册账户![]() ![]() ![]() ![]() ![]() ![]() 用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。 您可以在访问凭证页面修改凭证密码。 1.6、将镜像推送到Registry docker tag nginx:v1 registry.cn-hangzhou.aliyuncs.com/misaki_nginx/my_nginx:v1 #将本地nginx:v1镜像创建标签并归属到阿里云镜像服务的指定仓库中 docker push registry.cn-hangzhou.aliyuncs.com/misaki_nginx/my_nginx:v1 #将重新标记的镜像推送到阿里云的容器镜像仓库中目前我还没注册,暂时写不了这部分的镜像上传 但基本思路还是注册登录账户--> 本地登录仓库--> 给需要上传的镜像tag标签 --> docker push -->官网验证即可 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |