侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

golang实现对docker容器心跳监控功能

Docker  /  管理员 发布于 5年前   308

自己写的go程序放到线上本来编译成二进制扔上去就行啦,但是怀着一颗docker的心,最终还是将它放到docker容器中运行起来了,运行起来也ok,一个最小容器64M,统一管理起来也方便,但是毕竟是个线上长驻内存的服务程序,万一跑挂了怎么办,如何才能监控它,直接上go代码,网上代码,略微做了下注释,但实测过,真实有效:

package mainimport ( "encoding/json" "errors" "flag" "fmt" "io/ioutil" "log" "net" "os" "strings" "time")// 镜像结构type Image struct { Created uint64 Id string ParentId string RepoTags []string Size uint64 VirtualSize uint64}// 容器结构type Container struct { Id string `json:"Id"` Names []string `json:"Names"` Image string `json:"Image"` ImageID string `json:"ImageID"` Command string `json:"Command"` Created uint64 `json:"Created"` State string `json:"State"` Status string `json:"Status"` Ports []Port `json:"Ports"` Labels map[string]string `json:"Labels"` HostConfig map[string]string `json:"HostConfig"` NetworkSettings map[string]interface{} `json:"NetworkSettings"` Mounts []Mount `json:"Mounts"`}// docker 端口映射type Port struct { IP string `json:"IP"` PrivatePort int `json:"PrivatePort"` PublicPort int `json:"PublicPort"` Type string `json:"Type"`}// docker 挂载type Mount struct { Type string `json:"Type"` Source string `json:"Source"` Destination string `json:"Destination"` Mode string `json:"Mode"` RW bool `json:"RW"` Propatation string `json:"Propagation"`}// 连接列表var SockAddr = "/var/run//docker.sock" //这可不是随便写的,是docker官网文档的套接字默认值,当然守护进程通讯方式还有tcp,fd等方式,各自都有适用场景。。。var imagesSock = "GET /images/json HTTP/1.0\r\n\r\n" //docker对外的镜像api操作var containerSock = "GET /containers/json?all=true HTTP/1.0\r\n\r\n"  //docker对外的容器查看apivar startContainerSock = "POST /containers/%s/start HTTP/1.0\r\n\r\n" //docker对外的容器启动api// 白名单var whiteList []stringfunc main() { // 读取命令行参数 // 白名单列表 list := flag.String("list", "", "docker white list to restart, eg: token,explorer") // 轮询的时间间隔,单位秒 times := flag.Int64("time", 10, "time interval to set read docker containers [second], default is 10 second") flag.Parse() // 解析list => whiteList whiteList = strings.Split(*list, ",") //将我们命令行中list参数的容器列表解析到代码中 log.SetOutput(os.Stdout) log.Println("start docker watching...") log.Printf("Your whiteList: %v\n", *list) log.Printf("Your shedule times: %ds\n", *times)  //接下来的这个for循环就是每隔一定时间监控docker容器是否正常运行,不正常就重新启动它 for {  // 轮询docker  err := listenDocker()   if err != nil {   log.Println(err.Error())  }  time.Sleep(time.Duration(*times)*time.Second) }}func listenDocker() error { // 获取容器列表,拿到所有的容器信息 containers, err := readContainer()  if err != nil {  return errors.New("read container error: " + err.Error()) } // 先遍历白名单快,次数少 for _, name := range whiteList { Name:  for _, container := range containers {   for _, cname := range container.Names {    // 如果匹配到白名单    if cname[1:] == name {     // 关心一下容器状态     log.Printf("id=%s, name=%s, state=%s", container.Id[:12], container.Names, container.Status)     if strings.Contains(container.Status, "Exited") {      // 如果出现异常退出的容器,启动它      log.Printf("find container: [%s] has exited, ready to start it. ", name)      e := startContainer(container.Id)      if e != nil {       log.Println("start container error: ", e.Error())      }      break Name     }    }   }  } } return nil}// 获取 unix sock 连接func connectDocker() (*net.UnixConn, error) { addr := net.UnixAddr{SockAddr, "unix"}  // SockAddr 这个变量的值被设定为docker的/var/run/docker 套接字路径值,也就是说此处就是拨通与docker的daemon通讯建立的关键处,其他处的代码就是些正常的逻辑处理了 return net.DialUnix("unix", nil, &addr)}// 启动容器func startContainer(id string) error { conn, err := connectDocker() if err != nil {  return errors.New("connect error: " + err.Error()) } start := fmt.Sprintf(startContainerSock, id) fmt.Println(start) cmd := []byte(start) code, err := conn.Write(cmd) if err != nil {  return err } log.Println("start container response code: ", code) // 启动容器等待20秒,防止数据重发 time.Sleep(20*time.Second) return nil}// 获取容器列表func readContainer() ([]Container, error) { conn, err := connectDocker() //建立一个unix连接,这其实是一个关键点,需要你了解unix 套接字 建立连接 if err != nil {  return nil, errors.New("connect error: " + err.Error()) } _, err = conn.Write([]byte(containerSock)) if err != nil {  return nil, err } result, err := ioutil.ReadAll(conn) if err != nil {  return nil, err } body := getBody(result) var containers []Container err = json.Unmarshal(body, &containers) if err != nil {  return nil, err } log.Println("len of containers: ", len(containers)) if len(containers) == 0 {  return nil, errors.New("no containers") } return containers, nil}// 获取镜像列表func readImage(conn *net.UnixConn) ([]Image, error) { _, err := conn.Write([]byte(imagesSock)) if err != nil {  return nil, err } result, err := ioutil.ReadAll(conn) if err != nil {  return nil, err } body := getBody(result[:]) var images []Image err = json.Unmarshal(body, &images) if err != nil {  return nil, err } return images, nil}// 从返回的 http 响应中提取 bodyfunc getBody(result []byte) (body []byte) { for i:=0; i<=len(result)-4; i++ {  if result[i] == 13 && result[i+1] == 10 && result[i+2] == 13 && result[i+3] == 10 {   body = result[i+4:]   break  } } return}/*error log : 1、write unix @->/var/run/docker.sock: write: broken pipe  建立的tcp连接不能复用,每次操作都建立连接 */

使用方法

1.编译

go build -o main main.go

2.linux下直接当可执行文件执行便可

./main -list="容器名称1,容器名称2..."

思路分析:

原来docker这个软件对外是提供了一些列api用来管理容器的增删该查的 官方api文档 ,既然提供了api了那么任何语言都能实现对其的管理控制及动态部署了。

但其实这里面真要弄明白还是有很多话要讲了

docker这个服务已经已进程的形式运行在linux的系统中了,为什么我们输入docker有关的命令能够与之交互,这好像是一个习以为常的行为,貌似理应如此,但是要知道我们是在与一个正在运行的进程发生通讯,若仍不以为然,请接以下问:

1.进程间都是如何通讯的? 进程通讯间方式

在明白了进程之间的通讯方式之后,我明白了docker的这个daemon通讯原理,瞬间就打通了之前对k8管理docker的疑惑(老实讲只知道kubernetes很强大,却没想明白它是如何能动态增容我的容器配置,负载等等等),套接字(socket) /var/run/docker 这个我们使用起来不会接触到,理解起来却必须打通的关键点请务必了解它。

总结

以上所述是小编给大家介绍的golang实现对docker容器心跳监控功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


  • 上一条:
    在Docker中自动化部署Ruby on Rails的教程
    下一条:
    安装docker-compose的两种最简方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在docker环境中实现Laravel项目执行定时任务和消息队列流程步骤(0个评论)
    • 在MacBook下laravel项目多php版本docker开发环境配置方案(0个评论)
    • 在docker环境中部署docker部署elk架构流程步骤(1个评论)
    • docker compose跟Dockerfile的区别浅析(0个评论)
    • Ubuntu 22.04系统中安装podman流程步骤(1个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-11
    • 2020-06
    • 2021-05
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-11
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客