zoukankan      html  css  js  c++  java
  • 4--Docker之Dockerfile镜像定制

    一、Dockerfile 镜像定制的使用

    创建docker镜像的方式有两种:

    1. 手动修改容器内容,然后docker commit提交容器为新的镜像。
    2. 通过在dockerfile中定义一系列的命令和参数构成的脚本,然后这些命令应用于基础镜像,以此添加层,最终生成一个新的镜像。极大的简化了部署工作。

    dockerfile是用来构建docker镜像的文件==>相当于一个脚本,通过dockerfile指令,来构建软件依赖,文件依赖,存储,等等

    构建步骤:

    • 编写一个dockerfile文件
    • docker build 构 建成一个镜像
    • docker run 运行镜像
    • docker push 发布镜像(DockerHub、阿里云镜像仓库)

    1.什么是Dockerfile?

    Dockerfile由一行行命令语句组成,并且支持以#开头的注释行,一般而言,Dockerfile主体内容分为四部分:基础镜像信息,维护者信息,镜像操作指令和容器启动时执行命令。
    Dockerfile以从上而下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM,一个声明以#字符开头则被视为注释,可以在docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。

    注意事项

    由于dockerfile中每一个指令都会建立一层,每一个 RUN 的行为,会新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。(安装包、缓存等)

    Dockerfile 支持 Shell 类的行尾添加 的命令换行方式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。

    2.基础知识

    每个保留关键字(指令)都必须是大写字母
    执行从上到下顺序执行
    用#表示注释
    每一个指令都会创建提交一个新的镜像 层,并提交!

    dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
    docker镜像逐渐成为了企业交付的标准,必须掌握 !

    步骤:开发、部署、运维,缺一不可!

    dockerfile:构建文件,定义了一切步骤,相当于源代码
    dockerimages:通过dockerfile构建生成的镜像,最终发布和运行的产品
    docker容器:容器就是镜像运行起来提供服务的

    3.dockerfile指令说明

    # 1.FROM        #基础镜像,一切从这里构建 
    # 2.USER        #指定容器执行程序的用户身份,默认是 root用户
    # 3.MAINTAINER  #镜像是谁写的,姓名+邮箱 maintainer 
    # 4.RUN         #镜像构建的时候需要运行的命令
    # 5.ADD         #更高级的复制文件,添加宿主机的文件到容器内,还多了一个自动解压的功能
    # 6.WORKDIR     #镜像的工作目录
    # 7.VOLUME      #挂载的目录
    # 8.EXPOSE      #暴露端口配置
    # 9.CMD         #指定容器启动的时候要运行的命令,只有最后一个会生效,可被替代
    # 10.ENTRYPOINT  #入口点,指定容器启动的时候要运行的命令,可以追加命令
    # 11.ONBUILD    #当构建一个被继承dockerfile,这个时候就会运行这个指令,触发指令
    # 12.COPY       #类似ADD,拷贝宿主机的文件到容器内,仅仅是拷贝
    # 13.ENV        #构建的时候设置环境变量
    

    COPY

    copy指令从宿主机复制文件或者目录到新的一层镜像内
    如:
    copy dockerfile.txt /opt
    
    支持多个文件,以及通配符形式的复制,语法要满足Golang的filepath.Match
    copy docker* /tmp/cc?.txt /opt
    
    COPY指令能够保留源文件的元数据,如权限,访问时间等等,这点很重要
    

    ADD

    特性和COPY基本一致,不过多了些功能
    1. 源文件是一个URL,此时dockcer引擎会下载该链接,放入目标路径,且权限自动设为600。若这不是期望结果,还得增加一层RUN指令进行调整
    # ADD dockerfile.gz /home
    # RUN xxx修改命令  
    2. 源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压
    3. 源文件是一个压缩文件,且是gzip,bzip,xz,tar情况,ADD指令会自动解压压缩该文件到没有文件
    

    Dockerfile官方更为推荐使用copy,ADD包含了更多复制的功能,切ADD会使构建缓存失效,导致镜像构建缓慢

    ADD和COPY的区别

    #ADD : 将文件添加至镜像内
    	1、支持自动解压(tar)
    	2、ADD支持远程下载内容到容器内(不支持自动解压)
    
    #COPY:将文件复制到镜像内
    	1、不支持自动解压
    	2、不支持网络下载内容
    

    CMD

    用法,注意是双引号
    # CMD在容器内运行某个命令,启动程序
    # 该镜像在运行容器实例的时候,执行的具体参数是什么
    
    CMD["参数1","参数2"]
    在指定了entrypoint指令后,用CMD指定具体的参数
    
    dokcer不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用
    
    例如centos镜像默认的CMD是/bin/bash,直接docker run -it centos会直接进入bash解释器。
    也可以启动容器时候,指定参数: docker run -it centos cat /etc/os-release
    
    CMD ["/bin/bash"]
    
    # 该容器运行时,执行的命令
    # 等同于命令行的直接操作:docker run -it centos cat /etc/os-release
    CMD ["cat","/etc/os-release"]
    

    容器内运行程序

    这里要注意的是,docker不是虚拟机的概念,虚拟机的程序运行,基本上都是在后台运行,利用systemctl运行,但是容器内没有后台进程的概念,必须在前台运行
    容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。

    例如一个经典的问题:
    # 这样的写法是错误的,容器会立即退出
    CMD systemctl start nginx
    
    因为systemctl start nginx是以守护进程(默认在后台运行)的形式启动nginx,且CMD命令会转化为
    CMD ["sh","-c","systemctl start nginx" ]
    
    这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了。
    
    # 相当于nginx -g daemon off
    因此正确的做法应该是 CMD ["nginx","-g","daemon off;"]
    

    dokcer面试题:
    ENTRYPOINT和CMD的区别以及用法! ! !

    ENTRYPOINT作用和CMD一样,都是在指定容器启动程序以及参数。
    
    当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是把CMD的内容当作参数传递给ENTRYPOINT指令。
    

    CMD和ENIRYPOINT的区别

    CMD #指定容器启动的时候要运行的命令,只有最后一个会 生效,可被替代
    
    ENTRYPOINT #指定容器启动的时候要运行的命令,可以追加命令
    
    #1.测试CMD
    [root@docker dockerfile]# vim dockerfile-cmd-test  #编写dockerfile文件
    FROM centos
    CMD ["ls","-a"]
    [root@docker dockerfile]# docker build -f dockerfile-cmd-test  -t cmdtest .  #构建镜像
    [root@docker dockerfile]# docker run c851cfaf4de4  #运行构建的镜像  (ls -a命令生效)
    .
    ..
    .dockerenv
    bin
    dev
    etc
    home
    lib
    lib64
    lost+found
    media
    mnt
    opt
    proc
    
    #2.想追加一个命令l【ls -al】
    [root@docker dockerfile]# docker run c851cfaf4de4 -l
    docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
    
    注:CMD用-l替换了 ["ls","-a"],然而-l不是命令所以报错
    
    #如果想运行命令要接完整命令
    [root@docker dockerfile]# docker run c851cfaf4de4 ls -al
    total 0
    drwxr-xr-x   1 root root   6 Mar 20 10:02 .
    drwxr-xr-x   1 root root   6 Mar 20 10:02 ..
    -rwxr-xr-x   1 root root   0 Mar 20 10:02 .dockerenv
    lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
    drwxr-xr-x   5 root root 340 Mar 20 10:02 dev
    drwxr-xr-x   1 root root  66 Mar 20 10:02 etc
    drwxr-xr-x   2 root root   6 Nov  3 15:22 home
    
    #1.测试ENTRYPOINT
    [root@docker dockerfile]# vim dockerfile-ENTRYPOINT-test   #编写dockerfile文件
    FROM centos
    ENTRYPOINT ["ls","-a"]
    [root@docker dockerfile]# docker build -f dockerfile-ENTRYPOINT-test  -t entrypointtest .   #构建镜像
    [root@docker dockerfile]# docker run fd149b7d1690   #运行镜像
    .
    ..
    .dockerenv
    bin
    dev
    etc
    home
    lib
    lib64
    lost+found
    
    #2.想追加一个命令-l  【ls -al】
    [root@docker dockerfile]# docker run fd149b7d1690 -l
    total 0
    drwxr-xr-x   1 root root   6 Mar 20 10:07 .
    drwxr-xr-x   1 root root   6 Mar 20 10:07 ..
    -rwxr-xr-x   1 root root   0 Mar 20 10:07 .dockerenv
    lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
    drwxr-xr-x   5 root root 340 Mar 20 10:07 dev
    

    ARG和ENV指令

    • 设置环境变量
    dockerfile脚本,shell脚本
    
    ENV NAME="cdan"
    ENV AGE=28
    ENV MYSQL_VERSION=5.6
    
    后续所有的操作,通过$NAME就可以直接获取变量值使用了,维护dockerfile更加方便
    
    ARG和ENV一样,都是设置环境变量
    ENV无论是在镜像构建时,还是容器运行,该变量都可以使用
    ARG只是用于构建镜像需要设置的变量,容器运行时就消失了
    

    VOLUME

    • 容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。
    VOLUME /data   #== mount /mnt 
    # 将容器内的/data文件夹,在容器运行时,该目录自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储无状态理念。
    
    # Dockerfile
    [root@docker01 ~]# cd /docker/
    [root@docker01 docker]# vim Dockerfile 
    FROM centos
    MAINTAINER cdan
    VOLUME ["/data1","/data2"]
    
    # 该容器运行的时候,这两个目录自动和宿主机的目录做好映射关系
    docker build .
    
    # 运行该镜像
    docker run 86b4dceba89a
    
    # 查看生成的容器信息
    [root@docker01 ~]# docker ps -a | head -2
    CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS                     PORTS     NAMES
    84014622b3a4   86b4dceba89a      "/bin/bash"              2 minutes ago   Exited (0) 2 minutes ago             sharp_noether
    
    # dokcer inspect命令查看
    [root@docker01 docker]# docker inspect 86b4dceba89a
                "Volumes": {
                    "/data1": {},
                    "/data2": {}
                },
    
    1. 容器数据挂载的方式,通过dockerfile,指定VOLUME目录
    2. 通过docker run -v参数,直接设置需要映射挂载的目录
    

    4.通过Dockerfile生成镜像

    #1.创建一个Dockerfile文件,名字必须是Dockerfile(文件中的内容指令大写)
    [root@docker ~]# cd /home
    [root@docker home]# vim dockerfile
    FROM centos
    VOLUME ["volume01","volume02" ]   #匿名挂载
    CMD echo "-----end-----"
    CMD /bin/bash              
    [root@docker home]# docker build -f dockerfile -t test/centos:v1 .   #构建镜像
    Sending build context to Docker daemon  190.8MB
    Step 1/4 : FROM centos
     ---> 300e315adb2f
    Step 2/4 : VOLUME ["volume01","volume02"]
     ---> Running in f0c041664f2f
    Removing intermediate container f0c041664f2f
     ---> 736d765bc692
    Step 3/4 : CMD echo "-----end-----"
     ---> Running in 718ddf9ab2fd
    Removing intermediate container 718ddf9ab2fd
     ---> d7a675f0e939
    Step 4/4 : CMD /bin/bash
     ---> Running in 585894ec73cd
    Removing intermediate container 585894ec73cd
     ---> 3850e269b94a
    Successfully built 3850e269b94a
    Successfully tagged test/centos:v1
    [root@docker home]# docker images  #查看构建镜像
    REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
    test/centos   v1        3850e269b94a   51 seconds ago   209MB
    
    #2.启动自己生成的容器
    [root@docker home]# docker run -it 3850e269b94a /bin/bash
    [root@383339684d3c /]# 
    [root@383339684d3c /]# ls -l   #查看目录
    total 0
    lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
    drwxr-xr-x   5 root root 360 Mar 20 07:09 dev
    drwxr-xr-x   1 root root  66 Mar 20 07:09 etc
    drwxr-xr-x   2 root root   6 Nov  3 15:22 home
    lrwxrwxrwx   1 root root   7 Nov  3 15:22 lib -> usr/lib
    lrwxrwxrwx   1 root root   9 Nov  3 15:22 lib64 -> usr/lib64
    drwx------   2 root root   6 Dec  4 17:37 lost+found
    drwxr-xr-x   2 root root   6 Nov  3 15:22 media
    drwxr-xr-x   2 root root   6 Nov  3 15:22 mnt
    drwxr-xr-x   2 root root   6 Nov  3 15:22 opt
    dr-xr-xr-x 113 root root   0 Mar 20 07:09 proc
    dr-xr-x---   2 root root 162 Dec  4 17:37 root
    drwxr-xr-x  11 root root 163 Dec  4 17:37 run
    lrwxrwxrwx   1 root root   8 Nov  3 15:22 sbin -> usr/sbin
    drwxr-xr-x   2 root root   6 Nov  3 15:22 srv
    dr-xr-xr-x  13 root root   0 Mar 20 07:09 sys
    drwxrwxrwt   7 root root 145 Dec  4 17:37 tmp
    drwxr-xr-x  12 root root 144 Dec  4 17:37 usr
    drwxr-xr-x  20 root root 262 Dec  4 17:37 var
    drwxr-xr-x   2 root root   6 Mar 20 07:09 volume01  #自己挂载的目录(生成镜像自动挂载的数据卷目录)
    drwxr-xr-x   2 root root   6 Mar 20 07:09 volume02  #自己挂载的目录(生成镜像自动挂载的数据卷目录)
    注:这个卷一定和外部有一个同步目录
    
    #3.在容器内挂载目录下创建测试文件
    [root@383339684d3c /]# cd volume01
    [root@383339684d3c volume01]# touch 1.txt
    [root@383339684d3c volume01]# ls
    1.txt
    
    #4.查看容器的具体信息
    [root@docker ~]# docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS       
    383339684d3c   3850e269b94a   "/bin/bash"              4 minutes ago   Up 4 minutes
    [root@docker ~]# docker inspect 383339684d3c
       "Mounts": [
                {
                    "Type": "volume",
                    "Name": "34bbc194a4ba7b7cdc424ba768f89d6437f6be9004ef91e89a205288cfa
                    "Source": "/var/lib/docker/volumes/34bbc194a4ba7b7cdc424ba768f89d643 #对应容器外目录路径
                    "Destination": "volume01",
                    "Driver": "local",
                    "Mode": "",
                    "RW": true,
                    "Propagation": ""
                },
                {
                    "Type": "volume",
                    "Name": "b4f2a3ca38131f0bc8fe55398a9759266f171e02fd8f3ad7813a6889712
                    "Source": "/var/lib/docker/volumes/b4f2a3ca38131f0bc8fe55398a9759266  #对应容器外目录路径
                    "Destination": "volume02",
                    "Driver": "local",
                    "Mode": "",
                    "RW": true,
                    "Propagation": ""
                }
            ],
    
    #5.去容器外看一下创建的测试文件是否同步
    [root@docker ~]# cd /var/lib/docker/volumes/34bbc194a4ba7b7cdc424ba768f89d6437f6be9004ef91e89a205288cfa3aeba/_data
    [root@docker _data]# ls
    1.txt
    

    5.实战测试(构建自己的centos)

    #1.编写dockerfile文件
    mkdir Dockerfile
    [root@docker dockerfile]# vim Dockerfile
    FROM centos
    MAINTAINER dan<757294876@qq.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    RUN yum install -y vim 
    RUN yum install -y net-tools
    
    EXPOSE 80
    
    CMD echo $MYPATH
    CMD echo "----end----"
    CMD /bin/bash
    
    #2.通过文件构建镜像
    [root@docker dockerfile]# docker build -f Dockerfile -t mycentos:v1 .
    Sending build context to Docker daemon  2.048kB 
    Step 1/10 : FROM centos
     ---> 300e315adb2f
    Step 2/10 : MAINTAINER fxs<1353421063@qq.com>
     ---> Running in e52e12575926
    Removing intermediate container e52e12575926
     ---> 4e870718528a
    Step 3/10 : ENV MYPATH /usr/local
     ---> Running in d82fa4ed482b
    Removing intermediate container d82fa4ed482b
     ---> c82eb3e4a162
    Step 4/10 : WORKDIR $MYPATH
     ---> Running in 6f0249f46ab3
    Removing intermediate container 6f0249f46ab3
     ---> 109dee8d18e9
    Step 5/10 : RUN yum install -y vim
     ---> Running in 5560189ef2bf
    CentOS Linux 8 - AppStream                      1.2 MB/s | 6.3 MB     00:05    
    CentOS Linux 8 - BaseOS                         935 kB/s | 2.3 MB     00:02    
    CentOS Linux 8 - Extras                         7.6 kB/s | 9.2 kB     00:01
    
    #3.查看自己创建的镜像
    [root@docker dockerfile]# docker images
    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    mycentos      v1        3f33768da126   2 minutes ago   291MB
    
    #4.运行自己构建的镜像
    [root@docker dockerfile]# docker run -it mycentos:v1
    [root@f9e4e57fdbeb local]# pwd   #自动进入工作目录
    /usr/local
    [root@f9e4e57fdbeb local]# ifconfig   #自己增加的命令可以使用
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
            ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
            RX packets 8  bytes 648 (648.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            loop  txqueuelen 1  (Local Loopback)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
  • 相关阅读:
    Istio技术与实践02:源码解析之Istio on Kubernetes 统一服务发现
    Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制
    深度剖析Kubernetes API Server三部曲
    深度剖析Kubernetes API Server三部曲
    深度剖析Kubernetes API Server三部曲
    深入了解Kubernetes REST API的工作方式
    Cassandra schema version 不一致
    ByteToMessageDecoder
    Byte Bit
    为什么要用Executors.defaultThreadFactory().newThread(run);创建线程?
  • 原文地址:https://www.cnblogs.com/caodan01/p/15078313.html
Copyright © 2011-2022 走看看