让我们尝试定义一种更好的、更简单的方法来设置MongoDB副本集。
现在将从创建三个mongo服务开始。稍后,每个服务都将成为Mongo副本集的成员:
与前面用于创建mongo服务的命令相比,唯一的区别是添加了环境变量MEMBERS。它保存着所有MongoDB的服务名称。下面将使用它作为下一个服务的参数。
由于官方的mongo镜像没有配置Mongo副本集的机制,所以将使用自定义的镜像。它的目的只是配置Mongo副本集。
镜像的定义在conf/Dockerfile.mongo文件中(https://github.com/vfarcic/ cloud-provisioning/blob/master/conf/Dockerfile.mongo)。其内容如下:
dockerfile.mongo扩展了官方的mongo镜像,添加了一个定制的init-mongo-rs.sh脚本,给予它执行权限,并将其作为入口点。
EENTRYPOINT用于定义每当容器运行时将运行的可执行文件。我们指定的任何命令参数都将追加到ENTRYPOINT上。
conf/init-mongo-rs.sh(https://github.com/vfarcic/cloud-provisioning/blob/master/ conf/init-mongo-rs.sh)的脚本如下:
第一部分遍历所有DB的地址(定义为脚本参数)并检查它们是否可用。如果不可用,则在重复循环之前等待3秒钟。
第二部分格式化定义所有成员(id和host)列表的JSON字符串。最后启动副本集,等待3秒钟,并输出其状态。
此脚本是我们在手动设置副本集时执行命令的稍微复杂的版本,并没有使用硬编码的值(例如,服务名称),它的编写方式可以用于成员数不同的Mongo副本集。
剩下的就是将容器作为Swarm服务运行。下面已经构建了vfarcic/mongodevops21的镜像,并将其推送到Docker Hub:(www.xing528.com)
脚本完成后,容器就会停止。通常,Swarm会将停止的容器视为故障,并重新调度它。这不是我们需要的行为。我们希望此服务执行一些任务(配置副本集)并在完成后停止。我们使用无参数的--restart-condition来实现这一点。否则,Swarm将进入一个无休止的循环,不断地重新调度一个服务副本,这个副本在几分钟后就会出现故障。
服务的命令是$MENBERS。当附加到ENTRYPOINT时,完整的命令是init-mongo-rs.sh go-demo-db-rs1 go-demo-db-rs2 go-demo-dbrs 3。让我们确认所有服务(go-demo-db-init除外)都在运行:
输出如下:
唯一没有运行的服务是go-demo-db-init。现在,它执行完成,并且由于使用了无参数的--restart-condition,所以Swarm没有重新调度它。
我们已经建立了一定程度的信任,而且你可能相信go-demo-dbinit正确地完成了它的工作。不过,再查一遍也没什么坏处。由于脚本的最后一个命令输出了副本集的状态,所以可以检查它的日志,以确定是否正确地配置了所有的内容。这意味着我们需要再次费事地查找容器的IP和ID:
日志命令输出的相关部分如下:
Mongo副本集确实配置了所有三个成员。现在有了一组可以提供高可用性的MongoDB的容错集合,可以在go-demo(或任何其他)服务中使用它们:
这个命令与前面几章中使用的命令只有一处不同。如果继续使用主MongoDB的一个地址,就不会有高可用性。当主MongoDB发生故障时,该服务将无法响应请求。即使Swarm会重新调度它,主节点的地址也会变得不同,因为副本集将选择一个新的地址给它。
这一次,我们将所有三个MongoDB指定为环境变量DB的值。服务的代码将该字符串传递给MongoDB驱动程序。于是,驱动程序将使用这些地址推断哪个DB是主节点,并使用它发送请求。所有Mongo驱动程序都具有相同的机制来指定副本集的成员。
最后,让我们确认go-demo服务的所有三个副本都在运行。记住,服务的代码是这样写的,如果无法建立到数据库的连接,服务就会失败。如果所有的服务副本都在运行,就证明我们正确设置了所有的内容:
输出如下(为简洁起见,移除了ID和ERROR列):
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。