自己动手写Docker系列 -- 5.4实现进入容器的namespace,exec命令

本文介绍如何实现进入Docker容器的namespace,通过Cgo调用setns系统调用来实现在Go程序中执行exec命令。文章详细解释了Cgo代码的编写和exec命令的工作原理,包括如何借助/proc/self/exe来确保C代码在exec时运行,从而成功进入命名空间。
摘要由CSDN通过智能技术生成

简介

在上篇中我们实现了将容器后台运行,本篇中我们将实现docker的ps命令,查看当前正在运行中的容器列表

源码说明

同时放到了Gitee和Github上,都可进行获取

本章节对应的版本标签是:5.4,防止后面代码过多,不好查看,可切换到标签版本进行查看

代码实现

这一部分实现起来就有点麻烦了,其中的一个nsenter始终不能运行正常,折腾了好一阵子发现,需要导出包才行,相关的会在代码中详细的说明

首先我们是需要使用setns去再次进入到我们容器的namespace中:

setns是一个系统调用,可以根据提供的PID再次进入到指定的Namespace 中。它需要先打开/proc/[pid]/ns/文件夹下对应的文件,然后使当前进程进入到指定的Namespace 中

但是一个具有多线程的进程是无法使用setns调用进入到对应的命名空间的,而Go启动一个程序就会进入多线程状态,所以无法简单使用命令调用去实现这个功能,需要借助C来实现

Cgo是一个很炫酷的功能,允许Go程序去调用C的函数与标准库。你只需要以一种特殊的方式在Go的源代码里写出需要调用的C的代码,Cgo就可以把你的C源码文件和Go文件整合成一个包

Cgo代码实现

新建一个文件夹 nsenter,新建文件:nsenter.go

编写Cgo的进入命名空间的代码,如下:

package nsenter

/*
#define _GNU_SOURCE
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

// 构造函数:这里作用是在被引用的时候,这段代码就会执行
__attribute__((constructor)) static void enter_namespace(void) {
	char *mydocker_pid;
    // 从环境变量中获取需要进入的PID
    // 如果没有PID,直接退出,不执行后面的处理逻辑
	mydocker_pid = getenv("mydocker_pid");
	if (mydocker_pid) {
		fprintf(stdout, "got mydocker_pid=%s\n", mydocker_pid);
	} else {
		fprintf(stdout, "missing mydocker_pid env skip nsenter");
		return;
	}
	char *mydocker_cmd;
    // 从环境变量中获取需要执行的命令,没有命令,直接退出
	mydocker_cmd = getenv("mydocker_cmd");
	if (mydocker_cmd) {
		fprintf(stdout, "got mydocker_cmd=%s\n", mydocker_cmd);
	} else {
		fprintf(stdout, "missing mydocker_cmd env skip nsenter");
		return;
	}
	int i;
	char nspath[1024];
	char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" };

	for (i=0; i<5; i++) {
		sprintf(nspath, "/proc/%s/ns/%s", mydocker_pid, namespaces[i]);
		int fd = open(nspath, O_RDONLY);
        / 调用setns进入对应的namespace
		if (setns(fd, 0) == -1) {
			fprintf(stderr, "setns on %s namespace failed: %s\n", namespaces[i], strerror(errno));
		} else {
			fprintf(stdout, "setns on %s namespace succeeded\n", namespaces[i]);
		}
		close(fd);
	}
    // 进入后执行指定的命令
	int res = system(mydocker_cmd);
	exit(0);
	return;
}
*/
import "C"

如上所示,这样就把进入命名空间的Cgo文件写好了,具体使用在后面会详细说明

Exec命令实现

我们在main中增加exec命令:

func main() {
   
	......
	app.Commands = []cli.Command{
   
		command.InitCommand,
		command.RunCommand,
		command.CommitCommand,
		command.ListCommand,
		command.LogCommand,
		command.ExecCommand,
	}
    ......
}

在main_command.go文件,增加Exec指令解析

var ExecCommand = cli.Command{
   
	Name:  "exec",
	Usage: "exec a command into container",
	Action: func
进入docker exec -it命令是用于在已经运行的容器中执行命令。其中,exec是执行命令的意思,-it参数表示以交互式的方式进入容器。在命令中需要指定容器的ID或名称,以及要执行的命令。例如,使用以下命令可以进入一个名为container_id的容器docker exec -it container_id /bin/bash 这个命令进入容器并打开一个交互式的bash终端,允许您在容器中执行命令和操作文件系统。您可以在终端中执行任何命令,就像在本地计算机上一样。注意,您需要在宿主机上安装Docker,并且容器必须处于运行状态才能使用这个命令。 另外还可以使用docker attach命令进入容器,这个命令docker exec类似,也可以进入容器并与其交互。使用docker attach命令时,不需要指定要执行的命令,而是直接进入容器的终端。例如,可以使用以下命令进入一个名为container_id的容器docker attach container_id [2] 需要注意的是,使用docker attach命令进入容器时,如果在容器中按下Ctrl+C会导致容器停止运行。因此,如果只需要执行命令而不需要保持交互式会话,建议使用docker exec命令。 希望这个解答对您有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [dockerexc:在所选容器上运行docker exec -it container_id binbash](https://download.csdn.net/download/weixin_42113754/18572638)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [docker run -it 和 docker exec -it](https://blog.csdn.net/wdadas/article/details/107129528)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [docker exec -it tomcat01 ip addr](https://blog.csdn.net/m0_37800387/article/details/124163197)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值