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


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

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

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

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


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

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

我们先从一段代码说起

// b2d hosts need to wait for the daemon to be up
// before continuing with provisioning
if err = WaitForDocker(provisioner, engine.DefaultPort); err != nil {
return err
} if err = makeDockerOptionsDir(provisioner); err != nil {
return err
} provisioner.AuthOptions = setRemoteAuthOptions(provisioner) if err = ConfigureAuth(provisioner); err != nil {
return err
}

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

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

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

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

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

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

matchNetstatOut = regexp.MatchString(reDaemonListening, line)

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

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

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

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

func (provisioner *Boot2DockerProvisioner) Service(name string, action serviceaction.ServiceAction) error {
_, err := provisioner.SSHCommand(fmt.Sprintf("sudo /etc/init.d/%s %s", name, action.String()))
return err
} bits := 2048 p.Service("docker", serviceaction.Stop);
.
log.Info("Copying certs to the local machine directory...");.
.
.
dockerPort := engine.DefaultPort
parts := strings.Split(u.Host, ":")
if len(parts) == 2 {
dPort, err := strconv.Atoi(parts[1])
if err != nil {
return err
}
dockerPort = dPort
}
.
.
. p.Service("docker", serviceaction.Start);
.
return WaitForDocker(p, dockerPort);

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

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

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

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

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

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

As:

func GetSSHClientFromDriver(d Driver) (ssh.Client, error) {
address, err := d.GetSSHHostname()
if err != nil {
return nil, err
} port, err := d.GetSSHPort()
if err != nil {
return nil, err
} var auth *ssh.Auth
if d.GetSSHKeyPath() == "" {
auth = &ssh.Auth{}
} else {
auth = &ssh.Auth{
Keys: []string{d.GetSSHKeyPath()},
}
} client, err := ssh.NewClient(d.GetSSHUsername(), address, port, auth)
return client, err } func RunSSHCommandFromDriver(d Driver, command string) (string, error) {
client, err := GetSSHClientFromDriver(d)
if err != nil {
return "", err
} log.Debugf("About to run SSH command:\n%s", command) output, err := client.Output(command)
log.Debugf("SSH cmd err, output: %v: %s", err, output)
if err != nil {
return "", fmt.Errorf(`ssh command error:
command : %s
err : %v
output : %s`, command, err, output)
} return output, nil
}

回到现象

func WaitForSpecificOrError(f func() (bool, error), maxAttempts int, waitInterval time.Duration) error {
for i := 0; i < maxAttempts; i++ {
stop, err := f()
if err != nil {
return err
}
if stop {
return nil
}
time.Sleep(waitInterval)
}
return fmt.Errorf("Maximum number of retries (%d) exceeded", maxAttempts)
} func WaitForSpecific(f func() bool, maxAttempts int, waitInterval time.Duration) error {
return WaitForSpecificOrError(func() (bool, error) {
return f(), nil
}, maxAttempts, waitInterval)
}

如果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中产生或许一点也不会吃惊,最后的伪函数片段是

// Driver defines how a host is created and controlled. Different types of
// driver represent different ways hosts can be created (e.g. different
// hypervisors, different cloud providers)
type Driver interface {
// Create a host using the driver's config
Create() error // DriverName returns the name of the driver
DriverName() string // GetCreateFlags returns the mcnflag.Flag slice representing the flags
// that can be set, their descriptions and defaults.
GetCreateFlags() []mcnflag.Flag // GetIP returns an IP or hostname that this host is available at
// e.g. 1.2.3.4 or docker-host-d60b70a14d3a.cloudapp.net
GetIP() (string, error) // GetMachineName returns the name of the machine
GetMachineName() string // GetSSHHostname returns hostname for use with ssh
GetSSHHostname() (string, error) // GetSSHKeyPath returns key path for use with ssh
GetSSHKeyPath() string // GetSSHPort returns port for use with ssh
GetSSHPort() (int, error) // GetSSHUsername returns username for use with ssh
GetSSHUsername() string // GetURL returns a Docker compatible host URL for connecting to this host
// e.g. tcp://1.2.3.4:2376
GetURL() (string, error) // GetState returns the state that the host is in (running, stopped, etc)
GetState() (state.State, error) // Kill stops a host forcefully
Kill() error // PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
PreCreateCheck() error // Remove a host
Remove() error // Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
Restart() error // SetConfigFromFlags configures the driver with the object that was returned
// by RegisterCreateFlags
SetConfigFromFlags(opts DriverOptions) error // Start a host
Start() error // Stop a host gracefully
Stop() error
}
u.Host from GetUrl() from Implementation of Driver
That's ALL of it.

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

// b2d hosts need to wait for the daemon to be up
// 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

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. Pytorch Bi-LSTM + CRF 代码详解

    久闻LSTM + CRF的效果强大,最近在看Pytorch官网文档的时候,看到了这段代码,前前后后查了很多资料,终于把代码弄懂了.我希望在后来人看这段代码的时候,直接就看我的博客就能完全弄懂这段代码. ...

  2. 【codeforces 766D】Mahmoud and a Dictionary

    time limit per test4 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  3. java GUI(图形用户界面)

    GUI Graphical User Interface(图形用户接口). 用图形的方式,来显示计算机操作的界面,这样更方便更直观. CLI Command line User Interface ( ...

  4. js执行代码顺序

    之前一直停留在主线程先执行,异步后执行的浅理解中,后来随着不断的学习,才渐渐意识到这里面还是有点复杂的,不过我不打算写很多.一幅图来说明这个复杂的关系 processTick可理解为node中的延时器 ...

  5. linux kgdb 补丁

    目前为止我们看到的 2 个交互式调试方法( 使用 gdb 于 /proc/kcore 和 kdb) 都缺乏 应用程序开发者已经熟悉的那种环境. 如果有一个真正的内核调试器支持改变变量, 断点 等特色, ...

  6. linux 使用 gdb

    gdb 对于看系统内部是非常有用. 在这个级别精通调试器的使用要求对 gdb 命令有信心, 需要理解目标平台的汇编代码, 以及对应源码和优化的汇编码的能力. 调试器必须把内核作为一个应用程序来调用. ...

  7. ES6类的继承

    ES6 引入了关键字class来定义一个类,constructor是构造方法,this代表实例对象. constructor相当于python的init 而this 则相当于self 类之间通过ext ...

  8. Channel 9视频整理【5】

    Jennifer Chiu https://channel9.msdn.com/Niners/JenniferChiu

  9. 22.json&pickle&shelve

    转载:https://www.cnblogs.com/yuanchenqi/article/5732581.html json 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不 ...

  10. Spark RDD的弹性到底指什么

    RDD(Resiliennt Distributed Datasets)抽象弹性分布式数据集对于Spark来说的弹性计算到底提现在什么地方? 自动进行内存和磁盘数据这两种存储方式的切换 Spark 可 ...