Docker原理&多阶段构建

大致原理

  1. Dockerfile 中的 COPY 与 ADD 命令的区别

    COPY和ADD功能差不多,但COPY支持多阶段构建,ADD支持解压缩

    注意这俩复制的时候都是默认复制目录下的所有文件

  2. FROM…AS…:docker 多阶段构建可以解决编译和构建复杂的问题,减小镜像大小。

    重点在于使用COPY指令的 -FROM参数,最终生成的还是一个镜像,但是通过COPY语句使用了上一个构建中的文件。

    但除此之外,还有更重要的:

    COPY FROM不仅可以从前置构建阶段的镜像中拷贝文件,还可以从一个已经存在的镜像中远程拷贝。 这样就相当于FROM了多个base镜像(但并不是,是拷贝了该镜像里的文件)

    栗子:

    1
    COPY -from=hub/image_sample file_path_in_image_sample target_path_of_this_image

    这样就把远程镜像的hub/image_sample的路径为file_path_in_image_sample的文件给拷贝到了本镜像的target_path_of_this_image路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    FROM golang:1.7.3 as builder
    WORKDIR /go/src/github.com/alexellis/href-counter/
    RUN go get -d -v golang.org/x/net/html
    COPY app.go .
    RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
    FROM alpine:latest
    RUN apk --no-cache add ca-certificates
    WORKDIR /root/
    COPY --from=builder /go/src/github.com/alexellis/href-counter/app . #注意这里COPY的from,就是从builder构建中继续执行
    CMD ["./app"]
  3. docker原理:https://zhuanlan.zhihu.com/p/51836305

    docker就是个应用程序,运行在用户空间,一个容器就是一个用户进程,通过调用系统接口实现功能,直接跑在内核上

    对于linux宿主 ,docker直接使用宿主内核;对于mac/win,docker使用自带的linux内核

    虚拟机完整虚拟了内核和用户空间;而 docker 仅仅虚拟了用户空间,不同容器使用了共用的内核,那么 docker 必然更轻量、更快

    docker的资源隔离依靠namespacehttps://zhuanlan.zhihu.com/p/67021108

    在不同容器中看不到宿主、其它容器的进程、文件等,做到了隔离(用户级隔离),是通过linux内核的Namespace和Cgroups特性实现的

    Namespace用于隔离不同容器的资源,Cgroups用于不同容器的资源使用限制

    Namespace有六种:Mount、IPC、PID、Network、User,每个容器不同的资源都对应各自种类的namespace,只有namespace相同的(认定为同一容器)的才能访问该namespace下的资源。

    (于是你甚至可以在容器启动的时候,指定这些参数,从而强制容器运行在特定namespace之中。例如,你可以指定 —pid host,从而让容器进程使用宿主机进程空间,此时容器可以看到host上所有的进程。见下)

    1
    2
    3
    4
    5
    6
    docker run中namespace相关参数

    --ipc string IPC namespace to use
    --pid string PID namespace to use
    --userns string User namespace to use
    --uts string UTS namespace to use

    cgroups 的全称是control groups,是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对 cpu,内存等资源实现精细化的控制。

    docker镜像是分层的https://zhuanlan.zhihu.com/p/70424048

    Docker镜像是分层构建的,Dockerfile 中每条指令都会新建一层

    (所以就会有加速docker镜像构建小优化:在使用 COPY 和 ADD 命令时,我们可以通过一些技巧来加速镜像的 build 过程。比如把那些最不容易发生变化的文件的拷贝操作放在较低的镜像层中,这样在重新 build 镜像时就会使用前面 build 产生的缓存)

    Dockerfile中构建镜像的每层都是只读层,当启动一个容器,Docker 会在最顶部添加读写层,你在容器内做的所有更改,如写日志、修改、删除文件等,都保存到了读写层内,一般称该层为容器层。也就是说,容器(container)和镜像(image)的最主要区别就是容器加上了顶层的读写层,使用Copy-On-Write 策略(基于联合挂载技术,这需要联合文件系统unionFS支持,如linux内核自带的overlay,AUFS等)。显然容器的任何修改都不会影响镜像,容器被删除,那该容器的读写层也就被删除了。

    docker ps -s,可以看到最后有两列sizevirtual size。其中 size就是容器读写层占用的磁盘空间,而 virtual size 就是读写层加上对应只读层所占用的磁盘空间

docker容器挺好玩的,以后有时间看看源码鼓捣一下!