Docker: hello world

一般安装完Docker之后,都会拉取官方的hello-world镜像运行下看看Docker是否正确安装、能否正常运行(docker run hello-world),以下是该镜像的相关链接:

所以这个镜像是怎么制作出来的,今天我们自己也来试试看,构建自己的第一个镜像my-hello-world~

一、构建第一个镜像

在这过程中,我把遇到的问题及其解决方法都汇总在第二部分,所以如果在构建镜像的过程中有遇到问题,可以先到第二部分看看有没有对应的问题和解决方法

  1. 创建一个目录存放镜像相关文件/turn

    mkdir my-hello-world
    cd my-hello-world
    
  2. 创建镜像所需的可执行文件

    i. 先新建文件hello.c

    vim hello.c
    

    ii. 将下面的代码复制到上面的文件中,这里直接使用官方github上的hello.c的源代码:

    #include <sys/syscall.h>
    #include <unistd.h>
    
    #ifndef DOCKER_IMAGE
      #define DOCKER_IMAGE "hello-world"
    #endif
    
    #ifndef DOCKER_GREETING
      #define DOCKER_GREETING "Hello from Docker!"
    #endif
    
    #ifndef DOCKER_ARCH
      #define DOCKER_ARCH "amd64"
    #endif
    
    const char message[] =
      "\n"
      DOCKER_GREETING "\n"
      "This message shows that your installation appears to be working correctly.\n"
      "\n"
      "To generate this message, Docker took the following steps:\n"
      " 1. The Docker client contacted the Docker daemon.\n"
      " 2. The Docker daemon pulled the \"" DOCKER_IMAGE "\" image from the Docker Hub.\n"
      "    (" DOCKER_ARCH ")\n"
      " 3. The Docker daemon created a new container from that image which runs the\n"
      "    executable that produces the output you are currently reading.\n"
      " 4. The Docker daemon streamed that output to the Docker client, which sent it\n"
      "    to your terminal.\n"
      "\n"
      "To try something more ambitious, you can run an Ubuntu container with:\n"
      " $ docker run -it ubuntu bash\n"
      "\n"
      "Share images, automate workflows, and more with a free Docker ID:\n"
      " https://hub.docker.com/\n"
      "\n"
      "For more examples and ideas, visit:\n"
      " https://docs.docker.com/get-started/\n"
      "\n";
    
    int main() {
      //write(1, message, sizeof(message) - 1);
      syscall(SYS_write, STDOUT_FILENO, message, sizeof(message) - 1);
    
      //_exit(0);
      //syscall(SYS_exit, 0);
      return 0;
    }
    

    iii. 编译源代码生成可执行文件:

    gcc -static hello.c -o hello
    

    在这里插入图片描述

    如果提示gcc命令没找到,直接按照提示安装该命令

    在这里插入图片描述

    iv. 运行生成的hello可执行文件,看能否正常输出

    在这里插入图片描述

    看起来程序运行和输出都没问题

  3. 编写Dockerfile

    Dockerfile是用于构建镜像的文本文件,里面包含了构建镜像所需的指令,每一条指令构建一层镜像,指令的内容描述了该层镜像应如何构建。这里也直接使用官方github上提供的Dockerfile

    新建文件Dockerfile,并将下面的代码复制进去:

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

    简单解释下上述构建镜像的指令:

    • FROM scratch:以scratch镜像为基础,从scratch这个镜像开始构建我们的镜像,scratch镜像的介绍可以看这里

    • COPY hello /:将可执行文件hello复制到镜像文件系统的根目录

    • CMD ["/hello"]:执行命令/hello

  4. 创建镜像

    强调一下,到目前为止,所有的文件都是在同一目录(这里是my-hello-world)下。

    先确保是在my-hello-world这个目录下面,然后执行如下命令开始构建镜像:

    sudo docker build -t my-hello-world:latest .
    

    在这里插入图片描述

    已经成功构建了my-hello-world镜像,执行sudo docker images命令也可以看到已经有了我们刚刚构建好的镜像

    在这里插入图片描述

  5. 运行镜像

    sudo docker run my-hello-world
    

    在这里插入图片描述

    可以看到自己制作的镜像可以正常运行输出了,跟官方提供的一样。

二、问题与解决方法

在这里插入图片描述

  • 编译hello.c时,出现错误

    /usr/bin/ld: cannot find -lc
    collect2: error: ld returned 1 exit status
    

    这是因为在安装gcc的过程中,默认只安装动态库libc.so,没有安装静态库libc.a,所以需要手动安装,根据这里的说明,执行以下命令安装相应的静态库:

    sudo dnf --enablerepo=crb install glibc-static
    

    这时再执行编译命令gcc -static hello.c -o hello就没问题了。

  • 如果编译时不加-static选项,则输出的可执行文件在Linux上可以正常运行,而在运行镜像时会产生问题

    exec /hello: no such file or directory
    

    这是因为如果直接使用gcc编译,不加任何选项,则默认时使用动态链接的方式编译,用到的动态库不会被编译进目标程序中,输出的可执行文件无法单独运行,需要系统提供相应的动态库才能正常运行。因为Linux中提供了动态库,所以hello在Linux中可以运行,而在镜像中,我们没有安装gcc,自然不会有运行程序需要的动态库,所以从这个镜像启动的容器自然也无法运行hello程序。加上-static选项可以让gcc使用静态编译的方式编译源代码,会把静态库添加编译到目标程序中,编译输出的可执行文件可独立运行,不需要系统提供其他的库文件,所以这个hello程序在容器中也可以正常运行。

    因为静态编译会把静态库编译进目标程序,所以静态编译输出的程序会比动态编译输出的程序要大很多:

    在这里插入图片描述

    可以使用file命令查看可执行文件是使用何种编译方式编译的

    在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elwin Wong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值