欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

玩转 Docker基础系列28:从零开始 - Dockerfile中使用scratch基础镜像(FROM scratch)

最编程 2024-07-24 08:48:47
...
 
通常使用 Docker 镜像时会以一个已存在的镜像为基础,在其上进行定制,这个已存在的镜像就是基础镜像。

在 DockerFile 中必须指定基础镜像,FROM 指令就是用于指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。在 Dockerfile 中以 scratch 为基础镜像 (FROM scratch),意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

1. 创建基于静态编译的 C 程序镜像

    1) C 程序

        $ cd ~/gcc
        $ vim hello.c
            #include <stdio.h>
           
            int main() {
                puts("Hello World!- C");
                return 0;
            }

  

        # gcc 静态编译
        $ gcc hello.c -static -o hello

        $ ./hello

            Hello World! - C

        $ ll -h hello

            -rwxrwxr-x 1 root root   852K  hello

    2) 创建 Dockerfile

        $ cd ~/gcc
        $ vim Dockerfile

            FROM scratch
            COPY hello /
            CMD ["/hello"]

        注:scratch 空镜像中没有 sh 或 bash,无法 mkdir、mv 等 shell 命令是无效的,因此需要在镜像外部把文件目录结构建立好,然后通过 ADD 或 COPY 命令拷贝到容器内。

    3) 创建 hello 镜像,并运行容器

        $ cd ~/gcc

        # 创建镜像
        $ docker build -t hello:1.0 .
            Step 1/3 : FROM scratch
            --->
            Step 2/3 : COPY hello /
            ---> bb893abeef08
            Step 3/3 : CMD ["/hello"]
            ---> Running in c31e62693472
            Removing intermediate container c31e62693472
            ---> cebea71dcbe0
            Successfully built cebea71dcbe0
            Successfully tagged hello:1.0

        $ docker images


            REPOSITORY      TAG      IMAGE ID       CREATED          SIZE
            hello           1.0      cebea71dcbe0   38 seconds ago   872kB

        $ docker run --rm hello:1.0

            Hello World!- C

    注:以上 Dockerfile 制作出来的镜像是 872kB,hello 的二进制文件是 852kB。使用 scratch 空镜像的本质是让程序只调用 host 主机的 Linux 内核部分的功能,而不依赖容器内的操作环境功能。host 主机的 Linux 内核部分对 Docker 容器是共享的,因此其 scratch 空镜像的大小可以认为近似为 0。

2. 创建基于编译的 Go 程序镜像

    1) Go 程序

        $ cd ~/go
        $ vim test.go
            package main

            import "fmt"

            func main() {
                fmt.Println("Hello world - Go")
            }

        # 编译

        $ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-w -s' test.go

            参数说明:

                GOOS=linux GOARCH=amd64 表示确保编译出来的程序可以运行在 amd64 linux 环境;
                CGO_ENABLED=0 表示确保用到的 C 函数库包含到 Go run-time 中,程序运行时以静态方式内部调用。否则,由于 scratch 空镜像内没有 C 函数库,Go 程序动态调用时会出错;
                -ldflags '-w -s' 表示排除 Debug 信息,让编译出来的程序更小。-w 是排除 DWARF,-s 是排除 debug symbol;

            注:Go 语言调用 C 函数库出错的现象也会出现在 alpine 中,这是因为 alpine 的 C 函数库是精简版的。

        $ ./test

            Hello world - Go

        $ ll -h test

            -rwxrwxr-x 1 root root  1.2M  test

    2) 创建 Dockerfile

        $ cd ~/go
        $ vim Dockerfile

            FROM scratch
            COPY test /
            CMD ["/test"]

    3) 创建 test 镜像,并运行容器

        $ cd ~/go

        # 创建镜像
        $ docker build -t test:1.0 .
            Step 1/3 : FROM scratch
            --->
            Step 2/3 : COPY test /
            ---> cd67f4bfb544
            Step 3/3 : CMD ["/test"]
            ---> Running in c3cf81ea01e4
            Removing intermediate container c3cf81ea01e4
            ---> 535665c081c8
            Successfully built 535665c081c8
            Successfully tagged test:1.0

        $ docker images


            REPOSITORY      TAG      IMAGE ID       CREATED          SIZE
            test            1.0      535665c081c8   29 seconds ago   1.18MB

        $ docker run --rm test:1.0

            Hello world - Go

3. 创建基于 Debian rootfs 的 Linux 镜像  

    由于 scratch 空镜像内,没有操作系统的根文件系统(rootfs),无法运行 sh 或 bash,无法进入容器内进行交互式调试。我们可以给基于 scratch 空镜像创建的镜像里,添加一个 rootfs。

    Docker Debain: https://docker.debian.net/
    Docker Debain GitHub: https://github.com/debuerreotype/docker-debian-artifacts

    1)下载 rootfs
       
        这里选用了 https://docker.debian.net/ 页面上的 debian:bookworm-20230227,amd64 链接跳转到页面 https://github.com/debuerreotype/docker-debian-artifacts/tree/fe5738569aad49a97cf73183a8a6b2732fe57840/bookworm。

        下载 rootfs.tar.xz 文件到 ~/debian 目录下,文件大小 29.66MB。

    2) 创建 Dockerfile

        $ cd ~/debian
        $ vim Dockerfile
            FROM scratch
            Add rootfs.tar.xz /
            WORKDIR /home/docker
            CMD /bin/bash
     3) 创建 Linux 镜像,并运行容器

        $ cd ~/debian

        # 创建镜像
        $ docker build -t debian_local:1.0 .
            Step 1/4 : FROM scratch
            --->
            Step 2/4 : Add rootfs.tar.xz /
            ---> 806b049c2199
            Step 3/4 : WORKDIR /home/docker
            ---> Running in e4c0defe9fd3
            Removing intermediate container e4c0defe9fd3
            ---> a2bea1387c68
            Step 4/4 : CMD /bin/bash
            ---> Running in ea20508cb334
            Removing intermediate container ea20508cb334
            ---> fd4fa7caba5d
            Successfully built fd4fa7caba5d
            Successfully tagged debian_local:1.0
         $ docker images

            REPOSITORY      TAG      IMAGE ID       CREATED          SIZE
            debian_local    1.0      fd4fa7caba5d   38 seconds ago   116MB

        $ docker run -itd --name debian-local-1.0 debian_local:1.0  

            0e6e3704225c5723349e8d1cc07fefefdf93d205cdabc6f938f3726482b0d918

        $ docker exec -it debian-local-1.0 /bin/bash
            root@0e6e3704225c:/home/docker# cd /
            root@0e6e3704225c:/# ls
            bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

            root@0e6e3704225c:/# cat /etc/issue
            Debian GNU/Linux bookworm/sid \n \l

原文地址:https://www.cnblogs.com/tkuang/p/17219527.html