当前位置: 首页 > news >正文

Docker: hello world

文章目录

    • 一、构建第一个镜像
    • 二、问题与解决方法

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

  • docker hello-world镜像地址:https://hub.docker.com/_/hello-world

  • 相关的源码:https://github.com/docker-library/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命令查看可执行文件是使用何种编译方式编译的

    在这里插入图片描述

相关文章:

  • 08.文件操作
  • linux上redis单机的安装
  • 云服务器CentOS8 安装 Oracle19c
  • 沃尔玛、eBay、wish、新蛋等美系平台对于测评风控点有哪些?怎么解决
  • 霸道 阿里最新版Spring Cloud Alibaba项目文档,竟将重要组件弃用
  • lightdb22.3-oracle系统视图兼容增强
  • 【大数据】Hadoop三大核心组件入门
  • Jackson别名@JsonAlias详细用法
  • 机器学习(二十八):灰狼优化算法对神经网络的优化
  • RabbitMQ入门(二)
  • watch监听的几种写法
  • 搭建vue3项目
  • 5000页?一份字节跳动Java面试全解手册发布,瞬间登顶各大搜索栏
  • 支付宝小程序模板行业合集,支付宝小程序制作平台分享
  • Active Directory 01 - 测试环境搭建
  • input的行数自动增减
  • jquery ajax学习笔记
  • js继承的实现方法
  • opencv python Meanshift 和 Camshift
  • oschina
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • 分享一份非常强势的Android面试题
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 用Canvas画一棵二叉树
  • 与 ConTeXt MkIV 官方文档的接驳
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 进程与线程(三)——进程/线程间通信
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • #{} 和 ${}区别
  • #Z0458. 树的中心2
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (原)本想说脏话,奈何已放下
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • @Autowired多个相同类型bean装配问题
  • [ 网络基础篇 ] MAP 迈普交换机常用命令详解
  • [android] 请求码和结果码的作用
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [BUG]vscode插件live server无法自动打开浏览器
  • [BZOJ1040][P2607][ZJOI2008]骑士[树形DP+基环树]
  • [C#]winform部署yolov9的onnx模型
  • [cb]UIGrid+UIStretch的自适应
  • [C语言][C++][时间复杂度详解分析]二分查找——杨氏矩阵查找数字详解!!!
  • [Firefly-Linux] RK3568 pca9555芯片驱动详解
  • [HJ56 完全数计算]
  • [iOS]Win8下iTunes无法连接iPhone版本的解决方法
  • [Java基础]—JDBC
  • [Latex学习笔记]数学公式基本命令