首页 > 其他分享 >从零开始写 Docker(十)---实现 mydocker logs 查看容器日志

从零开始写 Docker(十)---实现 mydocker logs 查看容器日志

时间:2024-04-09 12:44:55浏览次数:26  
标签:容器 logs err --- mydocker error root

mydocker-logs.png

本文为从零开始写 Docker 系列第十篇,实现类似 docker logs 的功能,使得我们能够查查看容器日志。


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


推荐阅读以下文章对 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 ps 命令,可以查看到当前运行中的容器了。

本篇主要实现 mydocker logs,让我们可以随时查看容器日志。

一般来说,对于容器中运行的进程,使日志打印到标准输出是一个非常好的实现方案,因此需要将容器中的标准输出保存下来,以便需要的时候访问。

我们就以此作为思路来实现 mydocker logs 命令:

  • 启动时将容器进程的标准输出挂载到/var/lib/mydocker/containers/{containerId}/{containerId}-json.log文件中
  • mydocker logs 则读取这个文件以获取容器日志

实际上 docker 实现也类似,他会把容器日志存储在var/lib/docker/containers/{containerId}/{containerId}-json.log 文件中。

2. 实现

具体实现包括两部分:

  • 1)重定向输出到文件
  • 2)实现 mydocker logs 命令

输出重定向

首先,需要修改一下原来的实现,在创建后台运行容器的时候,把进程的标准输出重新定向一下到日志文件。

前台容器依旧打印到 Stdout 即可

func NewParentProcess(tty bool, volume, containerId string) (*exec.Cmd, *os.File) {
// 省略其他内存
	if tty {
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		// 对于后台运行容器,将 stdout、stderr 重定向到日志文件中,便于后续查看
		dirPath := fmt.Sprintf(InfoLocFormat, containerId)
		if err := os.MkdirAll(dirURL, constant.Perm0622); err != nil {
			log.Errorf("NewParentProcess mkdir %s error %v", dirURL, err)
			return nil, nil
		}
		stdLogFilePath := dirPath + LogFile
		stdLogFile, err := os.Create(stdLogFilePath)
		if err != nil {
			log.Errorf("NewParentProcess create file %s error %v", stdLogFilePath, err)
			return nil, nil
		}
		cmd.Stdout = stdLogFile
		cmd.Stderr = stdLogFile
	}
// ...
}

实现 logs 命令

在 main_command.go 中添加一个 logCommand:

var logCommand = cli.Command{
    Name:  "logs",
    Usage: "print logs of a container",
    Action: func(context *cli.Context) error {
       if len(context.Args()) < 1 {
          return fmt.Errorf("please input your container name")
       }
       containerName := context.Args().Get(0)
       logContainer(containerName)
       return nil
    },
}

并加到 main 函数中。

func main(){
  // 省略其他内容
  app.Commands = []cli.Command{
       initCommand,
       runCommand,
       commitCommand,
       listCommand,
       logCommand,
    }
}

具体实现如下:

func logContainer(containerName string) {
    logFileLocation := fmt.Sprintf(container.InfoLocFormat, containerName) + container.LogFile
    file, err := os.Open(logFileLocation)
    defer file.Close()
    if err != nil {
       log.Errorf("Log container open file %s error %v", logFileLocation, err)
       return
    }
    content, err := ioutil.ReadAll(file)
    if err != nil {
       log.Errorf("Log container read file %s error %v", logFileLocation, err)
       return
    }
    _, err = fmt.Fprint(os.Stdout, string(content))
    if err != nil {
       log.Errorf("Log container Fprint  error %v", err)
       return
    }
}

实现很简单,根据 containerId 拼接出完整路径,读取文件内容并重定向到标准输出即可。

3. 测试

启动一个后台容器

root@mydocker:~/feat-logs/mydocker# go build .
root@mydocker:~/feat-logs/mydocker# ./mydocker run -d -name mytop top
{"level":"info","msg":"createTty false","time":"2024-01-26T11:25:53+08:00"}
{"level":"info","msg":"resConf:\u0026{ 0  }","time":"2024-01-26T11:25:53+08:00"}
{"level":"info","msg":"busybox:/root/busybox busybox.tar:/root/busybox.tar","time":"2024-01-26T11:25:53+08:00"}
{"level":"error","msg":"mkdir dir /root/merged error. mkdir /root/merged: file exists","time":"2024-01-26T11:25:53+08:00"}
{"level":"error","msg":"mkdir dir /root/upper error. mkdir /root/upper: file exists","time":"2024-01-26T11:25:53+08:00"}
{"level":"error","msg":"mkdir dir /root/work error. mkdir /root/work: file exists","time":"2024-01-26T11:25:53+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-26T11:25:53+08:00"}
{"level":"info","msg":"command all is top","time":"2024-01-26T11:25:53+08:00"}

查看容器列表

root@mydocker:~/feat-logs/mydocker# ./mydocker ps
{"level":"error","msg":"read file /var/lib/mydocker/containers/0439540405/config.json error open /var/lib/mydocker/containers/0439540405/config.json: no such file or directory","time":"2024-01-26T11:26:13+08:00"}
{"level":"error","msg":"get container info error open /var/lib/mydocker/containers/0439540405/config.json: no such file or directory","time":"2024-01-26T11:26:13+08:00"}
ID           NAME         PID         STATUS      COMMAND     CREATED
0439540405   mytop        171754      running     top         2024-01-26 11:25:53

容器 Id 为 0439540405,查看对应目录是否生成了日志文件

root@mydocker:~/feat-logs/mydocker# ls /var/lib/mydocker/containers/0439540405/
0439540405-json.log config.json

其中的0439540405-json.log 就是日志文件,config.json 则是上一次添加的容器信息记录文件。

查看日志文件内容

root@mydocker:~/feat-logs/mydocker# cat /var/lib/mydocker/containers/0439540405/0439540405-json.log
Mem: 1793456K used, 241932K free, 1064K shrd, 91276K buff, 1354272K cached
CPU:  0.4% usr  0.0% sys  0.0% nic 99.3% idle  0.0% io  0.0% irq  0.2% sirq
Load average: 0.01 0.01 0.00 1/141 4
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND

说明,日志存储是正常的。

接下里执行 mydocker logs 看看是否能查询到日志

root@mydocker:~/feat-logs/mydocker# ./mydocker logs 0439540405
Mem: 1793424K used, 241964K free, 1064K shrd, 91316K buff, 1354280K cached
CPU:  0.0% usr  0.0% sys  0.0% nic  100% idle  0.0% io  0.0% irq  0.0% sirq
Load average: 0.00 0.00 0.00 1/141 4
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND

可以看到,mydocker logs 命令成功运行并输出了容器的日志。

至此,说明我们的 mydocker logs 命令实现是 ok 的。

4. 小结

本篇主要实现 mydocker logs 命令,和 docker 实现基本类似:

  • 容器启动把 stdout、stderr 重定向到 /var/lib/mydocker/container/{containerId}/{containerId}-json.log 文件
  • 执行 mydocker logs 则根据容器 Id 找到对应文件,读取文件内容并打印

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



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

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

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

# 克隆代码
git clone -b feat-logs https://github.com/lixd/mydocker.git
cd mydocker
# 拉取依赖并编译
go mod tidy
go build .
# 测试 
./mydocker run -d -name c1 top
# 查看容器 Id
./mydocker ps
# 根据 Id 查询日志
./mydocker logs ${containerId}

标签:容器,logs,err,---,mydocker,error,root
From: https://www.cnblogs.com/KubeExplorer/p/18123727

相关文章

  • 若依RuoYi-Vue代码生成,新建一个增删改查模块
    启动ruoyi-ui,登录前端后台 以cti_faq问答对表为例。首先在mysql数据库中建张cti_faq表CREATETABLE`cti_faq`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'编号',`question`varchar(255)DEFAULTNULLCOMMENT'问题内容',`answer`textCOMMENT'答案......
  • 【攻防实操系列+域渗透】--安装域控(Windows-Server-2008-R2-x64)教程
    1.创建windows2008R2虚拟机选完全安装。第一个是标准版功能很少。不建议选。另外两个任意选。我选的是Enterprse企业版。❗❗❗注意:需要提前了解域控的密码复杂度规则。密码一定要自己记住!!!密码①可以看到界面非常小,不方便操作。❗❗❗需要安装vm......
  • AtCoder Beginner Contest 348 A-F 题解
    A-PenaltyKickQuestion高桥将在一场足球比赛中获得\(N\)个点球。对于第\(i\)个罚球,如果\(i\)是\(3\)的倍数,他将罚球失败,否则罚球成功。请打印他罚球的结果。Solution当\(i\%3==0\)时说明能被\(3\)整除Code#include<bits/stdc++.h>usingnamespacest......
  • Linux mformat命令教程:MS-DOS文件系统的磁盘格式化工具(附实例详解和注意事项)
    Linuxmformat命令介绍mformat是一个用于在低级格式化的磁盘上添加MS-DOS文件系统的命令。它可以在已经通过Unix低级格式化的磁盘上添加一个最小的MS-DOS文件系统(包括引导扇区、FAT和根目录)。Linuxmformat命令适用的Linux版本mformat命令在大多数Linux发行版中都可以使......
  • STLINK-V3PWR连接STM32最小系统板方法(含引脚分布)
    前段时间导师给我了一个STLINK-V3PWR,让我试着用它下载程序到STM32单片机上,我找了半天发现网上资源挺少的,于是自己搞了一下,从官网下载了相关的规格书,然后连了一下。下面是我自己找的官方资源然后翻译的。下面是STLINK-V3PWR的调试端口引脚分布。手上只有STM32F103C6T6A......
  • NAT转换-4.9
    *****************************************************************************源NAT技术只对源地址进行转换;可以分为NATNO-PAT、NAPT、EASYIP和三元组NAT*******************************************************************************NATNO-PAT非端口地址转换,只转......
  • 开发Element-UI的Table 组件列显示隐藏,列表数据勾选批量导出/全量导出,显示导出进度并
    #用法<TabColDisplay:total="total"api-url="hgp/order"api-name="hgpLocalList":s-param="listQuery":select-ids="selIds"title="快速......
  • 大话设计模式-简单工厂模式
    简单工厂模式面向对象和面向过程在大话设计模式中,为了引出简单工厂模式这一个话题,作者举了一个计算器的例子,通过不断的去优化计算器功能的实现代码,来帮助我们理解面向对象这一概念。首先是初始的代码,逻辑简单明了,是面向过程的方法去解决的,用计算机的方式去思考问题,直接判断输......
  • 百度公司真的太差劲了--客服全是套话,规则全是霸王条款
    结论与应对:对百度需要避而远之,尽量不要产生相关联系,不可信任。主题:百度公司真的太差劲了--客服全是套话,规则全是霸王条款。事情内容:1.2019年使用百度网盘,将自己很多学习资料做了存储,也存在BT下载的盗版电影;2.结果突然被告知因为涉及XXOO,百度网盘永久封......
  • el-table 表头添加Tooltip render-header动态传参
    给el-table表头添加Tooltip,光标移动到表头问号区域,自动弹出tooltip提示render-header传参方式<el-table-columnprop="usedCredit"label="已占授信额度(元)"width="140"header-align="center"align=&......