【docker】docker建立最简单最小的helloworld镜像

本篇博客旨在手动制作一个最简单的myhello镜像,而并非使用用官方的hello-world。

首先运行一下官方的hello-world看看效果:

$ docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

官方的hello-world镜像也很小,只有1.85kB

$ docker image ls hello-world
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              e38bc07ac18e        7 days ago          1.85 kB

我的宿主机环境ubuntu16,首先编写一个c源文件hello.c,内容如下

#include <stdio.h>

int main(int argc, char *argv[])
{
        printf("hello world\n");
        return 0;
}

编译

mkdir build
gcc -o build/hello hello.c

编写Dockerfile,内容如下:

FROM ubuntu:16.04
MAINTAINER arvik [email protected]
RUN mkdir /data
COPY hello /data
ENTRYPOINT ["/data/hello", "arvik"]

进入build目录下制作镜像docker build -t myhello:1.0 .,可以看到生成了image

$ docker image ls myhello
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myhello             1.0                 6e87875b0282        11 seconds ago         113 MB

运行docker run myhello:1.0可以看到一会儿就有了hello world的打印输出。这样,最省事的入门hello world就制作出来了。


细心的同学发现,制作出来的镜像大小居然有113MB,官方的hello-world镜像只有1.85kB,差距如此之大。

这是因为我们的myhello依赖了ubuntu:16.04基础镜像

$ docker image ls ubuntu
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               c9d990395902        6 days ago          113 MB
ubuntu              latest              c9d990395902        6 days ago          113 MB

这个镜像差不多就有113MB大小,能不能不依赖ubuntu:16.04基础镜像,只把编译后生成的二进制文件hello打包进myhello呢,是可以的。

改一下Dockerfile文件如下:

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

运行docker run myhello:2.0制作出myhello的2.0版本,运行一下却发现报错:

$ docker run myhello:2.0
standard_init_linux.go:178: exec user process caused "no such file or directory"

由于刚刚我们编译hello的时候,采用的是动态链接,gcc帮我们默认链接了库文件,而myhello:2.0中只有根目录下一个hello文件,并没有这些库文件,所以容器中的hello肯定运行不起来,查看hello链接了哪些库文件

$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffe3639a000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe04f30e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe04f6d8000)

知道原因了,这次我们采用静态编译的方式编译hello:
···
$ gcc -static -o build/hello hello.c

$ ldd hello
not a dynamic executable
···

然后删除myhello镜像(docker image rm -f myhello:2.0),按照上面方法重新制作myhello:2.0,运行,发现有hello world输出,这次镜像比较小,不到1MB,但还是大于官方的hello-world镜像1.85kB

$ docker image ls myhello
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myhello             2.0                 efa6213c2fb5        1 minutes ago      913 kB
myhello             1.0                 6e87875b0282        5 minutes ago      113 MB

原因是gcc在编译的时候采用了静态的方式,把libc.so.6等库链接到hello可执行文件内部了,导致hello文件比较大。

可不可以再小点??? 可以! 但是就跟官方hello-world镜像一样,意义不大
我们重写hello.c,如下:

#include <sys/syscall.h>

void _start() {
syscall(SYS_write, 1, "hello world\n", sizeof("hello world\n") - 1);
syscall(SYS_exit, 0);
}

gcc编译方式改为:

$ gcc -static -Os -nostartfiles -fno-asynchronous-unwind-tables -o build/hello hello.c

ls build/hello -al
-rwxrwxr-x 1 arvik arvik 1864 Apr 19 17:42 build/hello

重新制作镜像,这次接近官方hello-world大小了

$ docker build -t myhello:4.0 .

$ docker image ls myhello:4.0
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myhello             4.0                 60f4a2c32e0a        59 seconds ago      1.86 kB

$ docker run -t myhello:4.0
hello world

最后还有个问题

本人发现以动态链接的方式编译hello.c文件,把生成的二进制文件hello和它依赖的库文件一起打包进入myhello:3.0镜像中却发现运行的容器不成功,报错依然是standard_init_linux.go:178: exec user process caused "no such file or directory",不知道是不是库linux-vdso.so.1找不到的原因,按道理说容器应该和宿主机共享一个操作系统内核,宿主机在运行容器的时候内核会自动提供linux-vdso.so.11运行库,有童鞋知道原因的还希望在留言告知下,谢谢!


  1. 本人对linux-vdso.so.1也不是很了解,参考了百度上的解释,请直接百度linux-vdso.so.1

猜你喜欢

转载自blog.csdn.net/u012819339/article/details/80007919