从零开始写 Docker(十三)---实现 mydocker rm 删除容器

mydocker-rm.png

本文为从零开始写 Docker 系列第十三篇,实现类似 docker rm 的功能,使得我们能够删除容器。


完整代码见:https://github.com/lixd/mydocker
欢迎 Star

推荐阅读以下文章对 docker 基本实现有一个大致认识:

  • 核心原理:深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs
  • 基于 namespace 的视图隔离:探索 Linux Namespace:Docker 隔离的神奇背后
  • 基于 cgroups 的资源限制
    • 初探 Linux Cgroups:资源控制的奇妙世界
    • 深入剖析 Linux Cgroups 子系统:资源精细管理
    • Docker 与 Linux Cgroups:资源隔离的魔法之旅
  • 基于 overlayfs 的文件系统:Docker 魔法解密:探索 UnionFS 与 OverlayFS
  • 基于 veth pair、bridge、iptables 等等技术的 Docker 网络:揭秘 Docker 网络:手动实现 Docker 桥接网络


开发环境如下:

root@mydocker:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.2 LTS
Release:	20.04
Codename:	focal
root@mydocker:~# uname -r
5.4.0-74-generic

注意:需要使用 root 用户

1. 概述

之前实现了 mydocker stop 能够停止后台运行的容器,那么,对于已经处于停止状态的容器,还剩余一个删除操作来补全容器的整个生命周期。

本篇就会完成这最后一步的清理工作,实现mydocker rm 命令,让我们能够直接删除已经停止的容器。

2. 实现

mydocker rm 实现起来很简单,主要是文件操作,因为容器对应的进程已经被停止,所以只需要将对应记录文件信息的目录删除即可。

docker 可以通过 -f 强制删除运行中的容器,具体见 moby/delete.go#L92,这里也加一下,指定 force 时先 stop 再删除即可。

removeCommand

同样是先定义 removeCommand,然后再添加到 main 函数中。

var removeCommand = cli.Command{Name:  "rm",Usage: "remove unused containers,e.g. mydocker rm 1234567890",Flags: []cli.Flag{cli.BoolFlag{Name:  "f", // 强制删除Usage: "force delete running container,",}},Action: func(context *cli.Context) error {if len(context.Args()) < 1 {return fmt.Errorf("missing container id")}containerId := context.Args().Get(0)force := context.Bool("f")removeContainer(containerId, force)return nil},
}

这里只做参数解析,拿到 containerId 传递给 removeContainer 即可。

removeContainer

removeContainer 则是 rm 命令的真正实现,根据 Id 拿到容器信息,然后先判断状态:

  • STOP 状态,则直接删除
  • RUNNING 状态,如果带了 force flag 则先 Stop 然后再删除,否则打印错误信息
func removeContainer(containerId string, force bool) {containerInfo, err := getInfoByContainerId(containerId)if err != nil {log.Errorf("Get container %s info error %v", containerId, err)return}switch containerInfo.Status {case container.STOP: // STOP 状态容器直接删除即可dirPath := fmt.Sprintf(container.InfoLocFormat, containerId)if err = os.RemoveAll(dirPath); err != nil {log.Errorf("Remove file %s error %v", dirPath, err)return}case container.RUNNING: // RUNNING 状态容器如果指定了 force 则先 stop 然后再删除if !force {log.Errorf("Couldn't remove running container [%s], Stop the container before attempting removal or"+" force remove", containerId)return}stopContainer(containerId)removeContainer(containerId, force)default:log.Errorf("Couldn't remove container,invalid status %s", containerInfo.Status)return}
}

3. 测试

删除 STOP 状态容器

首先创建一个 detach 容器

root@mydocker:~/feat-rm/mydocker# go build .
root@mydocker:~/feat-rm/mydocker# ./mydocker run -d -name rm1 top
{"level":"info","msg":"createTty false","time":"2024-01-30T15:11:20+08:00"}
{"level":"info","msg":"resConf:\u0026{ 0  }","time":"2024-01-30T15:11:20+08:00"}
{"level":"info","msg":"busybox:/root/busybox busybox.tar:/root/busybox.tar","time":"2024-01-30T15:11:20+08:00"}
{"level":"error","msg":"mkdir dir /root/merged error. mkdir /root/merged: file exists","time":"2024-01-30T15:11:20+08:00"}
{"level":"error","msg":"mkdir dir /root/upper error. mkdir /root/upper: file exists","time":"2024-01-30T15:11:20+08:00"}
{"level":"error","msg":"mkdir dir /root/work error. mkdir /root/work: file exists","time":"2024-01-30T15:11:20+08:00"}
{"level":"info","msg":"mount overlayfs: [/usr/bin/mount -t overlay overlay -o lowerdir=/root/busybox,upperdir=/root/upper,workdir=/root/work /root/merged]","time":"2024-01-30T15:11:20+08:00"}
{"level":"info","msg":"command all is top","time":"2024-01-30T15:11:20+08:00"}

mydocker ps 查看一下:

root@mydocker:~/feat-rm/mydocker# ./mydocker ps
ID           NAME        PID         STATUS      COMMAND     CREATED
0394026801   rm1         181151      running     top         2024-01-30 15:11:20

可以看到,容器正处于 running 状态。

尝试直接删除容器:

root@mydocker:~/feat-rm/mydocker# ./mydocker rm 0394026801
{"level":"error","msg":"Couldn't remove running container [0394026801], Stop the container before attempting removal or force remove","time":"2024-01-30T15:12:12+08:00"}

根据错误信息可知,不能直接删除运行中的容器

于是先把容器 stop 掉:

root@mydocker:~/feat-rm/mydocker# ./mydocker stop 0394026801
root@mydocker:~/feat-rm/mydocker# ./mydocker ps
ID           NAME        PID         STATUS      COMMAND     CREATED
0394026801   rm1                     stopped     top         2024-01-30 15:11:20

此时已经是 stopped 状态,可以执行删除了。

root@mydocker:~/feat-rm/mydocker# ./mydocker rm 0394026801
root@mydocker:~/feat-rm/mydocker# ./mydocker ps
ID          NAME        PID         STATUS      COMMAND     CREATED

可以看到,容器信息已经不见了,说明删除成功。

强制删除 RUNNING 状态容器

再测试一下指定 -f 时能否删除 RUNNING 状态的容器。

首先,也是启动一个 detach 容器

root@mydocker:~/feat-rm/mydocker# ./mydocker run -d -name rm2 top
{"level":"info","msg":"createTty false","time":"2024-01-30T15:13:44+08:00"}
{"level":"info","msg":"resConf:\u0026{ 0  }","time":"2024-01-30T15:13:44+08:00"}
{"level":"info","msg":"busybox:/root/busybox busybox.tar:/root/busybox.tar","time":"2024-01-30T15:13:44+08:00"}
{"level":"error","msg":"mkdir dir /root/merged error. mkdir /root/merged: file exists","time":"2024-01-30T15:13:44+08:00"}
{"level":"error","msg":"mkdir dir /root/upper error. mkdir /root/upper: file exists","time":"2024-01-30T15:13:44+08:00"}
{"level":"error","msg":"mkdir dir /root/work error. mkdir /root/work: file exists","time":"2024-01-30T15:13:44+08:00"}
{"level":"info","msg":"mount overlayfs: [/usr/bin/mount -t overlay overlay -o lowerdir=/root/busybox,upperdir=/root/upper,workdir=/root/work /root/merged]","time":"2024-01-30T15:13:44+08:00"}
{"level":"info","msg":"command all is top","time":"2024-01-30T15:13:44+08:00"}

查看容器信息

root@mydocker:~/feat-rm/mydocker# ./mydocker ps
ID           NAME        PID         STATUS      COMMAND     CREATED
9293725578   rm2         181202      running     top         2024-01-30 15:13:44
root@mydocker:~/feat-rm/mydocker# ps -ef|grep top
root      181202       1  0 15:13 pts/10   00:00:00 top

普通删除和强制删除

root@mydocker:~/feat-rm/mydocker# ./mydocker rm 9293725578
{"level":"error","msg":"Couldn't remove running container [9293725578], Stop the container before attempting removal or force remove","time":"2024-01-30T15:15:10+08:00"}
root@mydocker:~/feat-rm/mydocker# ./mydocker rm -f 9293725578

普通删除提示失败,强制删除则成功了,看下是否真的删掉了

root@mydocker:~/feat-rm/mydocker# ./mydocker ps
ID          NAME        PID         STATUS      COMMAND     CREATED
root@mydocker:~/feat-rm/mydocker# ps -ef|grep top
root      181231  177607  0 15:15 pts/10   00:00:00 grep --color=auto top

容器信息删除了,进程也消失了,说明删除是成功的。

4. 小结

本篇主要实现 mydocker rm 命令,根据 containerId 找到记录容器信息的目录,然后删除该目录以实现删除容器的效果。

对于 RUNNING 状态容器可以指定-f 强制删除,或者先执行 stop 命令停止容器。


**【从零开始写 Docker 系列】**持续更新中,搜索公众号【探索云原生】订阅,文章。



完整代码见:https://github.com/lixd/mydocker
欢迎关注~

相关代码见 feat-rm 分支,测试脚本如下:

需要提前在 /root 目录准备好 busybox.tar 文件,具体见第四篇第二节。

# 克隆代码
git clone -b feat-rm https://github.com/lixd/mydocker.git
cd mydocker
# 拉取依赖并编译
go mod tidy
go build .
# 测试 
./mydocker run -d -name c1 top
# 查看容器 Id
./mydocker ps
# stop 停止指定容器
./mydocker stop ${containerId}

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

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

相关文章

C语言柔性数组、柔性数组的特点、柔性数组的使用等的介绍

文章目录 前言一、柔性数组二、柔性数组的特点三、柔性数组的使用总结 前言 C语言柔性数组、柔性数组的特点、柔性数组的使用等的介绍。 一、柔性数组 C99中&#xff0c;结构中的最后一个元素是允许未知大小的数组&#xff0c;这就叫做【柔性数组】成员。 struct S {int i;i…

那些年使用过的UA头

一些WAF会根据扫描器UA头进行屏蔽 UA头 在sqlmap 中可以使用 –random-agnet /xx.txt 来更换UA头 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60 Opera/8.0 (Windows NT 5.1; U; en) Mozi…

谷歌CEO最新访谈:AI浪潮仍处于早期阶段,公司未来最大威胁是执行力不足

作为搜索领域无可争议的霸主&#xff0c;谷歌改变了我们生活的方方面面&#xff0c;从日常琐事到工作事务&#xff0c;再到我们的沟通方式。多年来&#xff0c;谷歌一直是互联网的窗口&#xff0c;为我们提供大量知识和信息&#xff0c;但如今&#xff0c;随着其他类似平台的崛…

Ubuntu安装Syzkaller——相关报错

目录 一:网络 二:安装go编译器 141 objtool: Dont fail on missing symbol table

HarmonyOS开发之ArkTS使用:用户登录页面应用

目录 目录 前言 关于HarmonyOS 环境准备 新建项目 设计用户登录页面 1. 布局设计 2. 编写ArkTS代码 运行和测试 结束语 前言 随着HarmonyOS&#xff08;鸿蒙操作系统&#xff09;的不断发展&#xff0c;越来越多的开发者开始投入到这个全新的生态系统中&#xff0c;而…

element-ui select 下拉框做成下拉加载更多

注意&#xff1a; vue 版本需要 ≥ 3.3 1、html <el-selectv-model"relation_type"placeholder"请选择合作类型"ref"select" ><el-optionv-for"item in cooperationTypeList":key"item.value":label"item.la…

车载测试系列:车载测试Bug定位与分析

车载Bug定位 1.1 模拟复现条件 能够复现bug才能对问题进行定位、解决以及验证。找到bug存在的特定的条件&#xff0c;进行重现。对于依赖外部输入的条件&#xff0c;如果条件比较复杂难以模拟可以在程序里预设直接进入对应状态。 1.2 打印Log 根据问题的现象&#xff0c;在…

Spring-依赖来源

依赖来源 1 Spring BeanDefinition&#xff08;xml,注解&#xff0c;BeanDefinitionBuilder, 还有API实现的单例对象&#xff09; 2 Spring 内建BeanDefinition 3 内建单例对象 依赖注入和依赖查找的区别 Context.refresh() 的时候会调用这个方法&#xff1a;prepareBeanF…

爬虫跟代理ip有什么不同

爬虫与代理IP的区别主要体现在它们的定义、功能和使用场景上。以下是对这两者的详细比较&#xff1a; 定义 爬虫&#xff1a; 爬虫是一种自动抓取互联网信息的脚本或者程序。它可以按照一定的规则&#xff0c;自动化地浏览网络中的信息&#xff0c;并将这些信息抓取下来&#x…

深入解析C#中的接口设计原则

深入解析C#中的接口设计原则 目录 深入解析C#中的接口设计原则 一、接口设计的SOLID原则 二、接口设计的最佳实践 三、接口设计的高级技术 四、结论 接口在面向对象编程中扮演着至关重要的角色。它们是定义行为契约的一种方式&#xff0c;允许实现者提供这些行为的具体实现…

扩展学习|结合故事的力量和数字的力量:混合方法研究和混合研究综述

文献来源&#xff1a;Pluye, Pierre, and Quan Nha Hong. "Combining the power of stories and the power of numbers: mixed methods research and mixed studies reviews." Annual review of public health 35 (2014): 29-45. 文献获取&#xff1a;链接&#xff1…

最靠谱线上线下相亲交友婚恋脱单渠道指南大全,单身必看!

刚好在30岁的年纪把自己嫁出去啦。以下这些都是我经历过的相亲途径&#xff0c;分享出来&#xff0c;希望能帮到大家 一.线上小程序/App 1.单身狗解救平台&#xff08;高质量人多&#xff0c;工作学历实名认证&#xff0c;你可能看到眼花&#xff0c;自己得有自己辨别力&#x…

<sa8650> snapdragon-auto-hqx-4-5-6-0基线代码camera开发错误记录

<sa8650> snapdragon-auto-hqx-4-5-6-0基线代码camera开发错误记录 一、 qcxserver自启动关不掉二、 qcxserver启动后串行器(MAX96717)detect不到?三、 qcarcam_test运行后系统log提示QCarCamReserve错误四、 tuning错误导致的异常DumpCore本文主要记录CAMERA开发过程中的一…

[ 项目 ] tcmalloc简化版—高并发内存池

目录 前言 基本介绍 高并发 内存池 定长内存池 基本介绍 框架设计 具体实现 性能测试 整体框架介绍 申请内存过程 threadcache 1.基本介绍 2.具体实现 centralcache 1.基本介绍 2.具体实现 pagecache 1.基本介绍 2.具体实现 申请内存连通 释放内存过…

探索智能编程新境界:我与Baidu Comate的独特体验之旅

文章目录 一、认识Baidu Comate二、VS Code安装Baidu Comate教程三、Baidu Comate功能体验功能概览具体功能1.根据注释自动生成代码2.函数注释3.行间注释4.代码解释5.生成单元测试6.代码优化7.答疑解惑 四、交互体验五、总结 一、认识Baidu Comate ✨Baidu Comate插件是一款基…

QT---day4事件

1、思维导图 2、 头文件 #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include<QIcon> //图标类 #include<QLabel> //标签类 #include<QMovie> //动图类 #include<QLineEdit> //行编辑器类 #include<QPushButton> //按钮…

阿里云开发uniapp之uni-starter

一、为什么使用uni-starter uni-starter是集成商用项目常见功能的、云端一体应用快速开发项目模版。 一个应用有很多通用的功能&#xff0c;比如登录注册、个人中心、设置、权限管理、拦截器、banner... uni-starter将这些功能都已经集成好&#xff0c;另外&#xff0c;uni-s…

QLabel文本

1. 文本自动换行 label->setWordWrap(true); 2. 文本居中显示 要将QLabel中的文本居中显示&#xff0c;可以使用setAlignment()方法来设置文本的对齐方式为居中。以下是一个示例代码&#xff1a; #include <QApplication> #include <QLabel>int main(int arg…

MySQL慢查询优化【三】

当面对MySQL中的慢查询时&#xff0c;可以根据不同的情况采取相应的优化方案。以下是几种常见的慢SQL情况及其对应的优化方案&#xff1a; 缺少索引的情况&#xff1a; SELECT * FROM orders WHERE customer_id 1000;如果orders表中的customer_id列没有索引&#xff0c;这个…

C:STDIN_FILENO和stdin的区别

1.STDIN_FILENO定义于文件/usr/include/unistd.h #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */ 作为read&#xff0c;write&#…