企业运维容器之 docker 镜像

企业运维容器之 docker 镜像

    • 1. 镜像的分层结构
    • 2. 镜像的构建
    • 3. Dockerfile
    • 4. 镜像的优化
    • 5. 总 结

1. 镜像的分层结构

  • 共享宿主机的kernel
  • base 镜像提供的是最小的 Linux 发行版;
  • 同一docker主机支持运行多种 Linux 发行版;
  • 采用分层结构的最大好处是:共享资源

企业运维容器之 docker 镜像_第1张图片

  • Copy-on-Write 可写容器层,相当于虚拟机的快照;
  • 容器层以下所有镜像层都是只读的;
  • docker从上往下依次查找文件;
  • 容器层保存镜像变化的部分,并不会对镜像本身进行任何修改;
  • 一个镜像最多127层;

2. 镜像的构建

  1. docker commit 构建新镜像三部曲
    运行容器
    修改容器
    将容器保存为新的镜像

缺点
效率低、可重复性弱、容易出错;
使用者无法对镜像进行审计,存在安全隐患.

  1. 构建镜像
[root@server1 ~]# docker pull busybox		##拉取镜像
Using default tag: latest
latest: Pulling from library/busybox
92f8b3f0730f: Pull complete 
Digest: sha256:b5fc1d7b2e4ea86a06b0cf88de915a2c43a99a00b6b3c0af731e5f4c07ae8eff
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
[root@server1 ~]# docker images		##查看镜像
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
busybox              latest              d3cd072556c2        4 days ago          1.24MB
yakexi007/game2048   latest              19299002fdbe        4 years ago         55.5MB

[root@server1 ~]# docker history busybox:latest 	
##查看镜像的构建历史,可以看到其分层结构;一层是官网信息,另外一层是得到一个shell 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
d3cd072556c2        4 days ago          /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           4 days ago          /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB              

[root@server1 ~]# docker run -it --name demo busybox		
##以交互模式来打开容器,获得一个 shell 
/ # uname -r 
3.10.0-957.el7.x86_64
/ # free -m
              total        used        free      shared  buff/cache   available
Mem:           3950         242        2977           0         730        3463
Swap:          2047           0        2047
/#

ctrl +d来退出,退出直接就关闭了docker ;用 ctrl+p+q 来将其打入后台运行;

[root@server1 ~]# docker run -it --name demo busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # touch zxk1
/ # touch zxk2
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var   zxk1  zxk2
/ # 		##此处用 ctrl +d 来退出之后,容器就被关闭了
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@server1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
4c28320d96c6        busybox             "sh"                27 seconds ago      Exited (0) 11 seconds ago                       demo
[root@server1 ~]# docker start demo		##可以用 start 来开启容器;
demo
[root@server1 ~]# docker attach demo		##然后用 attach 来进入容器
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var   zxk1  zxk2
/ # 

用参数ctrl +p +q 退出之后,是将容器打入后台继续在运行;

[root@server1 ~]# docker attach demo
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var   zxk1  zxk2
/ # touch zxkfile1
/ # touch zckfile2
/ # ls
bin       etc       proc      sys       usr       zckfile2  zxk2
dev       home      root      tmp       var       zxk1      zxkfile1
/ # read escape sequence
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
4c28320d96c6        busybox             "sh"                3 minutes ago       Up 2 minutes                            demo

运行的容器是能分配到 IP 的,可以用命令 docker inspect demo` 来查看运行容器的 IP ;此 IP 是桥接的方式和主机进行连接的;

[root@server1 ~]# docker inspect demo

            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",

[root@server1 ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.180 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.050 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.050/0.115/0.180/0.065 ms

对于桥接的查看可以下载一个工具包来进行查看;

[root@server1 ~]# yum install bridge-utils.x86_64 -y		##下载来查看桥接的状态

[root@server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.024226b06bff	no		veth8a55abb
[root@server1 ~]# docker stop demo
demo
[root@server1 ~]# brctl show		
##当容器关闭后,此时资源就被释放,当别的容器再次运行时,便会依次获得IP
bridge name	bridge id		STP enabled	interfaces
docker0		8000.024226b06bff	no	

对于容器的删除:
刚刚的只是停掉了容器,但容器还在;可以将其不需要的容器删除;

[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@server1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
4c28320d96c6        busybox             "sh"                17 minutes ago      Exited (137) 2 minutes ago                       demo
[root@server1 ~]# docker rm demo		##删除没有运行的容器
demo
[root@server1 ~]# docker ps		##查看运行的容器
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@server1 ~]# docker ps -a		##查看所有的容器
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

当容器删除之后,此时之前新建的文件时在容器层,此时再次开启镜像,但是看不到之前的信息;

[root@server1 ~]# docker run -it --name demo busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # touch 111		##修改容器
/ # touch 222
/ # ls
111   222   bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # 
[root@server1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
4f26670e58f0        busybox             "sh"                43 seconds ago      Exited (0) 17 seconds ago                       demo
[root@server1 ~]# docker commit --help

Usage:	docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

Options:
  -a, --author string    Author (e.g., "John Hannibal Smith ")
  -c, --change list      Apply Dockerfile instruction to the created image
  -m, --message string   Commit message
  -p, --pause            Pause container during commit (default true)
[root@server1 ~]# docker commit -m "add file" demo busybox:v1		##将容器保存为新的镜像
sha256:ec156da5008793b690ab6b9859daa4074e24d04bcc9302b27a2095f74e0e6182
[root@server1 ~]# docker images		##查看镜像
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
busybox              v1                  ec156da50087        11 seconds ago      1.24MB
busybox              latest              d3cd072556c2        6 days ago          1.24MB
yakexi007/game2048   latest              19299002fdbe        4 years ago         55.5MB
[root@server1 ~]# docker history busybox:latest
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
d3cd072556c2        6 days ago          /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           6 days ago          /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB              
[root@server1 ~]# docker history busybox:v1		##查看构建历史
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
ec156da50087        33 seconds ago      sh  ##此处别人不知道做了什么,存在安全隐患                                            26B                 add file
d3cd072556c2        6 days ago          /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           6 days ago          /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB  
[root@server1 ~]# docker rm demo		##删除之前的容器
demo
[root@server1 ~]# docker run -it --name demo busybox:v1	##对新打包的镜像运行
/ # ls
111   222   bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # 
[root@server1 ~]# docker rm demo
demo
[root@server1 ~]# docker run -it --name demo busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # 

3. Dockerfile

上面的方式构建的镜像存在一定的安全隐患,因为别人无法从构建历史中知道做了那些事。

dockerfile常用指令

  • FROM
    指定base镜像,如果本地不存在会从远程仓库下载。
  • MAINTAINER
    设置镜像的作者,比如用户邮箱等。
  • COPY
    把文件从build context复制到镜像
    支持两种形式:COPY src dest 和 COPY [“src”, “dest”]
    src必须指定build context中的文件或目录
  • ADD
    用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
    ADD html.tar /var/www
    ADD http://ip/html.tar /var/www
  • ENV
    设置环境变量,变量可以被后续的指令使用:
    ENV HOSTNAME sevrer1.example.com
  • EXPOSE
    如果容器中运行应用服务,可以把服务端口暴露出去:
    EXPOSE 80
  • VOLUME
    申明数据卷,通常指定的是应用的数据挂在点:
    VOLUME ["/var/www/html"]
  • WORKDIR
    为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
  • RUN
    在容器中运行命令并创建新的镜像层,常用于安装软件包:
    RUN yum install -y vim

创建 Dockerfile 文件
创建一个空目录,然后在空目录中创建 Dockerfile 文件;

COPY:用于当前目录,不能指定为根目录。

[root@server1 ~]# mkdir docker
[root@server1 ~]# cd docker/
[root@server1 docker]# ls
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM busybox		##指定镜像,如果不存在会从远程仓库下载
COPY index.html /		##把文件从复制到镜像
[root@server1 docker]# echo www.westos.org > index.html

[root@server1 docker]# docker build -t busybox:v2 .		##构建镜像
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM busybox
 ---> d3cd072556c2
Step 2/2 : COPY index.html /
 ---> bac12c96f3cf
Successfully built bac12c96f3cf
Successfully tagged busybox:v2
[root@server1 docker]# docker history busybox:v2 	
##用 Dockerfile 文件构建镜像的过程会有详细的过程
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
bac12c96f3cf        About a minute ago   /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
d3cd072556c2        4 days ago           /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           4 days ago           /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB              

RUN

[root@server1 docker]# vim Docker        
[root@server1 docker]# cat Dockerfile 
FROM busybox
COPY index.html /
RUN touch testfile	##在容器中运行命令并创建新的镜像层,常用于安装软件包	
[root@server1 docker]# docker build -t busybox:v3 .
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM busybox
 ---> d3cd072556c2
Step 2/3 : COPY index.html /
 ---> Using cache
 ---> bac12c96f3cf
Step 3/3 : RUN touch testfile
 ---> Running in 1a97d38ee1dc
Removing intermediate container 1a97d38ee1dc
 ---> af6759a259ae
Successfully built af6759a259ae
Successfully tagged busybox:v3
[root@server1 docker]# docker history busybox:v3
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
af6759a259ae        3 seconds ago       /bin/sh -c touch testfile                       0B                  
bac12c96f3cf        2 minutes ago       /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
d3cd072556c2        4 days ago          /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           4 days ago          /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB              

ADD

[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM busybox
COPY index.html /
RUN touch testfile
ADD nginx-1.18.0.tar.gz /
[root@server1 docker]# ls
Dockerfile  index.html  nginx-1.18.0.tar.gz
[root@server1 docker]# docker build -t busybox:v4 .
Sending build context to Docker daemon  1.043MB
Step 1/4 : FROM busybox
 ---> d3cd072556c2
Step 2/4 : COPY index.html /
 ---> Using cache
 ---> bac12c96f3cf
Step 3/4 : RUN touch testfile
 ---> Using cache
 ---> af6759a259ae
Step 4/4 : ADD nginx-1.18.0.tar.gz /
 ---> 4a5ec9658a0a
Successfully built 4a5ec9658a0a
Successfully tagged busybox:v4
[root@server1 docker]# docker history busybox:v4
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
4a5ec9658a0a        About a minute ago   /bin/sh -c #(nop) ADD file:46b14d1c307d23f50…   6.25MB              
af6759a259ae        8 minutes ago        /bin/sh -c touch testfile                       0B                  
bac12c96f3cf        10 minutes ago       /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
d3cd072556c2        4 days ago           /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           4 days ago           /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB
[root@server1 docker]# docker run --rm busybox:v4 ls		##--rm 表示运行完后直接回收掉容器
bin
dev
etc
home
index.html
nginx-1.18.0	##当前目录生成解压文件
proc
root
sys
testfile
tmp
usr
var

ENV、EXPOSE 、VOLUME

[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM busybox
COPY index.html /
RUN touch testfile
ADD nginx-1.18.0.tar.gz /mnt
ENV HOSTNAME server1
EXPOSE 22
VOLUME ["/data"]		##挂载
[root@server1 docker]# docker build -t busybox:v6 .
Sending build context to Docker daemon  1.043MB
Step 1/7 : FROM busybox
 ---> d3cd072556c2
Step 2/7 : COPY index.html /
 ---> Using cache
 ---> bac12c96f3cf
Step 3/7 : RUN touch testfile
 ---> Using cache
 ---> af6759a259ae
Step 4/7 : ADD nginx-1.18.0.tar.gz /mnt
 ---> Using cache
 ---> 2bd486599e5d
Step 5/7 : ENV HOSTNAME server1
 ---> Running in 585940a17fef
Removing intermediate container 585940a17fef
 ---> 815841bf0454
Step 6/7 : EXPOSE 22
 ---> Running in 020e1555035d
Removing intermediate container 020e1555035d
 ---> bf1c448c8e88
Step 7/7 : VOLUME ["/data"]
 ---> Running in e752fadafca6
Removing intermediate container e752fadafca6
 ---> 079d588ee2b0
Successfully built 079d588ee2b0
Successfully tagged busybox:v6
[root@server1 docker]# docker history busybox:v6
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
079d588ee2b0        17 seconds ago      /bin/sh -c #(nop)  VOLUME [/data]               0B                  
bf1c448c8e88        17 seconds ago      /bin/sh -c #(nop)  EXPOSE 22                    0B                  
815841bf0454        17 seconds ago      /bin/sh -c #(nop)  ENV HOSTNAME=server1         0B                  
2bd486599e5d        3 minutes ago       /bin/sh -c #(nop) ADD file:46b14d1c307d23f50…   6.25MB              
af6759a259ae        13 minutes ago      /bin/sh -c touch testfile                       0B                  
bac12c96f3cf        15 minutes ago      /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
d3cd072556c2        4 days ago          /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           4 days ago          /bin/sh -c #(nop) ADD file:c423dc64e02718dd3…   1.24MB              
[root@server1 docker]# docker run -it --rm busybox:v6 env		##查询变量
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=server1
TERM=xterm
HOME=/root
[root@server1 docker]# docker run -it --rm busybox:v6 
/ # cd /data/
/data # ls
/data # touch file1
/data # ls
file1
/data # [root@server1 docker]# docker ps		##此时可以看到暴露的端口号
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
89b679669449        busybox:v6          "sh"                46 seconds ago      Up 45 seconds       22/tcp              quirky_buck

[root@server1 docker]# docker inspect quirky_buck	
##此名称为 ps 后看到的结果,用此命令可以看到挂载
[root@server1 docker]# cd /var/lib/docker/volumes/f3890ceefa0cf175ba9477be8dc027fcbac07e83237ac0183e5cac034eafca8d/_data
[root@server1 _data]# ls		##在挂载中可以看到其容器中新建的文件
file1
[root@server1 _data]# rm -fr file1 
[root@server1 _data]# ls
[root@server1 _data]# touch file2	##在该目录中修改文件
[root@server1 _data]# ls
file2
[root@server1 _data]# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
89b679669449        busybox:v6          "sh"                4 minutes ago       Up 4 minutes        22/tcp              quirky_buck
[root@server1 _data]# docker attach 89b679669449	##也可以用ID加进取,可以看到其修改后的文件信息
/data # ls
file2
/data # 

WORKDIR

[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM busybox
COPY index.html /
RUN touch testfile
ADD nginx-1.18.0.tar.gz /mnt
ENV HOSTNAME server1
EXPOSE 22
VOLUME ["/data"]
WORKDIR /nginx-1.18.0.tar.gz		##指定进入容器所在目录
[root@server1 docker]# docker build -t busybox:v7 .
Sending build context to Docker daemon  1.043MB
Step 1/8 : FROM busybox
 ---> d3cd072556c2
Step 2/8 : COPY index.html /
 ---> Using cache
 ---> bac12c96f3cf
Step 3/8 : RUN touch testfile
 ---> Using cache
 ---> af6759a259ae
Step 4/8 : ADD nginx-1.18.0.tar.gz /mnt
 ---> Using cache
 ---> 2bd486599e5d
Step 5/8 : ENV HOSTNAME server1
 ---> Using cache
 ---> 815841bf0454
Step 6/8 : EXPOSE 22
 ---> Using cache
 ---> bf1c448c8e88
Step 7/8 : VOLUME ["/data"]
 ---> Using cache
 ---> 079d588ee2b0
Step 8/8 : WORKDIR /nginx-1.18.0.tar.gz
 ---> Running in 99fe5b85b0df
Removing intermediate container 99fe5b85b0df
 ---> 469584a6752f
Successfully built 469584a6752f
Successfully tagged busybox:v7
[root@server1 docker]# docker run -it --rm busybox:v7
/nginx-1.18.0.tar.gz # ls
/nginx-1.18.0.tar.gz # 
  • CMD 与 ENTRYPOINT
    这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
    docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
    Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

  • Shell和exec格式的区别
    #cat Dockerfile
    FROM busybox
    ENV name world
    CMD echo “hello, $name”

  • Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会:
    #cat Dockerfile
    FROM busybox
    ENV name world
    ENTRYPOINT ["/bin/echo", “hello, $name”]

  • 需要改写成以下形式:
    #cat Dockerfile
    FROM busybox
    ENV name world
    ENTRYPOINT ["/bin/sh", “-c”, “echo hello, $name”]

  • Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
    #cat Dockerfile
    FROM busybox
    ENTRYPOINT ["/bin/echo", “hello”]
    CMD [“world”]

  • 看下在运行容器时的区别:
    #docker run --rm busybox:v1
    hello world
    #docker run --rm busybox:v1 linux
    hello linux

官方推荐使用exec格式书写

[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM busybox
COPY index.html /
RUN touch testfile
ADD nginx-1.18.0.tar.gz /mnt
ENV HOSTNAME server1
EXPOSE 22
VOLUME ["/data"]
WORKDIR /nginx-1.18.0.tar.gz
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]
[root@server1 docker]# docker build -t busybox:v8 .
Sending build context to Docker daemon  1.043MB
Step 1/10 : FROM busybox
 ---> d3cd072556c2
Step 2/10 : COPY index.html /
 ---> Using cache
 ---> bac12c96f3cf
Step 3/10 : RUN touch testfile
 ---> Using cache
 ---> af6759a259ae
Step 4/10 : ADD nginx-1.18.0.tar.gz /mnt
 ---> Using cache
 ---> 2bd486599e5d
Step 5/10 : ENV HOSTNAME server1
 ---> Using cache
 ---> 815841bf0454
Step 6/10 : EXPOSE 22
 ---> Using cache
 ---> bf1c448c8e88
Step 7/10 : VOLUME ["/data"]
 ---> Using cache
 ---> 079d588ee2b0
Step 8/10 : WORKDIR /nginx-1.18.0.tar.gz
 ---> Using cache
 ---> 469584a6752f
Step 9/10 : ENTRYPOINT ["/bin/echo","hello"]
 ---> Running in 9eb5b2461081
Removing intermediate container 9eb5b2461081
 ---> 3dd02e78d687
Step 10/10 : CMD ["world"]
 ---> Running in 4c2b4bf52610
Removing intermediate container 4c2b4bf52610
 ---> 9e88acbedae1
Successfully built 9e88acbedae1
Successfully tagged busybox:v8
[root@server1 docker]# docker run -it --rm busybox:v8
hello world
[root@server1 docker]# docker run -it --rm busybox:v8  zxk
hello zxk
[root@server1 docker]# docker run -it --rm busybox:v8  westos
hello westos

4. 镜像的优化

  • 选择最精简的基础镜像;
  • 减少镜像的层数;
  • 清理镜像构建的中间产物;
  • 注意优化网络请求;
  • 尽量去用构建缓存;
  • 使用多阶段构建镜像;

例子

尝试创建一个 Nginx 的镜像,这里使用精简版的 RHEL7 作为 base 镜像;

[root@server1 ~]# ls
docker  rhel7.tar
[root@server1 ~]# docker load -i rhel7.tar 		##导入镜像
e1f5733f050b: Loading layer  147.1MB/147.1MB
[root@server1 ~]# docker images 
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
<none>               <none>              1ae02957d153        About an hour ago   7.49MB
yakexi007/game2048   latest              19299002fdbe        4 years ago         55.5MB
rhel7                latest              0a3eb3fde7fd        6 years ago         140MB
[root@server1 docker]# ls
Dockerfile  dvd.repo  index.html  nginx-1.18.0.tar.gz
[root@server1 docker]# cat dvd.repo
[dvd]
name=rhel7.6
baseurl=http://172.25.25.250/rhel7.6
gpgcheck=0
[root@server1 docker]# cat Dockerfile
FROM rhel7
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt/
WORKDIR /mnt/nginx-1.18.0
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel
RUN ./configure --prefix=/usr/local/nginx
RUN make
RUN make install
COPY index.html /usr/local/nginx/html
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@server1 docker]# docker build -t rhel7:v1 .	
	##构建镜像
[root@server1 docker]# docker images rhel7	
	##可以看到新构建出来的镜像比较大
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7               v1                  fffa388c2f85        45 seconds ago      296MB
rhel7               latest              0a3eb3fde7fd        6 years ago         140MB
[root@server1 docker]# docker run -d --name nginx rhel7:v1		
	##运行容器
c518fc1078acf7a8bca3b2c2dede4a17c42c80b5c6ff83edce323044294f5e18
[root@server1 docker]# docker ps		
	##能运行起来说明没有问题
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
36b62af6ee1c        rhel7:v1            "/usr/local/nginx/sb…"   11 seconds ago      Up 10 seconds       80/tcp              nginx
[root@server1 docker]# docker inspect nginx 		##容器运行之后会获得一个IP

                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }

[root@server1 docker]# curl 172.17.0.2		##测试
www.westos.org

优化一:减少镜像层数,清理镜像构建的中间产物

[root@server1 docker]# docker history rhel7:v1 	
	##优化之前查看其镜像层
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
fffa388c2f85        4 minutes ago       /bin/sh -c #(nop)  CMD ["/usr/local/nginx/sb…   0B                  
bc7b1152962c        4 minutes ago       /bin/sh -c #(nop)  EXPOSE 80                    0B                  
e4255b736ea2        4 minutes ago       /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
f4372157f041        4 minutes ago       /bin/sh -c make install                         3.88MB              
c82e12550cac        4 minutes ago       /bin/sh -c make                                 12.4MB              
6d042420eb1d        4 minutes ago       /bin/sh -c ./configure --prefix=/usr/local/n…   71.7kB              
0a26b8674cb6        6 minutes ago       /bin/sh -c rpmdb --rebuilddb && yum install …   133MB               
8c2017ec9956        7 minutes ago       /bin/sh -c #(nop) WORKDIR /mnt/nginx-1.18.0     0B                  
4086ae26148a        7 minutes ago       /bin/sh -c #(nop) ADD file:46b14d1c307d23f50…   6.25MB              
18246b081767        7 minutes ago       /bin/sh -c #(nop) COPY file:5ec2460d7fc0badb…   67B                 
0a3eb3fde7fd        6 years ago                                                         140MB               Imported from -
[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM rhel7
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt/
WORKDIR /mnt/nginx-1.18.0
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.18.0 && yum clean all
COPY index.html /usr/local/nginx/html
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@server1 docker]# docker build -t rhel7:v2 .
[root@server1 docker]# docker images rhel7
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7               v2                  45d788701ce8        35 seconds ago      255MB
rhel7               v1                  fffa388c2f85        48 minutes ago      296MB
rhel7               latest              0a3eb3fde7fd        6 years ago         140MB

[root@server1 docker]# docker history rhel7:v2	
	##优化之后查看其镜像层
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
45d788701ce8        About a minute ago   /bin/sh -c #(nop)  CMD ["/usr/local/nginx/sb…   0B                  
46a3d583baa3        About a minute ago   /bin/sh -c #(nop)  EXPOSE 80                    0B                  
571b111ea252        About a minute ago   /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
a4605bef525d        About a minute ago   /bin/sh -c rpmdb --rebuilddb && yum install …   108MB               
8c2017ec9956        52 minutes ago       /bin/sh -c #(nop) WORKDIR /mnt/nginx-1.18.0     0B                  
4086ae26148a        52 minutes ago       /bin/sh -c #(nop) ADD file:46b14d1c307d23f50…   6.25MB              
18246b081767        52 minutes ago       /bin/sh -c #(nop) COPY file:5ec2460d7fc0badb…   67B                 
0a3eb3fde7fd        6 years ago                                                          140MB               Imported from -

优化二:使用多阶段构建镜像
在构建NGINX时我们只需要的是Nginx的二进制文件, 中途为了编译而安装的依赖以及编译中产生的内容其实在服务中都没有用到;
采用多阶段构建的方法,创建一个临时镜像用于编译,将编译好的二进制文件拷贝到最终要创建的镜像。

[root@server1 docker]# vim Dockerfile 
[root@server1 docker]# cat Dockerfile 
FROM rhel7 as build
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt/
WORKDIR /mnt/nginx-1.18.0
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.18.0 && yum clean all

FROM rhel7
COPY --from=build /usr/local/nginx	/usr/local/nginx
COPY index.html /usr/local/nginx/html
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@server1 docker]# docker build -t rhel7:v3 .

查看构建完成的大小为141M, 仅比base镜像大了1M而已。

[root@server1 docker]# docker images rhel7
		##查看最新构建出来的大小
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7               v3                  8c8a22458c17        25 seconds ago      141MB
rhel7               v2                  45d788701ce8        4 minutes ago       255MB
rhel7               v1                  fffa388c2f85        53 minutes ago      296MB
rhel7               latest              0a3eb3fde7fd        6 years ago         140MB
[root@server1 docker]# docker history rhel7:v3
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
8c8a22458c17        50 seconds ago      /bin/sh -c #(nop)  CMD ["/usr/local/nginx/sb…   0B                  
fa842e59a5ed        50 seconds ago      /bin/sh -c #(nop)  EXPOSE 80                    0B                  
9ac15082bdda        50 seconds ago      /bin/sh -c #(nop) COPY file:89a58ee0b2565a73…   15B                 
bd2144a4860b        50 seconds ago      /bin/sh -c #(nop) COPY dir:e5b2163c7ba7dfad7…   851kB               
0a3eb3fde7fd        6 years ago                                                         140MB               Imported from -

优化三:选择最精简的基础镜像
如果还需要进一步的优化,此处我们选择更加精简的基础镜像;

[root@server1 ~]# ls
base-debian10.tar  docker  rhel7.tar
[root@server1 ~]# docker load -i base-debian10.tar 	##导入镜像
[root@server1 ~]# docker images 		
	##可以看到其只有 19.2M
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
rhel7                             v3                  8c8a22458c17        7 minutes ago       141MB
rhel7                             v2                  45d788701ce8        12 minutes ago      255MB
rhel7                             v1                  fffa388c2f85        About an hour ago   296MB
<none>                            <none>              1ae02957d153        2 hours ago         7.49MB
yakexi007/game2048                latest              19299002fdbe        4 years ago         55.5MB
rhel7                             latest              0a3eb3fde7fd        6 years ago         140MB
gcr.io/distroless/base-debian10   latest              d48fcdd54946        51 years ago        19.2MB

对于刚才构建的镜像,可以查看其大小以及运行过程调用的资源;

[root@server1 ~]# docker run -it --rm rhel7:v3 bash
bash-4.2# cd /usr/local/nginx/
bash-4.2# ls
conf  html  logs  sbin
bash-4.2# du -sh
876K	.
bash-4.2# cd sbin/
bash-4.2# ls
nginx
bash-4.2# ldd nginx 		##调用系统的库函数
	linux-vdso.so.1 =>  (0x00007ffdbe7c2000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f9aabde3000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9aabbc7000)
	libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f9aab990000)
	libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f9aab72f000)
	libz.so.1 => /lib64/libz.so.1 (0x00007f9aab519000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f9aab158000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9aabfe7000)
	libfreebl3.so => /lib64/libfreebl3.so (0x00007f9aaaed9000)
bash-4.2# 

使用官方镜像的Dockfile 来构建新的镜像;

[root@server1 ~]# cd docker/
[root@server1 docker]# mkdir new
[root@server1 docker]# cd new/
[root@server1 new]# docker pull nginx		
	##拉取最新版的镜像
[root@server1 new]# vim Dockerfile
[root@server1 new]# cat Dockerfile 		
	##内容为从官方复制而来
FROM nginx as base

#https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE

RUN mkdir -p /opt/var/cache/nginx && \
    cp -a --parents /usr/lib/nginx /opt && \
    cp -a --parents /usr/share/nginx /opt && \
    cp -a --parents /var/log/nginx /opt && \
    cp -aL --parents /var/run /opt && \
    cp -a --parents /etc/nginx /opt && \
    cp -a --parents /etc/passwd /opt && \
    cp -a --parents /etc/group /opt && \
    cp -a --parents /usr/sbin/nginx /opt && \
    cp -a --parents /usr/sbin/nginx-debug /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
    cp /usr/share/zoneinfo/${
     TIME_ZONE:-ROC} /opt/etc/localtime

FROM gcr.io/distroless/base-debian10

COPY --from=base /opt /

VOLUME ["/usr/share/nginx/html"]		##来挂接发布目录;

EXPOSE 80 443

ENTRYPOINT ["nginx", "-g", "daemon off;"]

[root@server1 new]# docker build -t rhel7:v4 .
		##构建镜像
[root@server1 new]# docker run -d --name demo rhel7:v4
		##运行容器
4a742f3593214fd518832e8a48928d8e94852df4823d4ddaf50f3c387c18d85c
[root@server1 new]# docker images  rhel7		
	##可以看到其只有31.9M,包括其中的基础19.2M,相对于前面的来说经建立很多
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7               v4                  e8c324efa2e0        About an hour ago   31.9MB
rhel7               v3                  8c8a22458c17        2 hours ago         141MB
rhel7               v2                  45d788701ce8        2 hours ago         255MB
rhel7               v1                  fffa388c2f85        2 hours ago         296MB
rhel7               latest              0a3eb3fde7fd        6 years ago         140MB

[root@server1 new]# docker history rhel7:v4
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
b3388a690329        5 minutes ago       /bin/sh -c #(nop)  ENTRYPOINT ["nginx" "-g" …   0B                  
52d6aca444a9        5 minutes ago       /bin/sh -c #(nop)  EXPOSE 443 80                0B                  
55d6bb5728eb        5 minutes ago       /bin/sh -c #(nop)  VOLUME [/usr/share/nginx/…   0B                  
36cd5ddf7ad3        5 minutes ago       /bin/sh -c #(nop) COPY dir:4b299d402b46c2983…   12.7MB              
d48fcdd54946        51 years ago        bazel build ...                                 17.4MB              
<missing>           51 years ago        bazel build ...                                 1.8MB               

除了 docker 引擎管理的卷之外还可以手动指定挂载;

[root@server1 new]# docker rm -f demo
[root@server1 new]# docker run -d --name demo -v /data:/usr/share/nginx/html rhel7:v4
		##手动指定挂载,-v 所接的路径不管是宿主机还是容器中的,当不存在时会自动新建;宿主机目录下的数据一定会覆盖容器中的数据
a8c1fcb30efd26b551caaea35d9c9cda37db7d357795e25d71bee3a3aa9739d0
[root@server1 new]# docker inspect demo	
	##查看运行容器分配的IP
[root@server1 new]# curl 172.17.0.2		
	##此时访问时已经被覆盖
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.19.10</center>
</body>
</html>
[root@server1 new]# cd /data
[root@server1 data]# echo www.westos.org > index.html
[root@server1 data]# curl 172.17.0.2
www.westos.org
[root@server1 data]# echo www.westos.org >> index.html
[root@server1 data]# echo www.westos.org >> index.html
[root@server1 data]# echo www.westos.org >> index.html
[root@server1 data]# curl 172.17.0.2
www.westos.org
www.westos.org
www.westos.org
www.westos.org
[root@server1 data]# docker rm -f demo	
[root@server1 new]# cd /data/
[root@server1 data]# ls

此时即使删除了容器,但是数据还在,当再启动一个容器时将数据挂接还可以看到数据

5. 总 结

  • 学习了docker 镜像,掌握了镜像的分层结构,学习了如何通过dockerfile 构建镜像,最后实践了docker 镜像的多种优化方法。
  • 镜像常用子命令
    images 显示镜像列表
    history 显示镜像构建历史
    commit 从容器创建镜像
    build 从Dockerfile构建镜像
    tag 给镜像打标签
    search 搜索镜像
    pull 从仓库拉取镜像
    push 上传镜像到仓库
    rmi 删除镜像

你可能感兴趣的:(docker,运维,docker,运维)