• Docker-Dockerfile


    一、引入

    1. 什么是Dockerfile

    Dockerfile 是一个用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明。

    • Dockerfile 是一个文本文件
    • 包含了一条条的指令
    • 每一条指令构建一层,基于基础镜像,最终构建出一个新的镜像
    • 对于开发人员:可以为开发团队提供一个完全一致的开发环境
    • 对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件 构建一个新的镜像开始工作了
    • 对于运维人员:在部署时,可以实现应用的无缝移植

    常见的镜像在DockerHub就能找到,但是我们自己写的项目就必须自己构建镜像了。
    dockerFile是用来构建docker镜像的文件!命令参数脚本!

    构建自定义的镜像时,并不需要一个个文件去拷贝,打包。

    我们只需要告诉Docker,我们的镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么,将来Docker会帮助我们构建镜像。

    而要自定义镜像,就必须先了解镜像的结构才行。

    2. 镜像结构

    镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。

    我们以MySQL为例,来看看镜像的组成结构:
    在这里插入图片描述

    简单来说,镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件。

    我们要构建镜像,其实就是实现上述打包的过程。

    3. 约定

    • Dockerfile中所用的所有文件一定要和Dockerfile文件在同一级父目录下,可以为Dockerfile父目录的子目录
    • Dockerfile中相对路径默认都是Dockerfile所在的目录
    • Dockerfile中一定要惜字如金,能写到一行的指令,一定要写到一行,原因是分层构建,联合挂载这个特性。Dockerfile中每一条指令被视为一层

    二、Dockerfile常用指令

    Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。

    网上找到一张很有意思的图,我将它放在这。

    在这里插入图片描述


    1. FROM

    基础镜像,定制的镜像都是基于 FROM 的镜像。并且必须是第一条指令

    如果不以任何镜像为基础,那么写法为:FROM scratch

    • 格式
    FROM <image>
    FROM <image>:<tag>
    FROM <image>@<digest>
    
    # 注意:
    tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 例子
    FROM mysql:5.7
    # 若不以任何镜像为基础
    FROM scratch
    
    • 1
    • 2
    • 3

    2. MAINTAINER

    镜像是谁写的, 姓名+邮箱。可以只写一个。

    新版Docker中将弃用,并使用LABEL指明

    • 格式
    MAINTAINER <name>
    
    • 1
    • 例子
    # 只写名字
    MAINTAINER tyt
    # 只写邮箱
    MAINTAINER 273@qq.com
    # 名字 + 邮箱
    MAINTAINER tyt<273@qq.com>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. LABEL

    LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式。通俗点说就是为镜像指定标签。

    • 格式
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    
    • 1
    • 例子
    LABEL org.opencontainers.image.authors="tyt" version="1.0" label1="l1" 
    
    • 1

    4. RUN

    镜像构建的时候需要运行的命令。有以下2种格式:

    • shell 格式
    RUN <命令行命令>
    # <命令行命令> 等同于,在终端操作的 shell 命令。
    
    • 1
    • 2
    • exec格式
    RUN ["可执行文件或命令", "参数1", "参数2", ...]
    # RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
    
    • 1
    • 2
    • 例子
    RUN yum -y install vim
    RUN yum -y install net-tools
    RUN ["/etc/execfile", "arg1", "arg1"]
    
    # 以上执行会创建 3 层镜像。可简化为以下格式:
    
    RUN yum -y install vim \
    	&& RUN yum -y install net-tools \
    	&& RUN ["/etc/execfile", "arg1", "arg1"]
    	
    # 如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意
    RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache

    5. CMD

    类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

    • CMDdocker run 时运行。
    • RUNdocker build时运行。

    作用

    • 为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
    • CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

    注意

    • 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效
    • 格式
    # 格式1:执行可执行文件或命令
    CMD ["<可执行文件或命令>","","",...] 
    # 格式2:执行 shell 内部命令
    CMD <shell命令> 
    
    # 格式3:该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
    # 注意,待会下面会提到
    CMD ["","",...]  
    
    推荐使用第一种格式,执行过程比较明确。
    第二种格式实际上在运行的过程中也会自动转换成第一种格式运行,
    并且默认可执行文件是 sh, 即 /bin/bash
    
    例如
    CMD ls -a 
    会转换为
    CMD ["ls", "-a"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 例子
    # 执行可执行文件或命令
    CMD ["/usr/bin/wc","--help"]
    # 执行 shell 内部命令
    CMD echo "This is a test." | wc -l
    
    # 为 ENTRYPOINT 指令指定的程序提供默认参数
    ENTRYPOINT ["nginx", "-c"]
    CMD ["/etc/nginx/nginx.conf"]
    
    默认执行时,运行以下命令
    nginx -c /etc/nginx/nginx.conf
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6. ENTRYPOINT

    类似于 CMD 指令,运行时机相同,都是在docker run执行,但其不会被 docker run命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数追加到 ENTRYPOINT 指令指定的程序。(具体谁被覆盖、谁被追加可看下方镜像构建实战中的 验证CMD 和ENTRYPOINT区别)。

    CMD与ENTRYPOINT不同点

    • ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖。但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

    ENTRYPOINT优点

    • 在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

    注意

    • 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
    • 如果我们在Dockerfile种同时写了ENTRYPOINTCMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数
    • 如果我们在Dockerfile种同时写了ENTRYPOINTCMD,并且CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效
    • 格式
    # 执行可执行文件
    ENTRYPOINT ["<可执行文件或命令>","","",...] 
    # 执行 shell 内部命令
    ENTRYPOINT <shell命令> 
    
    • 1
    • 2
    • 3
    • 4
    • 例子

    假设已通过 Dockerfile 构建了 nginx:test 镜像:

    FROM nginx
    ENTRYPOINT ["nginx", "-c"]    # 定参
    CMD ["/etc/nginx/nginx.conf"] # 变参 
    
    -----------------------------------------------
    
    不传参运行
    docker run nginx:test
    
    容器内会默认运行以下命令,启动主进程
    nginx -c /etc/nginx/nginx.conf
    
    -----------------------------------------------
    
    传参运行
    docker run  nginx:test -c /etc/nginx/my.conf
    
    容器内会默认运行以下命令,启动主进程(/etc/nginx/my.conf:假设容器内已有此文件)
    nginx -c /etc/nginx/my.conf
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 对于上述提到的ENTRYPOINT和CMD同时存在时举例
    # CMD指令不是一个完整的可执行命令
    ENTRYPOINT ["nginx", "-c"]   
    CMD ["/etc/nginx/nginx.conf"] 
    
    # 那么CMD指定的内容将会作为ENTRYPOINT的参数
    # 容器内会默认运行以下命令
    nginx -c /etc/nginx/nginx.conf
    
    ------------------------------------------------
    
    # CMD指令是一个完整的可执行命令
    ENTRYPOINT ["nginx", "-c"]   
    CMD ["ls", "-a"] 
    
    # 那么它们两个会互相覆盖,谁在最后谁生效
    # 容器内会默认运行以下命令
    ls -a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7. COPY

    复制指令,从本地主机复制文件或者目录到容器里指定路径。

    注意

    • 目标路径是绝对路径,或相对于 WORKDIR 的路径,源将在目标容器内复制到该路径中
    • --chown 仅适用于 linux 上的 dockerfile,在 window 上没有用户、组的概念
    • 源文件一定要和Dockerfile文件在同一级父目录下,或者为Dockerfile父目录的子目录
    • 格式
    COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
    # 用于支持包含空格的路径
    COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]
    
    • 1
    • 2
    • 3
    • 例子
    # 将所有 hom 开头的文件复制到镜像文件系统的 /mydir/ 目录下
    COPY hom* /mydir/           
    # ? 匹配 0 或 1 个字符,比如会把 home.txt 文件复制到 /mydir/ 目录下
    COPY hom?.txt /mydir/      
    # 复制名为 arr[0].txt 的文件到镜像文件系统的 /mydir/ 目录下
    COPY arr[[]0].txt /mydir/
    # 复制 "file1" 到 `WORKDIR`/relativeDir/
    COPY file1 relativeDir/       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    8. ADD

    ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

    • ADD 支持添加远程 url 和自动提取压缩格式的文件,COPY 只允许从本机中复制文件
    • COPY 支持从其他构建阶段中复制源文件(--from
    • 根据官方 Dockerfile 最佳实践,除非真的需要从远程 url 添加文件或自动提取压缩文件才用 ADD,其他情况一律使用 COPY

    9. ENV

    设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

    • 格式
    # 设置一个变量
    ENV <key> <value>
    # 设置多个变量
    ENV <key1>=<value1> <key2>=<value2>...
    
    • 1
    • 2
    • 3
    • 4
    • 例子
    # 设置 myInfo 一个变量
    ENV myInfo tyt 20 boy
    # 设置多个变量
    ENV name=tyt age=20 sex=boy
    
    • 1
    • 2
    • 3
    • 4
    • 在Dockerfile中使用变量的方式
    $varname
    ${varname}
    ${varname:-default value}
    $(varname:+default value} 
    
    第一种和第二种相同 
    第三种表示当变量不存在使用-号后面的值 
    第四种表示当变量存在时使用+号后面的值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 例子
    # dockerfile
    FROM centos
    ENV name TYT
    RUN echo "第一种格式变量存在 $name"
    RUN echo "第一种格式变量不存在 $username"
    RUN echo "第二种格式变量存在 ${name}"
    RUN echo "第二种格式变量不存在 ${username}"
    RUN ["/bin/bash", "-c", "echo 第三种格式变量存在 ${name:-HSYSJ}"]
    RUN ["/bin/bash", "-c", "echo 第三种格式变量不存在 ${username:-HSYSJ}"]
    RUN ["sh", "-c", "echo 第四种格式变量存在 ${name:+HSYSJ}"]
    RUN ["sh", "-c", "echo 第四种格式变量不存在 ${username:+HSYSJ}"]
    
    -----------------------------------------------------------------
    
    
    第一种格式 TYT
    第一种格式变量不存在
    第二种格式 TYT
    第二种格式变量不存在
    第三种格式变量存在 TYT
    第三种格式变量不存在 HSYSJ
    第四种格式变量存在 HSYSJ
    第四种格式变量不存在
    
    -----------------------------------------------------------------
    
    由以上可知
    第一种、第二种、第四种在变量不存在时都无法解析
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    10. EXPOSE

    声明端口配置。

    作用

    • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
    • 在运行时使用随机端口映射时,也就是docker run -P 时,会自动随机映射 EXPOSE 的端口。

    注意

    • EXPOSE 并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。
    • 如果没有暴露端口,后期也可以通过 -p 宿主机端口:容器端口 方式映射端口,但是不能通过 -P 形式映射。
    • 格式
    EXPOSE <端口1> [<端口2>...]
    
    • 1
    • 例子
    EXPOSE 80 443
    EXPOSE 8080    
    EXPOSE 11211/tcp 11211/udp
    
    • 1
    • 2
    • 3

    11. VOLUME

    定义匿名挂载数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

    作用

    • 避免重要的数据,因容器重启而丢失,这是非常致命的。
    • 避免容器不断变大。

    注意
    一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

    • 卷可以容器间共享和重用
    • 容器并不一定要和其它容器共享卷
    • 修改卷后会立即生效
    • 对卷的修改不会对镜像产生影响
    • 卷会一直存在,直到没有任何容器在使用它
    • 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点
    • 格式
    VOLUME ["<路径1>", "<路径2>"...]
    VOLUME <路径>
    
    • 1
    • 2
    • 例子
    VOLUME /data
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
    
    • 1
    • 2

    12. WORKDIR

    指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

    docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

    注意

    • 通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUNCMDENTRYPOINTADDCOPY 等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
    • 格式
    WORKDIR <工作目录路径>
    
    • 1
    • 例子
    FROM centos
    # 此时工作目录为/a
    WORKDIR /a
    RUN pwd # 输出 /a
    # 此时工作目录为/a/b
    WORKDIR b
    RUN pwd # 输出 /a/b
    # 此时工作目录为/a/b/c
    WORKDIR c
    RUN pwd # 输出 /a/b/c
    # 此时工作目录为/d
    WORKDIR /d
    RUN pwd # 输出 /d
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    13. USER

    用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

    注意

    • 使用USER指定用户后,Dockerfile中其后的命令RUNCMDENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。使用这个命令一定要确认容器中拥有这个用户,并且拥有足够权限
    • 格式
    USER <用户名>[:<用户组>]
    
    • 1
    • 例子
    USER tyt
    
    • 1

    14. ARG

    构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

    构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

    • 格式
    ARG <参数名>[=<默认值>]
    
    • 1
    • 例子
    # 我们可以定义一个或多个参数
    ARG username
    ARG password
    
    # 也可以给参数一个默认值
    ARG username=tyt
    ARG password=123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    15. ONBUILD

    用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

    • 格式
    ONBUILD <其它指令>
    
    • 1
    • 例子
    # 例如当前镜像 A
    ONBUILD RUN ls -al
    # 这个 ls -al 命令不会在A镜像构建或启动的时候执行
    
    # 此时镜像 B 是基于镜像 A 构建的
    # 那么这个ls -al 命令会在镜像 B 构建的时候被执行。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    更新详细语法说明,请参考官网文档


    三、镜像制作步骤

    构建步骤

    1. 编写一个dockerFile文件

    2. 使用 docker build 构建成为一个镜像

    docker build -f dockerfile文件路径 -t 镜像名:[tag] .
    
    • 1
    1. docker run 运行镜像

    2. docker push 发布镜像(DockerHub、阿里云镜像)


    四、镜像构建实战

    1. 验证CMD 和ENTRYPOINT区别

    CMD         # 指定这个容器启动的时候要运行的命令,仅最后一个生效,可被替代
    ENTRYPOINT  # 指定这个容器启动的时候要运行的命令,仅最后一个生效,可以追加命令
    
    • 1
    • 2
    • 测试CMD

    ① 编写 dockerfile 文件

    [root@iZ2vc7ujcalf4qilxwke3nZ dockerfile]# vim cmd-test
    
    # 基于 centos
    FROM centos
    # 设置容器启动的时候执行 ls -a
    CMD ["ls", "-a"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ② 构建成为一个镜像

    docker build -f cmd-test -t cmd-test:1 .
    
    • 1

    在这里插入图片描述

    ③ 运行容器测试

    dokcer run -it cmd-test:1
    
    • 1

    docker run运行, 发现我们的ls -a 命令生效

    在这里插入图片描述
    现在,如果我们想要使用 ls -al 命令,却报错。

    [root@iZ2vc7ujcalf4qilxwke3nZ dockerfile]# docker run -it cmd-test:1 -l
    docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
    ERRO[0000] error waiting for container: context canceled
    
    • 1
    • 2
    • 3

    这是因为当我们添加了 -l 参数后,-l替换了CMD["ls", "-a"]命令, -l不是命令,所以报错了。如果我们想要追加一个-l,就可以考虑使用ENTRYPOINT

    • 测试ENTRYPOINT

    ① 编写 dockerfile 文件

    [root@iZ2vc7ujcalf4qilxwke3nZ dockerfile]# vim point-test
    
    # 基于 centos
    FROM centos
    # 设置容器启动的时候执行 ls -a
    ENTRYPOINT ["ls", "-a"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ② 构建成为一个镜像

    docker build -f point-test -t point-test:1 .
    
    • 1

    在这里插入图片描述

    ③ 运行容器测试

    dokcer run -it point-test:1
    
    • 1

    docker run运行, 与 CMD相同,发现我们的ls -a 命令生效

    在这里插入图片描述
    现在,我们追加一个 -l 参数

    在这里插入图片描述

    我们的追加命令, 是直接拼接到ENTRYPOINT命令的后面,即 ls -al

    2. 基于centos构建Java项目

    • 编写 dockerfile 文件 (此处我命名为 demo-df
    # 指定基础镜像
    FROM centos
    # 配置环境变量,JDK的安装目录
    ENV JAVA_DIR=/usr/local
    # 指定工作目录
    WORKDIR /tmp
    # 拷贝jdk和java项目的包,这两个文件都在 demo-df 同目录
    COPY ./jdk8.tar.gz $JAVA_DIR/
    # 会将 springboot-demo.jar 复制到容器内 /tmp目录下,并命名为 app.jar
    COPY ./springboot-demo.jar app.jar
    
    # 安装JDK
    RUN cd $JAVA_DIR \
     && tar -xf ./jdk8.tar.gz \
     && mv ./jdk1.8.0_144 ./java8
    
    # 配置环境变量
    ENV JAVA_HOME=$JAVA_DIR/java8
    ENV PATH=$PATH:$JAVA_HOME/bin
    
    # 暴露端口
    EXPOSE 8080
    # 入口,java项目的启动命令
    # 启动应用固定命令
    ENTRYPOINT ["java" , "-jar" ] 
    # 动态传递jar包名,启动容器内 /tmp 目录下的app.jar
    CMD ["app.jar"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 通过dockerfile文件构建镜像
    docker build -f demo-df -t demo:1 .
    
    • 1
    • 运行项目
    docker run -id --name demo1 -p 8080:8080 demo:1
    
    • 1

    3. 基于Jdk8构建Java项目

    虽然我们可以基于Centos基础镜像,添加任意自己需要的安装包,构建镜像,但是却比较麻烦。所以大多数情况下,我们都可以在一些安装了部分软件的基础镜像上做改造。

    例如,构建Java项目的镜像,可以在已经准备了JDK的基础镜像基础上构建。

    需求:基于java:8-alpine镜像,将一个Java项目构建为镜像。

    • 编写 dockerfile 文件 (此处我命名为 demo-df2
    # 指定基础镜像
    FROM java:8-alpine ·
    # 拷贝java项目的包,该文件在 demo-df2 同目录
    # 拷贝到 /tmp/app.jar
    COPY ./springboot-demo.jar /tmp/app.jar
    # 暴露端口
    EXPOSE 8081
    # 入口,java项目的启动命令,启动容器内 /tmp 目录下的app.jar
    ENTRYPOINT java -jar app.jar
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 通过dockerfile文件构建镜像
    docker build -f demo-df2 -t demo2:1 .
    
    • 1
    • 运行项目
    docker run -id --name demo2 -p 8081:8081 demo2:1
    
    • 1

    五、发布镜像到DockerHub

    • DockerHub注册账号

    • 确定账号可以登录

     docker login -u 账号名
    
    • 1

    在这里插入图片描述

    • 在服务器上提交自己的镜像
    docker push 镜像名:tag
    
    • 1

    # 此处我将刚才制作的 Java项目 镜像推送上去
    docker push demo2:1
    
    但是报错
    [root@iZ2vc772r7963j25lx3cusZ test]# docker push demo2:1
    The push refers to repository [docker.io/library/demo2]
    3dba9e1d09df: Preparing 
    35c20f26d188: Preparing 
    c3fe59dd9556: Preparing 
    6ed1a81ba5b6: Preparing 
    a3483ce177ce: Preparing 
    ce6c8756685b: Waiting 
    30339f20ced0: Waiting 
    0eb22bfb707d: Waiting 
    a2ae92ffcd29: Waiting 
    denied: requested access to the resource is denied # 拒绝
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这里大多数是两种原因

    ① docker未登录

    解决方法:docker login

    ② 如果已经登陆了还是报错,应将镜像改到自己账户名下

    在上述制作 demo2 镜像中时,我指定的MAINTAINERtyt ,但是我的DockerHub的账号名为tangyt6

    解决方法:

    1. 将要发布的镜像改到自己账户名下
     docker tag demo2:1 tangyt6/demo2:1
    
    • 1
    1. 再次发布镜像
    docker push tangyt6/demo2:1
    
    [root@iZ2vc772r7963j25lx3cusZ test]# docker push tangyt6/demo2:1
    The push refers to repository [docker.io/tangyt6/demo2]
    3dba9e1d09df: Pushed 
    35c20f26d188: Pushed 
    c3fe59dd9556: Pushed 
    6ed1a81ba5b6: Pushed 
    a3483ce177ce: Pushed 
    ce6c8756685b: Pushed 
    30339f20ced0: Pushed 
    0eb22bfb707d: Pushed 
    a2ae92ffcd29: Pushed 
    1: digest: sha256:6cc28f078ab5f94d9c4178d2c985b402dc40b81d0c3df84a78cb2bda67b53aba size: 2212 
    # 成功
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    六、发布镜像到阿里云

    • 登录阿里云
    • 找到容器镜像服务
    • 创建命名空间

    在这里插入图片描述

    • 创建镜像仓库

    在这里插入图片描述

    在这里插入图片描述

    • 参考官方文档操作即可
      在这里插入图片描述
  • 相关阅读:
    Go 言 Go 语,一文看懂 Go 语言文件操作
    Worthington植物原生质体制备丨纤维素酶方案
    【配准和融合相互作用,交互】
    12-2- DCGAN -简单网络-卷积网络
    【LeetCode题目详解】第九章 动态规划part09 198.打家劫舍 213.打家劫舍II 337.打家劫舍III(day48补)
    Web前端:雇佣全栈开发者有哪些好处?
    余弦距离介绍
    C/C++ 入门(7)vector类(STL)
    Vue列表渲染
    SpringBoot-调用外部接口(三种方式)
  • 原文地址:https://blog.csdn.net/qq_51938362/article/details/127811154