基于Docker搭建一个Go-ethereum节点(下)
2017-03-08 14:33
274 查看
原文链接:http://dockone.io/article/1936
上一篇奠定了基础的知识点以后,我们开始区块链之旅了!
我们要做的第一件事是将“geth”节点连接到以太坊生产网络,从而保证我们的本地区块链同步,并为其他工具打开服务端口 - 当然也是在容器中运行。
![](http://dockerone.com/uploads/article/20161221/9c453628eb0e384dbf02c37093676255.jpg)
通过“docker run”命令,启动镜像“ethereum / client-go”。 RUN命令具有以下参数:
“-it”以交互模式启动容器,并将容器的标准输出发送到我们的终端。当以后重新启动容器时,我们可以选择在后台运行该进程,但是现在我们要看看发生了什么。
“ - -name”给容器以逻辑名“ethereum”,我们稍后可以使用它来访问这个实例。
“-p 30303:30303 -p 8545:8545 -p 8546:8546”公开并且将三个端口从容器内部映射到外部。
“-v /opt/docker/ethereum:/root/.ethereum”将主机目录“/ opt / docker / ethereum”(我们要存储区块链数据的位置)挂载到位置“/ root
/ .ethereum“。后者是“geth”在使用root用户帐户启动时存储所有信息的默认位置。
这个镜像的ENTRYPOINT命令“geth”可以通过INSPECTing可视化来调用,就像我们在主机上直接运行时使用该工具一样。请注意,容器命令行参数不能(容易)过后更改,如果需要不同的命令行,我们将需要创建一个新容器。然而从Docker的角度“容器很便宜”,所以这个约束不是真正的问题,特别是数据不在容器中,不需要重新下载。有一件事要记住:同一时间只有一个“geth”节点可以访问blockchain数据,所以不可能同时运行多个主“geth”节点。
“ - -ws - -rpc”分别激活“geth”的Web接口和HTTP RPC接口。“ - -rpcaddr”0.0.0.0“ - -wsaddr”0.0.0.0“向网络上的所有地址开放这些接口。这样做通常会有点危险,但我们不是在主机的物理网络上运行。这个部分后面会介绍更多。执行上面的命令应该启动一个新的容器,调用“geth”工具,然后开始下载blockchain数据。
(注意:您可以使用“-fast”选项)。
![](http://dockerone.com/uploads/article/20161221/343e9e0dc5affe1631a1457182a918d1.jpg)
![](http://dockerone.com/uploads/article/20161221/2165d5a4b40dfb0182df33ef669bb63e.jpg)
以下行值得重点关注:
![](http://dockerone.com/uploads/article/20161221/23134536e776582b76e45e73e5de023b.jpg)
![](http://dockerone.com/uploads/article/20161221/c57a0de702d857f59e3ec34234a4eb32.jpg)
1、首先,告警提示“geth”抱怨没有定义“etherbase”。 “etherbase”是成功挖掘区块,执行智能合约并在区块链内返回结果之后用来接收以太奖励的“默认以太坊地址”。这个帐户,在开发合同时也很方便。
2 、接下来,我们看到blockchain数据被写入“/root/.ethereum/chaindata”,因为我们已经从我们的主机挂载了这个目录,我们应该可以在本地磁盘上看到出现的数据:
![](http://dockerone.com/uploads/article/20161221/8b6449fdaadf2e3fae479bbc2b7aabfc.jpg)
3、最后,HTTP和Web socket端点已经打开,并且创建了默认的IPC(进程间通信)文件句柄“/root/.ethereum/geth.ipc”。这通常会隐藏在容器中,但是我们已经挂载了外部目录,所以该文件可以用于与这个“geth”节点通信。
剩下的就是定义一个默认的以太坊帐户。使用Docker命令允许在正在运行的容器中执行命令,所以很容易。注意,这各操作不会打开另一个不同的容器,它连接到现在运行的容器。
![](http://dockerone.com/uploads/article/20161221/58e4373007807fcfce27b8cf0f9e21b6.jpg)
不要忘记记下以太坊地址和密码。为了被“geth”节点识别,容器必须重新启动。新帐户可以在我们挂载的数据目录中找到:
![](http://dockerone.com/uploads/article/20161221/43f697aed9c4c6a23b37cc3bf8e5651b.jpg)
在交互式模式下,容器实例可以使用CTRL + C停止。否则,应该调用docker STOP命令。
关于这一点的最后说明:
为了能与以太坊网络同步,主机时间必须精确匹配以太网网络时间。因此,可能需要使用NTP协议与“世界时间”执行同步:
![](http://dockerone.com/uploads/article/20161221/74773516b6b4fa6ab296b7e479c74c94.jpg)
在当前配置中,我们有一个可以挂载到我们的容器中的以太坊数据目录。这不是因为区块链数据只能在任何情况下由一个进程访问,而是访问可由Ethereum节点用于进程间通信的IPC文件描述符。因此,我们可以在这里继续,而不需要访问网络。
然而,为了充分利用我们的完整容器化以太坊节点,了解Docker如何与网络结合可以大大帮助我们为我们未来的用例找到最佳解决方案。众所周知,网络可以是相当复杂的,所以我们在这里只专注于文章内容相关的部分。
默认情况下,Docker容器无法访问主机的网络。如果这样的话,容器化有什么意义呢?作为替代,Docker创建一个单独的虚拟网络,所有容器和主机都可以访问:“docker0”。可以通过显示主机的网络配置查看:
![](http://dockerone.com/uploads/article/20161221/9402ee02ab036b090b9892436f84fd18.jpg)
除了我们的本地网络“eth0”(或类似,NB。eth以太网,而不是以太坊),我们看到名为“docker0”的网络。它是一个不同的子网,172.17.42.1是这个网络上的主机IP地址。为了简单,我们将使用由所有容器共享的默认“docker0”网络。但是,知道Docker也允许创建单独的逻辑网络并将它们分配到特定的容器!
获取容器的IP地址不太直接。默认情况下,在轻量级Linux镜像中未安装“ifconfig”。我们可以使用命令“sudo docker exec apt-get -y install .....”安装一切,但是这个需要在每个容器中一次又一次地执行。有一个更容易的解决方案:
![](http://dockerone.com/uploads/article/20161221/13b80e00d7f43eb73d2dd989f5f33424.jpg)
对于这个IP必须要清楚的事情是,它会在在容器重新启动时改变。这个对于将IP用于在创建另一个容器作为命令行参数传递时可能是一个问题,我们将在下面看到。
顺便提一句,INSPECT命令允许查看关于容器,系统和IO配置,启动命令行,文件路径和挂载等等的任何信息。
![](http://dockerone.com/uploads/article/20161221/733822e779e9d71af9b3a7b2215959ea.jpg)
![](http://dockerone.com/uploads/article/20161221/f692475eec3fff02d9015a408785e734.jpg)
![](http://dockerone.com/uploads/article/20161221/c7ca514a065a301aeff11304ec24d93e.jpg)
![](http://dockerone.com/uploads/article/20161221/80ff1df0a25bc9e2b42cb48dc02949eb.jpg)
4 、连接JavaScript控制台
接下来,我们想让以太坊主节点与“geth”JavaScript控制台进行交互。这个十分简单…
而棘手的部分是两个容器化的“geth”节点之间的进程间通信。第一个选项是使用安装的数据目录中存在的IPC文件。这是当在同一主机上运行时“geth”节点通信的典型方式。我们需要的是将数据目录安装到第二个节点,在同一个地方,所以“geth”“看到”另一个节点,就好像它只运行一个控制台窗口。两个容器使用相同的IPC描述符进行互连:
![](http://dockerone.com/uploads/article/20161221/0bb63e756bc014728a88283c88003781.png)
替代方案是Web socket或HTTP接口。这需要知道主节点的IP地址,我们知道如何找出.
![](http://dockerone.com/uploads/article/20161221/14ee6db6e31b03188589af4cc6671713.jpg)
此方法有一个重要的障碍:我们必须指定主“geth”节点的IP地址作为第二个容器的命令行的一部分。一旦创建,此IP声明不能再更改(除了在配置文件上做手脚),所以这个容器只有在目标容器重新启动和其IP更改之前才有用。
最简单的解决方案是删除此容器,并在每次需要控制台时启动一个新容器。记住 - “容器很便宜”,我们可以用脚本自动化:
![](http://dockerone.com/uploads/article/20161221/88abe7b73d6469f332f9d7dce39272b3.png)
5 、运行MIX IDE
现在它将要变得非常有趣。到目前为止,我们使用纯命令行“geth”实例在单独的容器中运行,我们使它们进行通信。运行Ethereum Mix IDE增加了一个新的挑战:使用图形用户界面。
Docker不是真正设计为在容器内运行UI,但是我们可以使用各种技巧来解决。目前有三种方式:
1)将整个X11服务器安装到容器中,并使用一些魔法:),如下所述。这个方式很重,但却是完全“Docker方式”让容器保持隔离。
2)简单地将VNC服务器安装到容器中并远程打开UI。很聪明,但由于性能问题用VNC工作却不是真的那么趣。
3)在正确的地方将Linux主机的X11 IPC(进程间通信)socket装入容器,这是相对优雅的,但却打破了容器之间的隔离,因此可能带来安全和稳定问题。
这个问题解决了,我们需要将Mix IDE转换为容器。由于以太坊团队尚未提供预定义的镜像,我们勇敢地使用“Dockerfile”构建自己的镜像。
第一步是创建一个目录来存储Dockerfile,让我们说“ethereum-mix-ide”。接下来,在内部创建名为“Dockerfile”的文件(文件名是必需的),其内容如下:
![](http://dockerone.com/uploads/article/20161221/97e41b69652a2d5cf8db49fbc0fad5e0.jpg)
![](http://dockerone.com/uploads/article/20161221/cba5b8038973110602f8bc6a36ad013a.jpg)
最后,在目录中,我们调用Docker命令,逐步执行此脚本,并将最终结果保存到我们的新镜像中。请不要忘记在末尾的“。”,因为它是命令行的一部分。
![](http://dockerone.com/uploads/article/20161221/3d40a8f8420f0ec2b323920c263e6032.png)
“Dockerfile”脚本是相当自我解释 。我们的镜像是基于最新的官方UBUNTU镜像。首先,它安装各种工具和Mix IDE。为了能够连接到X服务器,正在运行的进程不能是“root”。因此,脚本创建一个名为“mix”的用户并赋予他sudo权限。最后,“mix-ide”设置为自动启动点。
让我们来验证一下结果:
![](http://dockerone.com/uploads/article/20161221/cf9a1b1db9e8e4d196608e0094e5069b.png)
镜像准备好了,我们将创建一个新的容器,并自豪地命名为“ethereumix”
![](http://dockerone.com/uploads/article/20161221/acc0f81405860e393e7032af53f2e0af.jpg)
一旦构建,容器可以随时重新启动:
![](http://dockerone.com/uploads/article/20161221/ec519e976ce6b2b8c7ba3ec25d48772b.png)
或者,在交互模式下查看所有Beta版的警告消息:
![](http://dockerone.com/uploads/article/20161221/03c6fe339889cc5e317b7077de8a5615.png)
你可能已经注意到这个参数:“-p 18545:8545”。它确实是一个参数,没有typo :)“geth”主节点容器已经将它的端口8545绑定到主机端口8545,所以我们需要选择另一个地方绑定。由于Mix
IDE容器启动到“geth”主节点的连接,因此绑定位置不重要。
“-v /tmp/.X11-unix:/tmp/.X11-unix”将我们的本地X11服务器socket挂载到容器,这次使用Docker的VOLUME功能,“-e DISPLAY = $ DISPLAY”设置$
DISPLAY环境变量在容器内的值与我们在主机上的值相同。此变量指定X客户端要显示的地址,这是必须设置的。
Mix IDE不需要访问Blockchain数据,但是我们需要在我们要在区块链上部署Smart Contract时联系主要的以太坊“geth”服务器节点。同样,我们需要服务器节点的IP地址:
![](http://dockerone.com/uploads/article/20161221/dee2768a7ca573a445959726644a1746.png)
然而,这一次,目标地址在UI中指定,并且当服务器IP更改时,容器可以重复使用而不用麻烦。
![](http://dockerone.com/uploads/article/20161221/f58488f9d5ffa2794be8c460c89c14a8.jpg)
镜像创建脚本安装了使用Mix IDE所需的内容,但我们可能需要安装其他工具或稍后调整容器。正如我们上面已经看到的,我们可以在容器内执行命令,这甚至可以是一个交互式shell:
![](http://dockerone.com/uploads/article/20161221/8956d44991a051bf318967e623939e1a.jpg)
成功!
![](http://dockerone.com/uploads/article/20161221/2165d5a4b40dfb0182df33ef669bb63e.jpg)
上一篇奠定了基础的知识点以后,我们开始区块链之旅了!
我们要做的第一件事是将“geth”节点连接到以太坊生产网络,从而保证我们的本地区块链同步,并为其他工具打开服务端口 - 当然也是在容器中运行。
![](http://dockerone.com/uploads/article/20161221/9c453628eb0e384dbf02c37093676255.jpg)
通过“docker run”命令,启动镜像“ethereum / client-go”。 RUN命令具有以下参数:
“-it”以交互模式启动容器,并将容器的标准输出发送到我们的终端。当以后重新启动容器时,我们可以选择在后台运行该进程,但是现在我们要看看发生了什么。
“ - -name”给容器以逻辑名“ethereum”,我们稍后可以使用它来访问这个实例。
“-p 30303:30303 -p 8545:8545 -p 8546:8546”公开并且将三个端口从容器内部映射到外部。
“-v /opt/docker/ethereum:/root/.ethereum”将主机目录“/ opt / docker / ethereum”(我们要存储区块链数据的位置)挂载到位置“/ root
/ .ethereum“。后者是“geth”在使用root用户帐户启动时存储所有信息的默认位置。
这个镜像的ENTRYPOINT命令“geth”可以通过INSPECTing可视化来调用,就像我们在主机上直接运行时使用该工具一样。请注意,容器命令行参数不能(容易)过后更改,如果需要不同的命令行,我们将需要创建一个新容器。然而从Docker的角度“容器很便宜”,所以这个约束不是真正的问题,特别是数据不在容器中,不需要重新下载。有一件事要记住:同一时间只有一个“geth”节点可以访问blockchain数据,所以不可能同时运行多个主“geth”节点。
“ - -ws - -rpc”分别激活“geth”的Web接口和HTTP RPC接口。“ - -rpcaddr”0.0.0.0“ - -wsaddr”0.0.0.0“向网络上的所有地址开放这些接口。这样做通常会有点危险,但我们不是在主机的物理网络上运行。这个部分后面会介绍更多。执行上面的命令应该启动一个新的容器,调用“geth”工具,然后开始下载blockchain数据。
(注意:您可以使用“-fast”选项)。
![](http://dockerone.com/uploads/article/20161221/343e9e0dc5affe1631a1457182a918d1.jpg)
![](http://dockerone.com/uploads/article/20161221/2165d5a4b40dfb0182df33ef669bb63e.jpg)
以下行值得重点关注:
![](http://dockerone.com/uploads/article/20161221/23134536e776582b76e45e73e5de023b.jpg)
![](http://dockerone.com/uploads/article/20161221/c57a0de702d857f59e3ec34234a4eb32.jpg)
1、首先,告警提示“geth”抱怨没有定义“etherbase”。 “etherbase”是成功挖掘区块,执行智能合约并在区块链内返回结果之后用来接收以太奖励的“默认以太坊地址”。这个帐户,在开发合同时也很方便。
2 、接下来,我们看到blockchain数据被写入“/root/.ethereum/chaindata”,因为我们已经从我们的主机挂载了这个目录,我们应该可以在本地磁盘上看到出现的数据:
![](http://dockerone.com/uploads/article/20161221/8b6449fdaadf2e3fae479bbc2b7aabfc.jpg)
3、最后,HTTP和Web socket端点已经打开,并且创建了默认的IPC(进程间通信)文件句柄“/root/.ethereum/geth.ipc”。这通常会隐藏在容器中,但是我们已经挂载了外部目录,所以该文件可以用于与这个“geth”节点通信。
剩下的就是定义一个默认的以太坊帐户。使用Docker命令允许在正在运行的容器中执行命令,所以很容易。注意,这各操作不会打开另一个不同的容器,它连接到现在运行的容器。
![](http://dockerone.com/uploads/article/20161221/58e4373007807fcfce27b8cf0f9e21b6.jpg)
不要忘记记下以太坊地址和密码。为了被“geth”节点识别,容器必须重新启动。新帐户可以在我们挂载的数据目录中找到:
![](http://dockerone.com/uploads/article/20161221/43f697aed9c4c6a23b37cc3bf8e5651b.jpg)
在交互式模式下,容器实例可以使用CTRL + C停止。否则,应该调用docker STOP命令。
关于这一点的最后说明:
为了能与以太坊网络同步,主机时间必须精确匹配以太网网络时间。因此,可能需要使用NTP协议与“世界时间”执行同步:
![](http://dockerone.com/uploads/article/20161221/74773516b6b4fa6ab296b7e479c74c94.jpg)
容器相关知识
在当前配置中,我们有一个可以挂载到我们的容器中的以太坊数据目录。这不是因为区块链数据只能在任何情况下由一个进程访问,而是访问可由Ethereum节点用于进程间通信的IPC文件描述符。因此,我们可以在这里继续,而不需要访问网络。然而,为了充分利用我们的完整容器化以太坊节点,了解Docker如何与网络结合可以大大帮助我们为我们未来的用例找到最佳解决方案。众所周知,网络可以是相当复杂的,所以我们在这里只专注于文章内容相关的部分。
默认情况下,Docker容器无法访问主机的网络。如果这样的话,容器化有什么意义呢?作为替代,Docker创建一个单独的虚拟网络,所有容器和主机都可以访问:“docker0”。可以通过显示主机的网络配置查看:
![](http://dockerone.com/uploads/article/20161221/9402ee02ab036b090b9892436f84fd18.jpg)
除了我们的本地网络“eth0”(或类似,NB。eth以太网,而不是以太坊),我们看到名为“docker0”的网络。它是一个不同的子网,172.17.42.1是这个网络上的主机IP地址。为了简单,我们将使用由所有容器共享的默认“docker0”网络。但是,知道Docker也允许创建单独的逻辑网络并将它们分配到特定的容器!
获取容器的IP地址不太直接。默认情况下,在轻量级Linux镜像中未安装“ifconfig”。我们可以使用命令“sudo docker exec apt-get -y install .....”安装一切,但是这个需要在每个容器中一次又一次地执行。有一个更容易的解决方案:
![](http://dockerone.com/uploads/article/20161221/13b80e00d7f43eb73d2dd989f5f33424.jpg)
对于这个IP必须要清楚的事情是,它会在在容器重新启动时改变。这个对于将IP用于在创建另一个容器作为命令行参数传递时可能是一个问题,我们将在下面看到。
顺便提一句,INSPECT命令允许查看关于容器,系统和IO配置,启动命令行,文件路径和挂载等等的任何信息。
![](http://dockerone.com/uploads/article/20161221/733822e779e9d71af9b3a7b2215959ea.jpg)
![](http://dockerone.com/uploads/article/20161221/f692475eec3fff02d9015a408785e734.jpg)
![](http://dockerone.com/uploads/article/20161221/c7ca514a065a301aeff11304ec24d93e.jpg)
![](http://dockerone.com/uploads/article/20161221/80ff1df0a25bc9e2b42cb48dc02949eb.jpg)
4 、连接JavaScript控制台
接下来,我们想让以太坊主节点与“geth”JavaScript控制台进行交互。这个十分简单…
而棘手的部分是两个容器化的“geth”节点之间的进程间通信。第一个选项是使用安装的数据目录中存在的IPC文件。这是当在同一主机上运行时“geth”节点通信的典型方式。我们需要的是将数据目录安装到第二个节点,在同一个地方,所以“geth”“看到”另一个节点,就好像它只运行一个控制台窗口。两个容器使用相同的IPC描述符进行互连:
![](http://dockerone.com/uploads/article/20161221/0bb63e756bc014728a88283c88003781.png)
替代方案是Web socket或HTTP接口。这需要知道主节点的IP地址,我们知道如何找出.
![](http://dockerone.com/uploads/article/20161221/14ee6db6e31b03188589af4cc6671713.jpg)
此方法有一个重要的障碍:我们必须指定主“geth”节点的IP地址作为第二个容器的命令行的一部分。一旦创建,此IP声明不能再更改(除了在配置文件上做手脚),所以这个容器只有在目标容器重新启动和其IP更改之前才有用。
最简单的解决方案是删除此容器,并在每次需要控制台时启动一个新容器。记住 - “容器很便宜”,我们可以用脚本自动化:
![](http://dockerone.com/uploads/article/20161221/88abe7b73d6469f332f9d7dce39272b3.png)
5 、运行MIX IDE
现在它将要变得非常有趣。到目前为止,我们使用纯命令行“geth”实例在单独的容器中运行,我们使它们进行通信。运行Ethereum Mix IDE增加了一个新的挑战:使用图形用户界面。
Docker不是真正设计为在容器内运行UI,但是我们可以使用各种技巧来解决。目前有三种方式:
1)将整个X11服务器安装到容器中,并使用一些魔法:),如下所述。这个方式很重,但却是完全“Docker方式”让容器保持隔离。
2)简单地将VNC服务器安装到容器中并远程打开UI。很聪明,但由于性能问题用VNC工作却不是真的那么趣。
3)在正确的地方将Linux主机的X11 IPC(进程间通信)socket装入容器,这是相对优雅的,但却打破了容器之间的隔离,因此可能带来安全和稳定问题。
这个问题解决了,我们需要将Mix IDE转换为容器。由于以太坊团队尚未提供预定义的镜像,我们勇敢地使用“Dockerfile”构建自己的镜像。
第一步是创建一个目录来存储Dockerfile,让我们说“ethereum-mix-ide”。接下来,在内部创建名为“Dockerfile”的文件(文件名是必需的),其内容如下:
![](http://dockerone.com/uploads/article/20161221/97e41b69652a2d5cf8db49fbc0fad5e0.jpg)
![](http://dockerone.com/uploads/article/20161221/cba5b8038973110602f8bc6a36ad013a.jpg)
最后,在目录中,我们调用Docker命令,逐步执行此脚本,并将最终结果保存到我们的新镜像中。请不要忘记在末尾的“。”,因为它是命令行的一部分。
![](http://dockerone.com/uploads/article/20161221/3d40a8f8420f0ec2b323920c263e6032.png)
“Dockerfile”脚本是相当自我解释 。我们的镜像是基于最新的官方UBUNTU镜像。首先,它安装各种工具和Mix IDE。为了能够连接到X服务器,正在运行的进程不能是“root”。因此,脚本创建一个名为“mix”的用户并赋予他sudo权限。最后,“mix-ide”设置为自动启动点。
让我们来验证一下结果:
![](http://dockerone.com/uploads/article/20161221/cf9a1b1db9e8e4d196608e0094e5069b.png)
镜像准备好了,我们将创建一个新的容器,并自豪地命名为“ethereumix”
![](http://dockerone.com/uploads/article/20161221/acc0f81405860e393e7032af53f2e0af.jpg)
一旦构建,容器可以随时重新启动:
![](http://dockerone.com/uploads/article/20161221/ec519e976ce6b2b8c7ba3ec25d48772b.png)
或者,在交互模式下查看所有Beta版的警告消息:
![](http://dockerone.com/uploads/article/20161221/03c6fe339889cc5e317b7077de8a5615.png)
你可能已经注意到这个参数:“-p 18545:8545”。它确实是一个参数,没有typo :)“geth”主节点容器已经将它的端口8545绑定到主机端口8545,所以我们需要选择另一个地方绑定。由于Mix
IDE容器启动到“geth”主节点的连接,因此绑定位置不重要。
“-v /tmp/.X11-unix:/tmp/.X11-unix”将我们的本地X11服务器socket挂载到容器,这次使用Docker的VOLUME功能,“-e DISPLAY = $ DISPLAY”设置$
DISPLAY环境变量在容器内的值与我们在主机上的值相同。此变量指定X客户端要显示的地址,这是必须设置的。
Mix IDE不需要访问Blockchain数据,但是我们需要在我们要在区块链上部署Smart Contract时联系主要的以太坊“geth”服务器节点。同样,我们需要服务器节点的IP地址:
![](http://dockerone.com/uploads/article/20161221/dee2768a7ca573a445959726644a1746.png)
然而,这一次,目标地址在UI中指定,并且当服务器IP更改时,容器可以重复使用而不用麻烦。
![](http://dockerone.com/uploads/article/20161221/f58488f9d5ffa2794be8c460c89c14a8.jpg)
镜像创建脚本安装了使用Mix IDE所需的内容,但我们可能需要安装其他工具或稍后调整容器。正如我们上面已经看到的,我们可以在容器内执行命令,这甚至可以是一个交互式shell:
![](http://dockerone.com/uploads/article/20161221/8956d44991a051bf318967e623939e1a.jpg)
成功!
![](http://dockerone.com/uploads/article/20161221/2165d5a4b40dfb0182df33ef669bb63e.jpg)
相关文章推荐
- 基于Docker搭建一个Go-ethereum节点(上)
- 用Docker在一台笔记本电脑上搭建一个具有10个节点7种角色的Hadoop集群(上)-快速上手Docker
- 基于Docker快速搭建多节点Hadoop集群
- 简单几步搭建一个基于Docker的Tomcat运行环境!
- 基于Docker快速搭建多节点Hadoop集群
- 基于Docker快速搭建多节点Hadoop集群--已验证
- 简单几步搭建一个基于Docker的Tomcat运行环境!
- 002 Ubuntu16.04上基于docker搭建以太坊go-ethereum客户端
- 用Docker在一台笔记本电脑上搭建一个具有10个节点7种角色的Hadoop集群(下)-搭建Hadoop集群
- GO编译环境搭建(基于SublimeText3)
- 基于hexo+github搭建一个独立的博客
- Docker学习笔记之一,搭建一个JAVA Tomcat运行环境
- 02.go搭建一个web服务器
- 【云计算虚拟化】基于docker的caffe环境搭建
- 一步一步教你搭建基于docker的MongoDB复制集群环境
- Docker学习笔记之一,搭建一个JAVA Tomcat运行环境
- 一个基于Mahout与hadoop的聚类搭建
- 基于Eclipse搭建SSH框架:第四篇 使用SSH开发一个小程序
- 搭建一个简单的基于web的网络流量监控可视化系统
- Nginx+Tomcat基于Docker的搭建