从零自制docker-8-【构建实现run命令的容器】

文章目录

  • log "github.com/sirupsen/logrus"
  • `args...`
  • go module
  • import第三方包失败
  • package和 go import的导入
  • go build . 和go run
  • cli库
  • `log.SetFormatter(&log.JSONFormatter{})`
  • error和nil的关系
  • cmd.Wait()和cmd.Start()
  • arg……
  • context.Args().Get(0)
  • syscall.Exec和os/exec.Command
  • `syscall.Exec`
  • mountflags
  • syscall.Mount
  • 请注意,只有包中首字母大写的函数(public函数)才能被其他包调用。首字母小写的函数(private函数)只能在包内部使用
  • 代码
  • 最终效果
  • 问题

log “github.com/sirupsen/logrus”

log “github.com/sirupsen/logrus”: 这是引入了 github.com/sirupsen/logrus 包,并将其重命名为 log

args...

假设我们有一个切片 myArgs := []string{"arg1", "arg2", "arg3"},我们想将这个切片作为参数传递给 exec.Command() 函数。

如果直接传递 myArgs 作为参数,那么 exec.Command() 函数会将整个切片作为一个单独的参数:

cmd := exec.Command("/path/to/executable", myArgs)

这相当于执行命令 /path/to/executable ["arg1" "arg2" "arg3"]

但是如果我们使用 args... 语法,就可以将切片中的每个元素都作为独立的参数传递给 exec.Command() 函数:

cmd := exec.Command("/path/to/executable", myArgs...)

这相当于执行命令 /path/to/executable "arg1" "arg2" "arg3"

args... 语法会将切片 myArgs 中的每个元素都作为独立的参数传递给 exec.Command() 函数。这种方式更加灵活,可以方便地将任意长度的参数列表传递给外部命令。

另一个例子是:

args := []string{"-flag1", "value1", "-flag2", "value2"}
cmd := exec.Command("/path/to/executable", args...)

这会将 args 切片中的 6 个元素全部作为独立的参数传递给 /path/to/executable 命令。

总之,args... 语法可以将一个切片展开为多个独立的参数,传递给需要接受多个参数的函数,在处理命令行参数时非常有用。

go module

三种包管理方式参考连接

go get下载的第三方包的位置

在GOMODULE模式下,go get命令会将依赖包下载到$GOPATH/pkg/mod目录下

go module包管理方式(推荐使用)

GO111MODULE 是一个用来控制 Go Modules 行为的环境变量。在 Go 1.11 版本之后,Go 引入了 Go Modules 来管理依赖关系和版本控制。GO111MODULE 环境变量可以设置为以下几个值:

  1. GO111MODULE=on:这是启用 Go Modules 的模式。当设置为 on 时,Go 将会使用 Go Modules 来管理依赖关系,无需再依赖 GOPATH。

  2. GO111MODULE=off:这是禁用 Go Modules 的模式。当设置为 off 时,Go 将使用传统的 GOPATH 模式来管理依赖关系。

  3. GO111MODULE=auto:这是自动模式。在自动模式下,Go 将根据当前目录是否包含 go.mod 文件来决定是否启用 Go Modules。如果在项目根目录下存在 go.mod 文件,则会启用 Go Modules,否则使用 GOPATH 模式。

因此,当设置 GO111MODULE=''(即空字符串)时,表示未显式设置 GO111MODULE 环境变量,Go 将根据自动模式来决定是否启用 Go Modules,具体行为取决于当前项目的目录结构和是否存在 go.mod 文件。

go mod tidy:检测该文件夹目录下所有引入的依赖,写入 go.mod 文件。删除错误或者不使用的modules,下载没download的package(下载到$GOPATH/pkg/mod)

import第三方包失败

go env -w GOPROXY=https://goproxy.cn,direct

再尝试

package和 go import的导入

go import导入包详解

在这里插入图片描述

golang使用同目录下的文件,golang中的package使用简介

在golang 里面一个目录为一个package, 一个package级别的func, type, 变量, 常量, 这个package下的所有文件里的代码都可以随意访问, 也不需要首字母大写。
引用当前目录得其它子目录中的文件可以import这个文件所在的文件夹相对位置,也可以import 当前目录/子目录中的package

Go语言中的包Package详解

包分为两种,一种是main函数(可执行文件)一种是库函数的包
可执行程序的包,编译完成后会生成一个可执行文件、静态库的包编译之后会生成一个.a为后缀的文件(在$GOPATH/pkg/里),自己不能执行只能被可执行包引用。

可执行程序的包必须以main作为包名,静态库的包名没有

main包和其他类库通过静态链接,最终形成的可执行文件是没有任何外部依赖的。

go build . 和go run

go build .将当前目录所有的文件都会编译并生成一个可执行程序
go run 编译单个程序并运行,此时如果多个package为main的程序有相互依赖,那么go run 其中一个会报错,因为用了其他package为main的程序

cli库

Go 每日一库之 cli

log.SetFormatter(&log.JSONFormatter{})

假设我们有一个简单的 Go 程序,用于记录一些基本的日志信息:

package mainimport ("log"
)func main() {// 设置日志输出格式为 JSON 格式log.SetFormatter(&log.JSONFormatter{})// 记录一些日志信息log.Println("This is an informational message")log.Printf("User %s logged in", "John Doe")log.Fatalf("Failed to connect to database: %s", "connection refused")
}

在这个例子中,我们首先使用 log.SetFormatter(&log.JSONFormatter{}) 将日志输出格式设置为 JSON 格式。

然后,我们分别使用 log.Println()log.Printf()log.Fatalf() 记录了三条不同级别的日志信息。

当我们运行这个程序时,日志输出将会是 JSON 格式,类似于以下内容:

{"level":"info","msg":"This is an informational message","time":"2024-04-07T12:34:56Z"}
{"level":"info","msg":"User John Doe logged in","time":"2024-04-07T12:34:56Z"}
{"level":"error","msg":"Failed to connect to database: connection refused","time":"2024-04-07T12:34:56Z"}

与默认的文本格式相比,JSON 格式的日志输出包含了更多的元信息,如日志级别(level)、消息内容(msg)和时间戳(time)。这种结构化的日志格式更加方便后续的处理和分析,特别是在需要机器解析日志的场景下。

总之,log.SetFormatter(&log.JSONFormatter{}) 是一个非常实用的方法,可以帮助我们更好地管理和处理 Go 程序的日志信息。

error和nil的关系

error类型和nil的关系是这样的:

  • error类型是Go语言中一个接口,用来表示一个错误情况。一个实现了Error()方法的值,即使没有实现任何具体的行为,也被称为一个error值。
  • nil是Go语言中的一个特殊值,它表示的是空值或不存在的值,对于error类型的值来说,nil表示没有错误发生。

在函数返回值中,当函数执行正确,没有遇到错误时,我们通常会用nil来表示。例如:

func someFunction() error {// 函数执行成功,没有错误return nil
}

当函数执行遇到错误时,我们会返回一个非nilerror值,例如:

func someFunction() error {// 函数执行失败,返回一个错误return errors.New("Some error occurred.")
}

所以,error类型和nil的关系是:nil表示error类型的值为非错误状态,非nilerror表示存在错误。在函数返回时,如果error值为nil,则表示函数执行成功,否则表示有错误发生。

cmd.Wait()和cmd.Start()

err变量在调用cmd.Wait()方法后得到返回值。当调用cmd.Start()时,该方法会启动命令并在后台执行。如果在启动命令时发生了错误(例如命令不存在、权限不足等),cmd.Start()会立即返回一个非nil的错误值。

而cmd.Wait()方法的作用是等待命令执行完毕。当命令执行结束后,此方法会返回。返回值有两个含义:

若命令执行成功结束,err将为nil。
若在命令执行过程中出现任何错误(比如命令被信号终止、超时退出等),err将包含相应的错误信息。
因此,在你的代码片段中,err = cmd.Wait()这一行会阻塞直到外部命令执行完毕,然后返回一个表示命令执行结果(成功与否及退出状态)的错误值。

arg……

在Go语言中,os/exec包提供了执行外部命令的功能。这里的代码片段是用于创建一个可执行命令的实例。

args := []string{"init", cmd} 是定义了一个字符串切片(slice),它存储了要执行的命令及其参数。在这个例子中:

  • "init":是一个命令参数,表示要执行的子命令为 “init”。
  • cmd:是一个变量,通常代表另一个命令参数。具体的值取决于程序上下文中的赋值情况。

然后,command := exec.Command("/proc/self/exe", args...) 这一行是用来创建一个新的 *Cmd 结构体实例,这个实例代表了一个待执行的命令。

"/proc/self/exe" 是一个特殊路径,在Linux系统中指向当前正在运行的可执行文件。也就是说,这里实际上是打算执行与当前进程相同的一个新进程,并且传入参数 args

args... 是Go语言中的变长参数语法,它会将字符串切片 args 扩展为多个单独的参数传递给 exec.Command 函数。

所以整个语句的作用是,根据给定的参数列表 args,执行与当前进程相同的新的命令行程序,并且第一个参数是 “init”,第二个参数是变量 cmd 的值。

context.Args().Get(0)

在Go语言中,这段代码片段是基于第三方命令行工具库(如urfave/clicobra)来定义一个命令行命令init的结构体。在这些库中,cli.Context对象包含了从命令行输入解析出来的所有信息。

context.Args().Get(0) 这一行代码在用户调用命令 init 并带有一个或多个额外参数时,用于获取命令行中紧随命令名 init 之后的第一个参数。

举个例子,假设用户在命令行中执行了如下命令:

./myapp init mycontainer

在上述代码段中,context.Args().Get(0) 将返回字符串 "mycontainer"。这是因为context.Args() 返回的是一个包含所有非命令名称参数的字符串切片,索引0位置的元素就是第一个参数。

然而,根据这段代码的具体上下文,看起来开发者并未真正使用到 cmd 变量(它保存了第一个参数的值),而是直接调用了 contain.init() 方法初始化容器。如果预期是利用第一个参数来定制初始化行为,那么应该会在 contain.init() 调用中使用到 cmd 变量。

syscall.Exec和os/exec.Command

在Go语言中,syscall.Execos/exec.Command 都是用来执行外部程序的,但它们在用途和机制上有显著的不同:

  1. syscall.Exec

    • syscall.Exec 是一个低级别的系统调用,直接在当前进程中替换当前程序的映像和数据,执行新的程序。
    • syscall.Exec 成功执行后,原始程序的内存空间、文件描述符等资源将被新程序接管,原始程序不会恢复执行,因为它已经被完全替换掉了。
    • 通常用在那些希望彻底转换当前进程上下文而不返回的情况。
  2. os/exec.Command

    • os/exec.Command 提供了一种高级别的、更易于使用的API来执行外部程序,并且它不会替换当前进程的内容。
    • exec.Command 创建并返回一个 *Cmd 类型的结构体,调用其 Run() 方法来执行外部程序,执行完成后,当前Go程序会继续执行后续代码。
    • 你可以通过 Output()CombinedOutput() 等方法获取子进程的输出,并且可以控制子进程的标准输入、输出和错误流。
    • 如果需要在同一进程中连续执行多个外部命令,或者需要处理子进程的输出结果,那么 os/exec 库是非常适合的。

简单来说,syscall.Exec 更像是进程自身的“变身”,而 os/exec.Command 则是在当前进程中启动一个新的子进程来进行任务,并且可以对子进程进行更多的控制和通信。

syscall.Exec

在Go语言中,当程序执行到 syscall.Exec 函数时,会发生以下情况:

  1. 当前进程替换
    syscall.Exec 函数负责执行一个新的程序,同时替换当前进程的映像和内存空间。这意味着当前执行的Go程序的所有代码和数据都会被新的程序所取代,不再有任何机会回到原来的Go程序执行流中。

  2. 资源继承
    新程序将继承当前进程的PID(进程ID)、打开的文件描述符以及其他一些进程相关的资源。这意味着新程序可以从原先的进程中接过控制权,例如继续监听同一套网络端口或读写已打开的文件。

  3. 程序执行
    syscall.Exec 函数接受一系列参数,包括要执行的程序路径、命令行参数和环境变量。新程序将以指定的方式执行,就像它是由shell或其他启动器直接启动的一样。

  4. 永不返回
    一旦 syscall.Exec 成功执行了新程序,原Go程序的代码将不再被执行,并且 syscall.Exec 函数本身也不会返回——因为它已经不再是那个进程的一部分了。如果 syscall.Exec 失败(例如由于找不到要执行的程序或权限问题),它会返回一个错误,但这种情况下的“返回”实际上已经是当前进程内的紧急错误处理逻辑了,而不是原Go程序的逻辑继续执行。

  5. 用途
    syscall.Exec 通常用于服务程序升级、执行子进程并替换自己以进入不同的执行环境等情况,或者是不需要原程序继续运行的场景。相比之下,如果你想在当前进程中启动一个子进程并与其交互或等待子进程结束后继续执行,应该使用 os/exec 包中的 CommandRun 等方法。

  • syscall.Exec(command, argv, os.Environ()) 的作用是:

    • command:这是要执行的新程序的路径或者可执行文件名。
    • argv:这是一个字符串切片,包含传递给新程序的命令行参数。在这个例子中,只有 command 一个参数,但实际上可以有多个,比如 argv := []string{command, arg1, arg2, ...}
    • os.Environ():这个函数返回当前进程的环境变量列表,格式为 key=value 的字符串切片。在 syscall.Exec 中,这个参数用于传递给新程序,使其继承当前进程的环境变量。

mountflags

  1. syscall.MS_NOEXEC
    设置此标志后,挂载的文件系统上的所有文件都无法被执行,即使是可执行文件。这是一项重要的安全措施,可以阻止恶意或误操作尝试执行存储在特定文件系统分区中的程序。例如,在只用于数据存储的分区上启用此选项可以增强安全性,确保即便有潜在恶意脚本或程序也不得运行。

  2. syscall.MS_NOSUID
    当挂载文件系统时带有此标志,系统会忽略文件的Set-User-ID (SUID) 和 Set-Group-ID (SGID) 位的效果。在Linux中,SUID和SGID权限通常允许用户在执行某个文件时暂时获取文件所有者的权限或执行该文件时的组权限。禁用SUID和SGID意味着,无论文件本身有何种特殊权限设定,进程在执行文件时不会继承文件所有者的用户ID或组ID,从而限制了可能因滥用特权而导致的安全风险。

  3. syscall.MS_NODEV
    使用此标志挂载文件系统时,系统将不允许任何设备特殊文件在该文件系统上工作。设备文件是用来访问硬件设备(如硬盘、终端、打印机等)的接口。禁止设备文件意味着无法在该挂载点创建或访问设备节点,这对于防止未经授权的设备访问以及增强隔离环境的安全性非常有用,比如在沙箱环境中或对安全性要求较高的文件系统分区。

syscall.Mount

syscall.Mount 是 Go 语言标准库 syscall 包中提供的一个函数,用于直接调用操作系统的系统调用来完成文件系统的挂载操作。在Linux环境下,这个函数对应的就是Linux内核提供的mount(2)系统调用接口。

函数签名一般如下所示(可能会根据不同Go版本有所变化):

func Mount(source string, target string, fstype string, flags int, data string) error

参数含义:

  • source:待挂载的文件系统源,它可以是设备名(如 /dev/sda1)、网络共享路径或者其他形式,对于虚拟文件系统如 proc,则是一个标识符字符串。

  • target:挂载点,即目标挂载路径,通常是一个已经存在的目录。

  • fstype:文件系统的类型名称,如 ext4ntfs 或者像上面提到的 proc 这样的特殊文件系统类型。

  • flags:挂载标志,是一个整数值,由多个标志位组合而成,例如 syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV,这些标志位用于控制挂载行为的不同属性。

  • data:可选的额外挂载选项,通常是一个字符串,格式取决于所使用的文件系统类型,对于一些文件系统,可能包含挂载选项的列表或其他特定信息,对于不需要额外数据的文件系统,可以传入空字符串 ""

函数执行的结果是成功或失败,若失败则返回一个错误对象。

在给出的例子中:

syscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), "")

这是在挂载Linux的虚拟文件系统 /proc/proc 目录下,并且使用了 defaultMountFlags 中定义的一系列安全相关的挂载标志。

请注意,只有包中首字母大写的函数(public函数)才能被其他包调用。首字母小写的函数(private函数)只能在包内部使用

代码

https://github.com/FULLK/llkdocker/tree/main/run_docker

最终效果

在这里插入图片描述
在这里插入图片描述

问题

发现只能run一次,下次就出现在这里插入图片描述
有待解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/309908.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GRE/MGRE详解

GRE GRE:通用路由封装,是标准的三层隧道技术,是一种点对点的隧道技术; 该技术可以实现不同的网络之间安全的访问; 如上:可以使用该技术搭建一条专线,实现公司A与分公司A1之间相互通信&#xf…

(处理流)转换流与对象流

1.字符编码与解码. (1). 字符编码 : 将字符,字符串,字符数组------> 字节,字节数组. (2). 字节,字节数组------>字符,字符串,字符数组. 如果希望程序在读取文件时(也就是解码)不…

Linux多进程开发2 - 进程间通信

1、进程间通信的概念 进程是一个独立的资源分配单元,不同进程之间的资源是独立的,没有关联,不能在一个进程中直接访问另一个进程的资源。但是,进程不是孤立的,不同的进程需要进行信息的交换和状态的传递等&…

【算法基础】插入排序与二分查找、升级二分查找

文章目录 1. 插入排序1.1 插入排序的思想1.2 插入排序的实现 2. 普通二分查找2.1 普通二分查找的思想2.2 普通二分查找的实现 3. 升级二分查找3.1 升级二分查找思想3.2 升级二分查找实现 1. 插入排序 1.1 插入排序的思想 插入排序很类似于已有一副有序的扑克牌,不断…

儿童对讲机玩具AW30N方案

一、儿童对讲机简介 儿童对讲机一种专为孩子们设计的通讯设备,可以让父母与孩子之间进行双向通讯,增强亲子关系,增强孩子的可玩性。儿童对讲机近几年发展的比较快,相比之前的方案,在设计、生产、成本都优化了很多&…

Win10 使用Telnet

命令行 telnet 127.0.0.1 80 调试是否能连接服务 输入exit 回车即可退出 相比于ping的不同

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类 运行时注解:通过反射在运行时动态处理注解的逻辑编译时注解:通过注解处理器在编译期动态处理相关逻辑 编译期注解我们常用的有Lombok,在class文件中自动生成get和set方法 解编译期处理流程最关键的一个类就…

【TCP套接字编程,UDP套接字编程】

文章目录 TCP套接字编程Socket编程Socket 编程TCP套接字编程TCPsocket编程C/S socket 交互: TCP数据结构 sockaddr_in数据结构 hostent UDP套接字编程UDP Socket编程Client/server socket 交互: UDP TCP套接字编程 Socket编程 应用进程使用传输层提供的服务才能交换报文。实现…

【嵌入式】交叉编译指南:将开源软件带到嵌入式世界

🧑 作者简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

PostgreSQL入门到实战-第二十八弹

PostgreSQL入门到实战 PostgreSQL中数据分组操作(三)官网地址PostgreSQL概述PostgreSQL中GROUPING SETS命令理论PostgreSQL中GROUPING SETS命令实战更新计划 PostgreSQL中数据分组操作(三) 使用PostgreSQL grouping sets子句在查询中生成多个分组集。 官网地址 声明: 由于操…

建筑覆膜板是干什么用的?

在现代建筑施工中,覆膜板是一种非常重要的工程材料。它俗称"模板",主要用于浇筑混凝土和钢筋结构的支撑和固定。覆膜板的质量直接关系到建筑物的施工效率和质量,因此选择一家专业、靠谱的生产厂家至关重要。 贵港市能强优品木业有限公司就是一家广西知名的建筑覆膜板…

[SystemVerilog]常见设计模式/实践

常见设计模式/实践 RTL 设计(尤其是 ASIC)的最终目标是制作出最小、最快的电路。为此,我们需要了解综合工具如何分析和优化设计。此外,我们还关注仿真速度,因为等待测试运行实际上是在浪费工程精力。虽然综合和仿真工…

【Linux】封装一下简单库 理解文件系统

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、封装一下简单库 二、理解一下stdin(0)、stdout(1)、stderr(3) 2.1、为什么要有0、1、2呢? 2.2、特点 2.3、如果我想让2也和1重定向到一个文件…

如何在Linux系统部署Joplin笔记并结合内网穿透实现无公网IP远程访问

文章目录 1. 安装Docker2. 自建Joplin服务器3. 搭建Joplin Sever4. 安装cpolar内网穿透5. 创建远程连接的固定公网地址 Joplin 是一个开源的笔记工具,拥有 Windows/macOS/Linux/iOS/Android/Terminal 版本的客户端。多端同步功能是笔记工具最重要的功能,…

华为数通方向HCIP-DataCom H12-821题库(多选题:321-340)

第321题 关于OSPF的命令描述,不正确的是: A、stub区域和totally stub区域配置了no-summary参数 B、OSPFv2和OSPF v3配置接口命令的区别是OSPF V2可以使用network命令,而OSPFv3直接 C、在接口上使能stubrouter命令用来配置次路由器为stub路由器,stub路由器可以与非stub路由 …

微软搭建零售新媒体创意工作室大举抢占数字营销广告市场

“微软新零售创意工作室新平台利用生成式人工智能,在几秒钟内轻松定制横幅广告。零售媒体预计到2026年将成为一个价值1000亿美元的行业。” 零售媒体在过去几年中发展迅速。根据eMarketerOpens在新窗口的数据,预计到2024年,仅美国的零售媒体…

【Node.js】Express学习笔记(黑马)

目录 初识 ExpressExpress 简介Express 的基本使用托管静态资源nodemon Express 路由路由的概念路由的使用 Express 中间件中间件的概念Express 中间件的初体验中间件的分类 初识 Express Express 简介 什么是 Express? 官方给出的概念:Express 是基于…

navicat远程连接mysql的异常解决-1130-2003-10061

结论: 1、修改数据库下root用户的host字段(为空或%) 2、修改 /etc/mysql/mysql.conf.d/mysqld.cnf 文件下 bind-address 的配置为 0.0.0.0 或者屏蔽此配置内容 (默认配置是: bind-address 127.0.0.1) 补充: 查看数据库下用户与host字段的关…

3D医疗图像配准 | 基于Vision-Transformer+Pytorch实现的3D医疗图像配准算法

项目应用场景 面向医疗图像配准场景,项目采用 Pytorch ViT 来实现,形态为 3D 医疗图像的配准。 项目效果 项目细节 > 具体参见项目 README.md (1) 模型架构 (2) Vision Transformer 架构 (3) 量化结果分析 项目获取 https://download.csdn.net/down…

【uniapp】vscode安装插件、ts校验、允许json文件注释

1、vscode安装的插件: uni-create-viewuni-hlperuniapp小程序扩展 2、ts校验 安装插件: pnpm i -D types/wechat-miniprogram uni-helper/uni-app-types配置tsconfig.json {"extends": "vue/tsconfig/tsconfig.json","compi…