github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/simulations/adapters/docker.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package adapters 26 27 import ( 28 "errors" 29 "fmt" 30 "io" 31 "io/ioutil" 32 "os" 33 "os/exec" 34 "path/filepath" 35 "runtime" 36 "strings" 37 38 "github.com/docker/docker/pkg/reexec" 39 "github.com/ethereum/go-ethereum/node" 40 "github.com/ethereum/go-ethereum/p2p/discover" 41 ) 42 43 var ( 44 ErrLinuxOnly = errors.New("DockerAdapter can only be used on Linux as it uses the current binary (which must be a Linux binary)") 45 ) 46 47 //Dockeradapter是在Docker中运行模拟节点的节点适配器。 48 //容器。 49 // 50 //建立了一个包含当前二进制at/bin/p2p节点的Docker映像。 51 //执行时运行基础服务(请参见说明 52 //有关详细信息,请参阅execp2pnode函数) 53 type DockerAdapter struct { 54 ExecAdapter 55 } 56 57 //newdockeradapter构建包含当前 58 //二进制并返回dockeradapter 59 func NewDockerAdapter() (*DockerAdapter, error) { 60 //因为Docker容器在Linux上运行,而这个适配器运行 61 //当前容器中的二进制文件,必须为Linux编译。 62 // 63 //要求这样做是合理的,因为打电话的人可以 64 //在Docker容器中编译当前二进制文件。 65 if runtime.GOOS != "linux" { 66 return nil, ErrLinuxOnly 67 } 68 69 if err := buildDockerImage(); err != nil { 70 return nil, err 71 } 72 73 return &DockerAdapter{ 74 ExecAdapter{ 75 nodes: make(map[discover.NodeID]*ExecNode), 76 }, 77 }, nil 78 } 79 80 //name返回用于日志记录的适配器的名称 81 func (d *DockerAdapter) Name() string { 82 return "docker-adapter" 83 } 84 85 //newnode使用给定的配置返回一个新的dockernode 86 func (d *DockerAdapter) NewNode(config *NodeConfig) (Node, error) { 87 if len(config.Services) == 0 { 88 return nil, errors.New("node must have at least one service") 89 } 90 for _, service := range config.Services { 91 if _, exists := serviceFuncs[service]; !exists { 92 return nil, fmt.Errorf("unknown node service %q", service) 93 } 94 } 95 96 //生成配置 97 conf := &execNodeConfig{ 98 Stack: node.DefaultConfig, 99 Node: config, 100 } 101 conf.Stack.DataDir = "/data" 102 conf.Stack.WSHost = "0.0.0.0" 103 conf.Stack.WSOrigins = []string{"*"} 104 conf.Stack.WSExposeAll = true 105 conf.Stack.P2P.EnableMsgEvents = false 106 conf.Stack.P2P.NoDiscovery = true 107 conf.Stack.P2P.NAT = nil 108 conf.Stack.NoUSB = true 109 110 //监听给定端口上的所有接口,当我们 111 //初始化nodeconfig(通常是随机端口) 112 conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port) 113 114 node := &DockerNode{ 115 ExecNode: ExecNode{ 116 ID: config.ID, 117 Config: conf, 118 adapter: &d.ExecAdapter, 119 }, 120 } 121 node.newCmd = node.dockerCommand 122 d.ExecAdapter.nodes[node.ID] = &node.ExecNode 123 return node, nil 124 } 125 126 //dockernode包装execnode,但exec的是docker中的当前二进制文件 127 //容器而不是本地 128 type DockerNode struct { 129 ExecNode 130 } 131 132 //docker command返回一个命令,exec是docker中的二进制文件 133 //容器。 134 // 135 //它使用了一个shell,这样我们就可以通过 136 //使用--env标志将变量转换为容器。 137 func (n *DockerNode) dockerCommand() *exec.Cmd { 138 return exec.Command( 139 "sh", "-c", 140 fmt.Sprintf( 141 `exec docker run --interactive --env _P2P_NODE_CONFIG="${_P2P_NODE_CONFIG}" %s p2p-node %s %s`, 142 dockerImage, strings.Join(n.Config.Node.Services, ","), n.ID.String(), 143 ), 144 ) 145 } 146 147 //DockerImage是为运行 148 //仿真节点 149 const dockerImage = "p2p-node" 150 151 //buildDockerImage构建用于运行模拟的Docker映像 152 //Docker容器中的节点。 153 // 154 //它将当前二进制文件添加为“p2p node”,以便运行execp2pnode 155 //执行时。 156 func buildDockerImage() error { 157 //创建用作生成上下文的目录 158 dir, err := ioutil.TempDir("", "p2p-docker") 159 if err != nil { 160 return err 161 } 162 defer os.RemoveAll(dir) 163 164 //将当前二进制文件复制到生成上下文中 165 bin, err := os.Open(reexec.Self()) 166 if err != nil { 167 return err 168 } 169 defer bin.Close() 170 dst, err := os.OpenFile(filepath.Join(dir, "self.bin"), os.O_WRONLY|os.O_CREATE, 0755) 171 if err != nil { 172 return err 173 } 174 defer dst.Close() 175 if _, err := io.Copy(dst, bin); err != nil { 176 return err 177 } 178 179 //创建dockerfile 180 dockerfile := []byte(` 181 FROM ubuntu:16.04 182 RUN mkdir /data 183 ADD self.bin /bin/p2p-node 184 `) 185 if err := ioutil.WriteFile(filepath.Join(dir, "Dockerfile"), dockerfile, 0644); err != nil { 186 return err 187 } 188 189 //运行“docker build” 190 cmd := exec.Command("docker", "build", "-t", dockerImage, dir) 191 cmd.Stdout = os.Stdout 192 cmd.Stderr = os.Stderr 193 if err := cmd.Run(); err != nil { 194 return fmt.Errorf("error building docker image: %s", err) 195 } 196 197 return nil 198 }