小伙伴们,她们中出了一个叛徒,他是谁?是谁?是谁?


由一则口口相传的故事开始吧:

中午吃饭时间抽空小李跑到同座大楼的小张公司串门,小李是一名docker顾问熟称砖家,这间公司老板想挖小李,他盯了前台不到三秒,移开视线走到前同事小张的隔间边上打招呼,看到小张眉头紧锁,正在专著的看代码,小李把头凑过去,客套起来,正在忙呢,在学什么新技术?小张开口吼到:在翻小王的代码,你认识的那个烟友!小李一愣,哦那一个小王啊~,研究别人的技术,挺钻的呀,小李嘴上奉承道(心里暗忖着小张工资以前没我高,跳到这里估计也还在当下手吧),小张叹了一口气,嘣出三个字:烦着呢,小李映入眼前的是满屏密密麻麻的代码,左边的行标显示9999,不愧是千足代码,还有那么一小行格空的注释,醒目的打着时间---5年前----这是旧代码,小李摇头晃脑,有所觉悟

那就不打扰你了,想起烟瘾又犯了,正巧认识的小王也是同道中人,下意识就问,小王人呢?小张硕小的脑袋一震,青筋暴起,指了指打印机房外一个空台子,上面积了一层薄灰,放着一些杂物,像似好久没有人办公了,与此同时,一阵阴风从窗角吹过,扬起的窗帘把小张的脸映射成斑斑点点,小张把迟滞的目光瞟向了窗外的浮云,仿佛小王就在云端,小王离职了吗?小李不甘心的问了一句,突然一排没有窗户的老板格间悠悠的打开一扇门,仿佛有人藏在门后很久了,一个光头中年把头探了出来利索的喊了一句,小张进来,谈话!小张战战兢兢的放下鼠标,快速使了一个撤离眼色,轻声说,小王的老板老王现在变成了我的老板...就是以前那一个咚咚咚画白板的那个...小李装作若有所悟的样子恢恢手溜了

从此小李再也没有去小张的办公室,至今小李还在打着寒颤


这个故事有什么寓意?听过的人众口难调(张冠李戴),索性作为发散性话题,放在本篇作引

标题GDP三个首字母的组合作为揭发233的docker/machine的后续,为了符合标题的意义,请Follow me一起探究其中的秘密

我们先从一段代码说起

  1. // b2d hosts need to wait for the daemon to be up
  2. // before continuing with provisioning
  3. if err = WaitForDocker(provisioner, engine.DefaultPort); err != nil {
  4. return err
  5. }
  6.  
  7. if err = makeDockerOptionsDir(provisioner); err != nil {
  8. return err
  9. }
  10.  
  11. provisioner.AuthOptions = setRemoteAuthOptions(provisioner)
  12.  
  13. if err = ConfigureAuth(provisioner); err != nil {
  14. return err
  15. }

这是一段在233篇中重点划出揭露的片断
节选自libmachine/provision/boot2docker.go

从233篇隐藏的逻辑可以判断,此处,导致了整个隐藏在Docker Machine中的b2d出现了port排异

函数WaitForDocker成为此段有争议的焦点

我们进入这段函数看看它到底是什么实现

  1. func checkDaemonUp(p Provisioner, dockerPort int) func() bool {
  2. reDaemonListening := fmt.Sprintf(":%d\\s+.*:.*", dockerPort)
  3. return func() bool {
  4. // HACK: Check netstat's output to see if anyone's listening on the Docker API port.
  5. netstatOut, err := p.SSHCommand("if ! type netstat 1>/dev/null; then ss -tln; else netstat -tln; fi")
  6. if err != nil {
  7. log.Warnf("Error running SSH command: %s", err)
  8. return false
  9. }
  10.  
  11. return matchNetstatOut(reDaemonListening, netstatOut)
  12. }
  13. }

这段试图在netstat返回结果字符类型中执行匹配函数matchNetstatOut

  1. matchNetstatOut = regexp.MatchString(reDaemonListening, line)

匹配的主角很不幸在这里被强硬的设置为engine.DefaultPort,在233篇里曾试图枚举过engine.DefaultPort的一些用例,不知道小伙伴们看出些什么端倪

在这里我们再次回到最先的那些函数片断,注意到随后调用的if err = ConfigureAuth(provisioner)没有?

这是一段惊心动魄的代码,路经在libmachine/provision/utils.go

不妨我们一起看一下这个ConfigureAuth函数有哪些内涵???

  1. func (provisioner *Boot2DockerProvisioner) Service(name string, action serviceaction.ServiceAction) error {
  2. _, err := provisioner.SSHCommand(fmt.Sprintf("sudo /etc/init.d/%s %s", name, action.String()))
  3. return err
  4. }
  5.  
  6. bits := 2048
  7.  
  8. p.Service("docker", serviceaction.Stop);
  9. .
  10. log.Info("Copying certs to the local machine directory...");.
  11. .
  12. .
  13. dockerPort := engine.DefaultPort
  14. parts := strings.Split(u.Host, ":")
  15. if len(parts) == 2 {
  16. dPort, err := strconv.Atoi(parts[1])
  17. if err != nil {
  18. return err
  19. }
  20. dockerPort = dPort
  21. }
  22. .
  23. .
  24. .
  25.  
  26. p.Service("docker", serviceaction.Start);
  27. .
  28. return WaitForDocker(p, dockerPort);

这是我抽象出来的慰慰代码,在这段代码里,吉祥寺(似)dockerPort被正确合理的设置成它应该有的值,我把这段代码称呼为2048代码,为了抵消你们不时涌现的1024的念头!

如果诸位可以认真地再多看几遍,一定会产生出一群问号???

这里所有的op都以SSH的方式调用,而SSH又隐藏了什么不为人知的小故事?我们一起来猜测,谁是哪一名画白板的人

  1. func (provisioner *Boot2DockerProvisioner) SSHCommand(args string) (string, error) {
  2. return drivers.RunSSHCommandFromDriver(provisioner.Driver, args)
  3. }

在b2d内部,SSH的责任链落到driver头上,对就是那一个driver,那一个,那一个,我在手动滑稽之golang-vmware-driver广告篇贴图之一,不会错了

driver为什么会对SSH轻车熟路?

As:

  1. func GetSSHClientFromDriver(d Driver) (ssh.Client, error) {
  2. address, err := d.GetSSHHostname()
  3. if err != nil {
  4. return nil, err
  5. }
  6.  
  7. port, err := d.GetSSHPort()
  8. if err != nil {
  9. return nil, err
  10. }
  11.  
  12. var auth *ssh.Auth
  13. if d.GetSSHKeyPath() == "" {
  14. auth = &ssh.Auth{}
  15. } else {
  16. auth = &ssh.Auth{
  17. Keys: []string{d.GetSSHKeyPath()},
  18. }
  19. }
  20.  
  21. client, err := ssh.NewClient(d.GetSSHUsername(), address, port, auth)
  22. return client, err
  23.  
  24. }
  25.  
  26. func RunSSHCommandFromDriver(d Driver, command string) (string, error) {
  27. client, err := GetSSHClientFromDriver(d)
  28. if err != nil {
  29. return "", err
  30. }
  31.  
  32. log.Debugf("About to run SSH command:\n%s", command)
  33.  
  34. output, err := client.Output(command)
  35. log.Debugf("SSH cmd err, output: %v: %s", err, output)
  36. if err != nil {
  37. return "", fmt.Errorf(`ssh command error:
  38. command : %s
  39. err : %v
  40. output : %s`, command, err, output)
  41. }
  42.  
  43. return output, nil
  44. }

回到现象

  1. func WaitForSpecificOrError(f func() (bool, error), maxAttempts int, waitInterval time.Duration) error {
  2. for i := 0; i < maxAttempts; i++ {
  3. stop, err := f()
  4. if err != nil {
  5. return err
  6. }
  7. if stop {
  8. return nil
  9. }
  10. time.Sleep(waitInterval)
  11. }
  12. return fmt.Errorf("Maximum number of retries (%d) exceeded", maxAttempts)
  13. }
  14.  
  15. func WaitForSpecific(f func() bool, maxAttempts int, waitInterval time.Duration) error {
  16. return WaitForSpecificOrError(func() (bool, error) {
  17. return f(), nil
  18. }, maxAttempts, waitInterval)
  19. }

如果docker port已经修改这里会抽风10次,显示ssh调用if ! type netstat 1>/dev/null; then ss -tln; else netstat -tln; fi正确返回已经改变的docker port和ssh port侦听列表

然而无法match engine.DefaultPort带来的err是臆想不到的,err msg更无法判断b2d的内部排异,这迫使我试图寻找AzureProvisioner,这个不存在的名称

如果看到这里我再向你吐露docker port从driver中产生或许一点也不会吃惊,最后的伪函数片段是

  1. // Driver defines how a host is created and controlled. Different types of
  2. // driver represent different ways hosts can be created (e.g. different
  3. // hypervisors, different cloud providers)
  4. type Driver interface {
  5. // Create a host using the driver's config
  6. Create() error
  7.  
  8. // DriverName returns the name of the driver
  9. DriverName() string
  10.  
  11. // GetCreateFlags returns the mcnflag.Flag slice representing the flags
  12. // that can be set, their descriptions and defaults.
  13. GetCreateFlags() []mcnflag.Flag
  14.  
  15. // GetIP returns an IP or hostname that this host is available at
  16. // e.g. 1.2.3.4 or docker-host-d60b70a14d3a.cloudapp.net
  17. GetIP() (string, error)
  18.  
  19. // GetMachineName returns the name of the machine
  20. GetMachineName() string
  21.  
  22. // GetSSHHostname returns hostname for use with ssh
  23. GetSSHHostname() (string, error)
  24.  
  25. // GetSSHKeyPath returns key path for use with ssh
  26. GetSSHKeyPath() string
  27.  
  28. // GetSSHPort returns port for use with ssh
  29. GetSSHPort() (int, error)
  30.  
  31. // GetSSHUsername returns username for use with ssh
  32. GetSSHUsername() string
  33.  
  34. // GetURL returns a Docker compatible host URL for connecting to this host
  35. // e.g. tcp://1.2.3.4:2376
  36. GetURL() (string, error)
  37.  
  38. // GetState returns the state that the host is in (running, stopped, etc)
  39. GetState() (state.State, error)
  40.  
  41. // Kill stops a host forcefully
  42. Kill() error
  43.  
  44. // PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
  45. PreCreateCheck() error
  46.  
  47. // Remove a host
  48. Remove() error
  49.  
  50. // Restart a host. This may just call Stop(); Start() if the provider does not
  51. // have any special restart behaviour.
  52. Restart() error
  53.  
  54. // SetConfigFromFlags configures the driver with the object that was returned
  55. // by RegisterCreateFlags
  56. SetConfigFromFlags(opts DriverOptions) error
  57.  
  58. // Start a host
  59. Start() error
  60.  
  61. // Stop a host gracefully
  62. Stop() error
  63. }
  1. u.Host from GetUrl() from Implementation of Driver
  2. That's ALL of it.

这些代码调用关系一一展示过之后

  1. // b2d hosts need to wait for the daemon to be up
  2. // before continuing with provisioning

这里,仅有的注释让我更加确信,以下一行是可以删除的代码,我们都善于反向操作

然而我对改Machine始终抱No的态度,或许将来可能会注册一个账户submit patch,但是让我犹豫的是,我还没有写过任何hello world go,为什么比我更合适的人选没有呢???

这个疑问始终挥之不去,到了放松环节,请跟着我的节奏Blame(扒)一下精彩截图

图片被我约束了HTML尺寸,请点击单独在TAB页观看图片链接

-->-->

a


简出:

对策篇:

  1. 上文提到的制作自己的Machine,可惜华而不为
  2. 提交patch,为社区贡献,可惜遥遥无期
  3. Register Injection by Init Driver AND YOU CAN HAVE 4069

作为一个万全的对策一定要有一些把握,forkersfolk贡起宝典手册,找到了入门

请看

Init() functions can be used within a package block and regardless of how many times that package is imported
The init() function will only be called once

  1. provisioners = make(map[string]*RegisteredProvisioner) <===hashmap

不仅如此,在一个go中init可以反复反反复复存在,按序调用

真是一大奇观, 请跟随我一起念作为结尾 Go

Goosy

Disk

Docker

Port

Provisioner

Go Goosy Disk Docker Port Provisioners(GDP)的更多相关文章

  1. docker port is already allocated 的解决方案

    ps -aux | grep -v grep | grep docker-proxy 第二列为进程号 停止 doker 进程,删除所有容器,然后删除 local-kv.db 这个文件,再启动 dock ...

  2. 再次聚焦DOCKER MACHINE CODE 2048

    如果有一种feeling让世界难以释怀,那一定是发掘(挖土机那家强?)了什么了不起的东西 如果有一种贴图叫做深夜,仍不止息,那一定是饱含深意的贴图 // TODO: I'm not super hap ...

  3. 娱乐往事,年初捡到1G PAR,平淡的日子泛起波澜

    常听说这样的故事 垃圾佬捡到蓝牙键盘,于是配了一台上万的电脑 垃圾佬捡到机箱,于是配了一台带遥控的HTPC 垃圾佬捡到假NAS,于是组了20+T的RAID 而我,不是垃圾佬,更没有捡到过U盘,对突如其 ...

  4. docker好文收藏

    深入浅出Docker(一):Docker核心技术预览 2. 核心技术预览 Docker核心是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观.我们从虚拟化方法的四个方面:隔离性.可配额/可度 ...

  5. Docker 学习笔记(CentOS 7.1)

    基本概念 Docker 包括三个基本概念 镜像(Image) 容器(Container) 仓库(Repository)理解了这三个概念,就理解了 Docker 的整个生命周期. Docker 镜像 D ...

  6. Docker 总结(转载)

    原文链接:http://blog.tankywoo.com/docker/2014/05/08/docker-4-summary.html 查看docker的子命令,直接敲docker或完整的dock ...

  7. docker基础命令详解

    Commands: attach    Attach to a running container build     Build an image from a Dockerfile commit  ...

  8. docker summary

    http://blog.tankywoo.com/docker/2014/05/08/docker-4-summary.html 总结的很好 ----------------------------- ...

  9. Docker初识

    <Docker--从入门到实践>是Docker技术的入门教程,学习时长两天,现整理关键点如下: 1. 什么是Docker? 轻量级操作系统虚拟化解决方案:Go语言实现:下图很好地说明了Do ...

随机推荐

  1. 洛谷P5020 货币系统 题解 模拟

    题目链接:https://www.luogu.org/problem/P5020 这道题目是一道模拟题,但是又有一点多重背包的思想在里面. 首先我们定义一个 vis[i] 来表示和为 i 的情况在之前 ...

  2. Python--day30--软件开发架构

    软件开发架构: C/S架构: B/S架构: B/S架构和C/S架构的关系:

  3. P1068 压缩技术

    题目描述 设某汉字由N × N的0和1的点阵图案组成. 我们依照以下规则生成压缩码.连续一组数值:从汉字点阵图案的第一行第一个符号开始计算,按书写顺序从左到右,由上至下.第一个数表示连续有几个0,第二 ...

  4. linux scull 中的缺陷

    让我们快速看一段 scull 内存管理代码. 在写逻辑的深处, scull 必须决定它请求的内 存是否已经分配. 处理这个任务的代码是: if (!dptr->data[s_pos]) { dp ...

  5. Storm使用总结

    Strom安装 Strom启动 ./zkServer.sh start 启动nimbus主节点: nohup bin/storm nimbus >> /dev/null & 启动s ...

  6. 【Kubernetes】创建Pod并分配到指定节点

    一.编辑yaml文件 [root@K8s-Master Tools]# cat hello-world-pod.yaml apiVersion: v1 kind: Pod metadata: name ...

  7. markdown color

    深青色 深蓝色 seagreen darkgreen indianred cornflowerblue lightskyblue coral lightcoral darkorange

  8. 定位、识别;目标检测,FasterRCNN

    定位: 针对分类利用softmax损失函数,针对定位利用L2损失函数(或L1.回归损失等) 人关节点检测 针对连续变量和离散变量需要采用不同种类的损失函数. 识别: 解决方案: 1.利用滑动窗口,框的 ...

  9. jdbc链接Oracle数据库的封装

    在src下创建properties文件 driver=oracle.jdbc.driver.OracleDriverurl=jdbc:oracle:thin:@//127.0.0.1:1521/XEu ...

  10. 最全最详细的PHP面试题(带有答案)

    这篇文章介绍的内容是关于最全最详细的PHP面试题(带有答案),有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 相关推荐: 分享一波腾讯PHP面试题 2019年PHP最新面试题(含答案) ...