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

news2024/11/25 10:45:09

文章目录

  • 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 main

import (
    "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.coloradmin.cn/o/1578947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XC7A35T-2FGG484 嵌入式FPGA现场可编程门阵列 Xilinx

XC7A35T-2FGG484 是一款由Xilinx(赛灵思)制造的FPGA(现场可编程门阵列)芯片 以下是XC7A35T-2FGG484 的主要参数: 1. 系列:Artix-7 2. 逻辑单元数量:33280个 3. 工艺技术:28nm 4. …

element问题总结之el-table使用fixed中 header换行后固定行错位问题/固定列下陷问题

固定列下陷问题 效果图问题描述解决方案1、为table添加ref2、调用节点重新自适应方法doLayout3、在操作表头的时候触发的函数header-dragend绑定doLayout方法4、成功解决 效果图 问题描述 在使用el-table的fixed中,发现如果header拖拽文本折行的时候会出现下陷 解…

Go操作Kafka之kafka-go

Kafka是一种高吞吐量的分布式发布订阅消息系统,本文介绍了如何使用kafka-go这个库实现Go语言与kafka的交互。 Go社区中目前有三个比较常用的kafka客户端库 , 它们各有特点。 首先是IBM/sarama(这个库已经由Shopify转给了IBM),之…

TCP/IP协议、HTTP协议和FTP协议等网络协议简介

文章目录 一、常见的网络协议二、TCP/IP协议1、TCP/IP协议模型被划分为四个层次2、TCP/IP五层模型3、TCP/IP七层模型 三、FTP网络协议四、Http网络协议1、Http网络协议简介2、Http网络协议的内容3、HTTP请求协议包组成4、HTTP响应协议包组成 一、常见的网络协议 常见的网络协议…

uniapp如何配置后使用uni.chooseLocation等地图位置api

在uniapp中想要使用uni.getLocation、uni.chooseLocation ……api的时候我们需要在小程序就开启配置,不然无法使用。 第一步:首先找到manifest.json 第二步:点击源码视图 第三步:在 mp-weixin 加入下面代码 "permission&…

DC-2靶机知识点

知识点总结 1.IP访问与域名访问 2.端口扫描 3.目录扫描 4.cewl密码生成器 5.指纹探测 6.爆破ssh 7.msf的使用 8.rbash逃逸 9.git提权 靶机,攻击机就不多说了,给个靶机地址 https://download.vulnhub.com/dc/DC-2.zip 环境配置 因为访问该靶机…

Python数学建模学习-莱斯利(Leslie)种群模型

Leslie模型是一种用于离散时间的生物种群增长模型,经常用于描述年龄结构对种群增长的影响。在1945年,人口生态学家Patrick H. Leslie(莱斯利)为了研究具有离散年龄结构的种群,特别是对于有不同年龄阶段的生物&#xff…

鸿蒙OS开发实战:【自动化测试框架】使用指南

概述 为支撑HarmonyOS操作系统的自动化测试活动开展,我们提供了支持JS/TS语言的单元及UI测试框架,支持开发者针对应用接口进行单元测试,并且可基于UI操作进行UI自动化脚本的编写。 本指南重点介绍自动化测试框架的主要功能,同时…

三行命令解决Ubuntu Linux联网问题

一开始我找到官方文档描述可以通过命令行连接到 WiFi 网络:https://cn.linux-console.net/?p10334#google_vignette 但是我的 $ ls /sys/class/net 命令无法显示无线网络接口,那么没有无线网卡? 所以我参照其他的博客在终端超级用户的权…

JUC:ScheduledThreadPoolExecutor 延迟任务线程池的使用

文章目录 ScheduledThreadPoolExecutortimer(不建议用)ScheduledThreadPoolExecutor处理异常应用 ScheduledThreadPoolExecutor timer(不建议用) timer也可以进行延迟运行,但是会有很多问题。 比如task1运行时间超过…

FOR循环

oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 前面两种循环都要根据条件是否成立而确定循环体的执行,具体循环体执行多少次事先并不知道。 FOR 循环可以控制循环执行的次数,由循环变量控制循环体的…

学透Spring Boot — 005. 深入理解 Spring Boot Starter 依赖管理

前面的文章直观的展示了,使用Spring Boot 集成 Hibernate 和手动集成 Hibernate 之间差距。 一个比喻 工作中使用过Spring Boot一段时间后,我越来越感觉到Spring Boot Starter带来的便利性。 使用手动集成 Hibernate, 就像去电脑城配电脑&…

二叉树的遍历的递归与非递归算法

一.二叉树的遍历: 按照一定规律对二叉树的每个结点进行访问且仅访问一次; 这里的访问:可以是计算二叉树中的结点数据,打印该结点的信息,也可以是对结点进行的任何其它操作! 为什么需要遍历二叉树&#x…

EditPlus来啦(免费使用!)

hello,我是小索奇 今天推荐一款编辑器,是索奇学习JavaSE时入手滴,非常好用哈,小索奇还是通过老杜-杜老师入手滴,相信很多人也是通过老杜认识嘞,来寻找破解版或者准备入手这个间接使用的编辑器~ EditPlus是…

在Ubuntu上搭建Prometheus + Grafana监控系统

1.Prometheus 部署 从官网下载页面找到最新的二进制文件下载 cd ~ curl -LO https://github.com/prometheus/prometheus/releases/download/v2.51.1/prometheus-2.51.1.linux-amd64.tar.gz将文件解压到指定目录 tar xf prometheus-2.51.1.linux-amd64.tar.gz -C /usr/local为…

⼿机客户端画K线图流程

优质博文:IT-BLOG-CN 一、什么是K线流程 K线图是一种用于展示金融市场价格走势的图表。它通常由四个关键价格点组成,即开盘价、收盘价、最高价和最低价。K线图的流程可以简单概括为以下几个步骤: 【1】收集数据: 首先&#xff0c…

Oracle 正则表达式

一、Oracle 正则表达式相关函数 (1) regexp_like :同 like 功能相似(模糊 匹配) (2) regexp_instr :同 instr 功能相似(返回字符所在 下标) (3) regexp_substr : 同 substr 功能相似&…

虚拟网络设备与Linux网络协议栈

在现代计算环境中,虚拟网络设备在实现灵活的网络配置和隔离方面发挥了至关重要的作用🔧,特别是在容器化和虚拟化技术广泛应用的今天🌐。而Linux网络协议栈则是操作系统处理网络通信的核心💻,它支持广泛的协…

点击上传文件

一、页面样式: (1)点击前: (2)点击后: 设计:①自定义elementPlus图标;②使用Tooltip实现鼠标悬浮按钮上出现文字提示;③上传与更换的切换样式;…

全栈开发医疗小程序 SpringBoot2.X + Vue + UniAPP 带源码

看到好多坛友都在求SpringBoot2.X Vue UniAPP,全栈开发医疗小程序 – 带源码课件,我看了一下,要么链接过期,要么课件有压缩密码。特意整理了一份分享给大家,个人认为还是比较全面的。希望对大家有所帮助!…