zoukankan      html  css  js  c++  java
  • 使用Dockerfile构建自己的镜像

    Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令可以根据Dockerfile里面的指令编排来打包定制我们自己的docker镜像,首先我们来看一个通用的例子,制作自己的nginx镜像。

    1.构建nginx镜像

    # Base image
    FROM centos:7
    
    # MAINTAINER
    MAINTAINER cbmiao <miaocbin@126.com>
    
    # 将nginx以及pcre源代码加入镜像
    ADD nginx-1.20.1.tar.gz /usr/local/src/
    ADD pcre-8.45.tar.gz /usr/local/src/
    
    # 安装编译器
    RUN yum install -y gcc gcc-c++ make openssl-devel lsof
    RUN useradd -s /sbin/nologin -M nginx
    
    # 指定工作目录
    WORKDIR /usr/local/src/nginx-1.20.1/
    
    # 编译nginx
    RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
    RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
    
    # 设置环境变量
    ENV PATH /usr/local/nginx/sbin:$PATH
    
    # 暴露80端口
    EXPOSE 80
    
    # 容器默认启动命令
    ENTRYPOINT ["nginx"]

    以上是通过Dockerfile来定制我们自己的nginx的Dockerfile,包含了如下指令:

    2. Dockerfile基本格式

    2.1 FROM指令

    FROM指令用于指定基础镜像,必须为Dockerfile的第一个指令

    # 格式:
    # FROM <image>
    # FROM <image>:<tag>
    # 示例:
    FROM mysql:5.7
    # 注意:
    # tag是可选的,如果不使用tag,则默认会使用latest版本的基础镜像

    参数解释:

    • FROM mysql:5.7:第一行必须指定 基础镜像信息

    2.2 MAINTAINER 指令

    用于说明镜像维护者的信息,名字,邮箱,联系方式,实例如下

    # 格式:
    # 	MAINTAINER <name>
    # 示例:
    	MAINTAINER Michael Miu
        MAINTAINER miaocbin@126.com
        MAINTAINER Michael Miu <miaocbin@126.com>

    2.3 COPY|ADD指令

    这两个命令的用法类似,都可以用于添加本地文件到镜像中(同样需求下,官方推荐使用 COPY),功能也类似,如:

    • 源路径可以有多个,相对于执行build的路径,如果源路径是一个目录,则该目录下面的所有内容都会被加入到容器,但目录本身不会被加入到容器;
    • 目标路径:必须是绝对路径或者相对于WORKDIR的相对路径;若目标路径不存在,则会自动创建完整路径;目标路径如果是文件夹,则必须已/结尾;
    • 路径中可以使用通配符

    二者区别如下:

    • ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
    • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
    • COPY:指令能够将构建命令所在的主机本地的文件或目录,复制到镜像文件系统。
    • ADD:指令不仅能够将构建命令所在的主机本地的文件或目录,而且能够将远程URL所对应的文件或目录,作为资源复制到镜像文件系统。
      所以,可以认为ADD是增强版的COPY,支持将远程URL的资源加入到镜像的文件系统。
    # 格式:
    # 	ADD|COPY <src>... <dest>
    # 示例:
        ADD|COPY tes* /mydir/    # 添加所有以"tes"开头的文件
        ADD|COPY test mydir/     # 添加 "test" 到 WORKDIR/mydir/
        ADD|COPY test /opt/      # 添加 "test" 到 /opt/
    # [--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

    说明:

    1. 对于从远程URL获取资源的情况,由于ADD指令不支持认证,如果从远程获取资源需要认证,则只能使用RUN wget或RUN curl替代。
    2. 如果源路径的资源发生变化,则该ADD指令将使Docker Cache失效,Dockerfile中后续的所有指令都不能使用缓存。因此尽量将ADD指令放在Dockerfile的后面。
    3. <源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。
    4. <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

    2.4 WORKDIR

    指定工作目录,通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。(WORKDIR 指定的工作目录,必须是提前创建好的)

    # 格式:
    # 	WORKDIR /path/to/workdir
    # 示例:
        WORKDIR /abc  (这时工作目录为/abc)

    2.5 RUN

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

    # 格式:
    # 	RUN <command>
    # 示例:
        RUN yum -y install nginx
        RUN pip install djaong
        RUN mkdir test && rm -rf /var/lib/testfile

    2.6 CMD

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

    • CMD:用于指定在容器启动时所要执行的命令,在docker run 时运行。
    • RUN:RUN用于指定镜像构建时所要执行的命令,是在 docker build时运行。

    作用:为启动的容器指定默认要运行的程序,也就是在容器启动时才进行调用。程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

    # 格式:
    #     CMD ["executable","param1","param2"] (执行可执行文件,优先)
    #     CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    #     CMD command param1 param2 (执行shell内部命令)
    # 示例:
        CMD ["/usr/bin/wc","--help"]
        CMD ping www.baidu.com

    注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

    2.7 ENTRYPOINT

    类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。

    # 格式:
    #     ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
    #     ENTRYPOINT command param1 param2 (shell内部命令)
    # 示例:
        ENTRYPOINT ["/usr/bin/wc","--help"]

    注意:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。

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

    注意:Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。

    2.8 ENV

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

    # 格式:
    #     ENV <key> <value>
    #     ENV <key>=<value>
    # 示例:
        ENV myName John
        ENV myCat=tomcat

    2.9 EXPOSE指令

    声明端口,作用如下:

    • 1)帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
    • 2)在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口;但是,EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。
    • 3)docker ps的时候看到的PORTS字段信息就是这里声明的信息;
    • 4)需要说明的是,即便这里不写EXPOSE指令,也不影响镜像构建和运行,只是会导致其他的使用者不清楚镜像监听的端口,使用的时候映射端口没有那么直观。
    # 格式:
    #     EXPOSE <port> [<port>...]
    # 示例:
        EXPOSE 80 443
        EXPOSE 8080
        EXPOSE 11211/tcp 11211/udp

    2.10 LABEL指令

    用来给镜像添加一些元数据(metadata),以键值对的形式

    # 语法格式:
    # LABEL <key>=<value> <key>=<value> <key>=<value> ...
    # 例如:添加镜像作者
    LABEL org.opencontainers.image.authors="runoob"

    2.11 VOLUME指令

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

    • 避免重要的数据,因容器重启而丢失,这是非常致命的。
    • 避免容器不断变大。
    # 格式:
    # 	VOLUME ["<路径1>", "<路径2>"...]
    # 	VOLUME <路径>
    # 举例:
    VOLUME [/var/lib/mysql]

    3. Dockerfile镜像构建命令

    利用Dockerfile构建自己的镜像命令

    docker build . -t ImageName:ImageTag -f Dockerfile
    • . 是上下文路径
    • 上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

    解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

    如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

    注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

    3.1 执行构建过程

    docker build . -t my-nginx:v1.20.1 -f Dockerfile
    
    Sending build context to Docker daemon  3.163MB
    Step 1/13 : FROM centos:7
     ---> 8652b9f0cb4c
    Step 2/13 : LABEL maintainer="cbmiao <miaocbin@126.com>"
     ---> Using cache
     ---> 16c2487146bc
    Step 3/13 : ENV DEBIAN_FRONTEND noninteractive
     ---> Using cache
     ---> 5f3132177398
    Step 4/13 : ADD nginx-1.20.1.tar.gz /usr/local/src/
     ---> Using cache
     ---> 116344a28ea2
    Step 5/13 : ADD pcre-8.45.tar.gz /usr/local/src
     ---> Using cache
     ---> 23451b87c29b
    Step 6/13 : RUN yum install -y wget gcc gcc-c++ make openssl-devel
     ---> Using cache
     ---> dcaa1cbaf4bd
    Step 7/13 : RUN useradd -s /sbin/nologin -M nginx
     ---> Using cache
     ---> e0ace7f20ffc
    Step 8/13 : WORKDIR /usr/local/src/nginx-1.20.1/
     ---> Using cache
     ---> d437722febe2
    Step 9/13 : RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45 && make && make install
     ---> Using cache
     ---> 307b6228d110
    Step 10/13 : RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
     ---> Using cache
     ---> dc8e0e800987
    Step 11/13 : ENV PATH /usr/local/nginx/sbin:$PATH
     ---> Using cache
     ---> e5a1119dced2
    Step 12/13 : EXPOSE 80
     ---> Using cache
     ---> 63c669be20e4
    Step 13/13 : ENTRYPOINT ["nginx"]
     ---> Using cache
     ---> 391f75b825bd
    Successfully built 391f75b825bd
    Successfully tagged my-nginx:v1.20.1

    3.2 查看构建结果

    docker image ls
    REPOSITORY                TAG       IMAGE ID       CREATED          SIZE
    my-nginx                  v1.20.1   391f75b825bd   17 minutes ago   490MB

    3.3 运行镜像

    # 利用我们刚构建的镜像来启动容器
    docker run -d --name nginx-test my-nginx:v1.20.1
    348a73f420181c36abf7a99c958ed76862503e930793331ab819629ea2bdc4a2
    
    # 进入容器查看nginx状态
    docker exec -ti nginx-test bash
    [root@348a73f42018 nginx-1.20.1]#
    
    # 确认80端口
    [root@348a73f42018 nginx-1.20.1]# lsof -i :80
    COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    nginx     1 root    6u  IPv4 645923      0t0  TCP *:http (LISTEN)
    # 确认nginx进程已经启动成功
    [root@348a73f42018 nginx-1.20.1]# ps aux
    USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root          1  0.1  0.0  46096  3280 ?        Ss   05:43   0:00 nginx: master process nginx
    nginx         7  0.0  0.0  46532  1880 ?        S    05:43   0:00 nginx: worker process
    root          8  0.2  0.0  11828  1908 pts/0    Ss   05:43   0:00 bash
    root         26  0.0  0.0  51732  1712 pts/0    R+   05:43   0:00 ps aux
    # 访问nginx也正常
    [root@348a73f42018 nginx-1.20.1]# curl localhost 
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
             35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

    若想让我们的nginx向外提供服务,还需要在启动容器时,将端口映射到主机,然后我们通过主机IP加上映射端口,就可以访问了

    docker run -d --name nginx-test1 -p 80:80 my-nginx:v1.20.1

    以上就添加了一个[-p 80:80]参数,将容器内的nginx的80端口,映射到宿主机。然后我们就可以通过宿主机的IP加上80端口访问刚才启动的nginx容器里的nginx服务,有关docker启动容器有不清楚的,可以看我的另外一篇博客:Docker简介及基本使用

    4. Dockerfile构建镜像的原则

    • 不必要的内容不要放在镜像中:以免增大镜像,同时也带来安全隐患;

    • 减少不必要的层文件

    • 减少网络传输操作:尽量使用本地文件,加快镜像构建速度,特别是后面我们将利用Jenkins做自动化构建的时候;

    • 可以适当的包含一些调试命令

    5. JAR包制作成docker镜像实例

    FROM java:8u211
    
    ENV JAVA_OPTS "
    -Xmx4096m 
    -XX:MetaspaceSize=256m 
    -XX:MaxMetaspaceSize=256m"
    ENV JAVA_HOME /usr/local/java
    ENV PATH ${PATH}:${JAVA_HOME}/bin
    
    COPY target/myweb.jar myweb.jar
    
    RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    RUN echo 'Asia/Shanghai' >/etc/timezone
    
    EXPOSE 8080
    CMD java ${JAVA_OPTS} -jar myweb.jar

    人们永远没有足够的时间把它做好,但永远有足够的时间重新来过。 可是,因为并不是总有机会重做一遍,你必须做得更好,换句话说, 人们永远没有足够的时间去考虑到底是不是想要它,但永远有足够的时间去为之后悔。 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ 浅掘千口井,不如深挖一口井!当知识支撑不了野心时,那就静下心来学习吧!运维技术交流QQ群:618354452

    个人微信公众号,定期发布技术文章和运维感悟。欢迎大家关注交流。

  • 相关阅读:
    poj 1113 Wall 凸包的应用
    NYOJ 78 圈水池 (入门级凸包)
    Monotone Chain Convex Hull(单调链凸包)
    poj Sudoku(数独) DFS
    poj 3009 Curling 2.0(dfs)
    poj 3083 Children of the Candy Corn
    Python join()方法
    通过FISH和下一代测序检测肺腺癌ALK基因融合比较
    华大病原微生物检测
    NGS检测ALK融合大起底--转载
  • 原文地址:https://www.cnblogs.com/miaocbin/p/15245836.html
Copyright © 2011-2022 走看看