如何使用Docker部署MongoDB副本集

我写了一篇有关如何使用DevOps时尚风格部署mongodb集群的新文章,在本文中,我正在使用Terraform,Ansible,Packer和更酷的技术,我强烈建议您阅读它。

以DevOps时尚风格(将基础架构作为代码)部署MongoDB副本集。


本文将逐步介绍如何使用docker设置带有身份验证的MongoDB副本集。

我们将在本文中使用的是:

  • MongoDB 3.4.1
  • 适用于Mac 1.12.6的Docker

副本集的体系结构

带有docker的副本集的架构

在上图中,我们看到了使用docker复制集的结果。

#先决条件

  • docker基础知识
  • 安装了dockerdocker-machine
  • mongoDB的基础知识
  • bash脚本编写的基础知识

如果您使用的是Mac或Windows,请考虑使用虚拟机。我将在MacOS Sierra上使用VirtualBox运行我们的mongoDB实例。

#步骤1 —创建我们的3个docker-machines

要创建docker机器,我们需要在终端中发出下一个命令:

$ docker-machine create -d virtualbox manager1

此命令将使用virtualbox作为我们的虚拟化提供程序创建一个名为manager1的计算机。

现在让我们创建两个左 docker-machine

$ docker-machine create -d virtualbox worker1
$ docker-machine create -d virtualbox worker2

要验证是否创建了我们的机器,让我们运行以下命令:

$ docker-machine ls
// the result will be
NAME    ACTIVE   DRIVER     STATE     URL    
manager1   -   virtualbox   Running  tcp://192.168.99.100:2376           
worker1    -   virtualbox   Running  tcp://192.168.99.101:2376
worker2    -   virtualbox   Running  tcp://192.168.99.102:2376

#步骤2 — MongoDB主节点的配置

现在我们有了三台机器,让我们将其放置在第一台机器上以启动mongodb配置,让我们运行下一个命令:

$ eval `docker-machine env manager1`

创建我们的MongoDB容器之前,还有一个已经存在了很长讨论了非常重要的课题数据库持久ocker containers,并为实现这一挑战,我们所要做的是创建一个docker volume

$ docker volume create --name mongo_storage

现在,让我们附加创建的卷以启动我们的第一个mongo容器并设置配置。

$ docker run --name mongoNode1 \
-v mongo_storage:/data \
-d mongo \
--smallfiles

接下来,我们需要创建密钥文件。

密钥文件的内容用作副本集成员的共享密码。对于副本集的所有成员,密钥文件的内容必须相同。

$ openssl rand -base64 741 > mongo-keyfile
$ chmod 600 mongo-keyfile

接下来,我们创建一个文件夹,用于存放mongo_storage卷中的数据,密钥文件和配置:

$ docker exec mongoNode1 bash -c 'mkdir /data/keyfile /data/admin'

下一步是创建一些管理员用户,让我们创建一个看起来像这样的admin.jscopy.js文件:

// admin.js
admin = db.getSiblingDB("admin")
// creation of the admin user
admin.createUser(
  {
    user: "cristian",
    pwd: "cristianPassword2017",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)
// let's authenticate to create the other user
db.getSiblingDB("admin").auth("cristian", "cristianPassword2017" )
// creation of the replica set admin user
db.getSiblingDB("admin").createUser(
  {
    "user" : "replicaAdmin",
    "pwd" : "replicaAdminPassword2017",
    roles: [ { "role" : "clusterAdmin", "db" : "admin" } ]
  }
)

//replica.js
rs.initiate({
 _id: 'rs1',
 members: [{
  _id: 0, host: 'manager1:27017'
 }]
})

IMPORTANT

密码应随机,长且复杂,以确保系统安全并防止或延迟恶意访问。有关内置角色的完整列表,请参见数据库用户角色,这些角色与数据库管理操作有关。

我们所做的直到知道:

  • 创建了mongo_storagedocker volume。
  • 创建了mongo-keyfile,openssl密钥生成。
  • mongoDB创建了admin.js文件 admin用户。
  • 创建了copy.js文件,以初始化副本集。

好的,让我们继续将文件传递到容器。

$ docker cp admin.js mongoNode1:/data/admin/
$ docker cp replica.js mongoNode1:/data/admin/
$ docker cp mongo-keyfile mongoNode1:/data/keyfile/

// change folder owner to the user container
$ docker exec mongoNode1 bash -c 'chown -R mongodb:mongodb /data'

我们所做的是,我们需要传递到容器中的文件,然后修改 / data文件夹所有者 到容器的用户,因为容器用户是需要访问这个文件夹和文件的用户。

现在,所有内容都已设置好,我们准备使用副本集配置重新启动mongod实例。

在启动经过身份验证的mongo容器之前,让我们创建一个env文件来设置我们的用户和密码。

MONGO_USER_ADMIN=cristian
MONGO_PASS_ADMIN=cristianPassword2017
MONGO_REPLICA_ADMIN=replicaAdmin
MONGO_PASS_REPLICA=replicaAdminPassword2017

现在我们需要删除容器并开始一个新的容器。为什么?,因为我们需要提供副本集和身份验证参数,并且为此,我们需要运行以下命令:

// first let's remove our container
$ docker rm -f mongoNode1
// now lets start our container with authentication 
$ docker run --name mongoNode1 --hostname mongoNode1 \
-v mongo_storage:/data \
--env-file env \
--add-host manager1:192.168.99.100 \
--add-host worker1:192.168.99.101 \
--add-host worker2:192.168.99.102 \
-p 27017:27017 \
-d mongo --smallfiles \
--keyFile /data/keyfile/mongo-keyfile \
--replSet 'rs1' \
--storageEngine wiredTiger \
--port 27017

这里发生了什么………似乎是在滥用旗帜。

让我分两部分向您解释:

Docker标志:

  1. --env-file读取ENV文件,并设置environment在容器内的变量。
  2. --add-host标志将条目添加到Docker容器的/etc/hosts文件中,因此我们可以使用主机名代替IP地址。在这里,我们映射了我们之前创建的3个docker-machines。

要更深入地了解docker run命令,请阅读Docker文档

Docker Flags

为了设置mongo副本集,我们需要各种mongo标志

  1. --keyFile 这个标志是用来告诉mongo在哪里 mongo-keyfile.
  2. --replSet 该标志用于设置副本集的名称。
  3. --storageEngine由于mongoDB 3.4.1的默认引擎为wiredTiger,因此不需要此标志用于设置mongoDB的引擎

为了对mongo副本集有更深入的了解,请阅读MongoDB文档,我也建议使用MongoUniversity课程以了解有关此主题的更多信息。

mongoNode1容器的最后一步是启动副本集,我们将通过运行以下命令来做到这一点:

$ docker exec mongoNode1 bash -c 'mongo < /data/admin/replica.js'

您应该会看到以下内容:

MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
{ "ok" : 1 }
bye

现在,让我们使用以下命令创建管理员用户:

$ docker exec mongoNode1 bash -c 'mongo < /data/admin/admin.js'

您应该会看到以下内容:

MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
admin
Successfully added user: {
 "user" : "cristian",
 ...
Successfully added user: {
 "user" : "replicaAdmin",
...
bye

现在,要进入副本,请运行以下命令:

$ docker exec -it mongoNode1 bash -c 'mongo -u $MONGO_REPLICA_ADMIN -p $MONGO_PASS_REPLICA --eval "rs.status()" --authenticationDatabase "admin"'

您应该已经准备好,看到类似以下内容:

MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
{
 "set" : "rs1",
 ...
 "members" : [
  {
   "_id" : 0,
   "name" : "manager1:27017",
   ...
 "ok" : 1
}

#步骤3 —再添加2个mongo节点容器

现在一切就绪,让我们再启动2个节点并将它们加入副本集。

要添加第一个节点,我们将其更改为worker1 docker计算机,如果您使用的是本地计算机,请运行以下命令:

eval `docker-machine env worker1`

如果您不在本地运行,只需将终端指向下一个服务器即可。

现在,由于我们将重复几乎为mongoNode1所做的所有步骤,因此让我们创建一个脚本来为我们运行所有命令。

让我们创建一个名为create-replica-set.sh的文件,然后看看如何组成main函数:

function main {
  init_mongo_primary
  init_mongo_secondaries
  add_replicas manager1 mongoNode1
  check_status manager1 mongoNode1
}
main

现在,让我向您展示此功能的组成:

INIT MONGO主要功能

function init_mongo_primary {
# [@params](http://twitter.com/params) name-of-keyfile
createKeyFile mongo-keyfile

# [@params](http://twitter.com/params) server container volume
createMongoDBNode manager1 mongoNode1 mongo_storage

# [@params](http://twitter.com/params) container
init_replica_set mongoNode1
}

该函数内部也有对函数的调用,没有添加任何新内容,我们之前已经看过所有功能,让我为您描述它的作用:

  1. 副本集身份验证创建密钥文件
  2. 创建一个mongodb容器,并接收2个参数:a)待定位的服务器,b)容器的名称,c)docker卷的名称,所有我们之前看到的功能。
  3. 最后,它将使用与我们之前完全相同的步骤来启动副本。

INIT MONGO SECONDARY FUNCTION

function init_mongo_secondaries {
# [@Params](http://twitter.com/Params) server container volume
createMongoDBNode worker1 mongoNode1 mongo_storage
createMongoDBNode worker2 mongoNode2 mongo_storage
}

此功能的作用是为副本集创建其他2个mongo容器,并执行与mongoNode1相同的步骤,但是这里我们不包括副本集实例化和admin用户创建,因为这些不是必需的,因为副本集将与副本的所有节点共享数据库配置,以后再将它们添加到主数据库中。

添加复制功能

<pre class="gl gm gn go gp lk ll dl" style="box-sizing: inherit; margin: 56px 0px 0px; overflow-x: auto; padding: 20px; background: rgba(0, 0, 0, 0.05); color: rgba(0, 0, 0, 0.8); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"># [@params](http://twitter.com/params) server container
function add_replicas {
  echo '·· adding replicas >>>> '$1' ··' switchToServer $1

  for server in worker1 worker2
   do
    rs="rs.add('$server:27017')"
    add='mongo --eval "'$rs'" -u $MONGO_REPLICA_ADMIN 
         -p $MONGO_PASS_REPLICA --authenticationDatabase="admin"'
    sleep 2
    wait_for_databases $server
    docker exec -i $2 bash -c "$add"
  done
}</pre>

在这里,我们要做的是最后将另外两个mongo容器添加到副本集配置上的主数据库中,首先我们遍历剩下的机器以添加容器,在循环中我们准备配置,然后检查容器是否准备好了,我们通过调用函数来做到这一点wait_for_databases,然后将机器作为参数传递给我们,然后在主数据库中执行配置,然后我们应该收集如下消息:

MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
{ "ok" : 1 }

这意味着mongo容器已成功添加到副本。

最后,我们使用main中的最后一个功能检查副本集的状态:

# [@params](http://twitter.com/params) server container
function check_status {
switchToServer $1
cmd='mongo -u $MONGO_REPLICA_ADMIN -p $MONGO_PASS_REPLICA
--eval "rs.status()" --authenticationDatabase "admin"'
docker exec -i $2 bash -c "$cmd"
}

既然我们已经了解了自动化脚本的功能并且知道将要执行的操作,那么现在该执行自动化bash脚本了,如下所示:

请注意,如果已完成上述所有步骤,则需要重置我们已实现的所有内容,以避免任何冲突名称问题,要重置配置,请在github存储库中找到一个reset.sh文件

# and this how we can execute the script that will configure 
# everything for us.
$ bash < create-replica-set.sh

如果一切设置正确,我们应该看到来自mongodb的消息,如下所示:

MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
{
 "set" : "rs1",
 ...
 },
 "members" : [
  {
   "_id" : 0,
   "name" : "manager1:27017",
   "health" : 1,
   "state" : 1,
   "stateStr" : "PRIMARY",
   ...
  },
  {
   "_id" : 1,
   "name" : "worker1:27017",
   "health" : 1,
   "state" : 2,
   "stateStr" : "SECONDARY",
   ...
  },
  {
   "_id" : 2,
   "name" : "worker2:27017",
   "health" : 1,
   "state" : 0,
   "stateStr" : "STARTUP",
   ...
  }
 ],
 "ok" : 1
}

正如您所看到的,每个容器现在都已正确配置,需要注意的是,我们--add-host像以前一样使用了来自docker 的标志,并将这些条目添加到Docker容器的/ etc / hosts文件中,因此我们可以使用主机名代替IP地址。

两个节点都可能需要一分钟才能完成从mongoNode1的同步。

您可以通过查看日志来查看每个mongo Docker容器中发生的情况。您可以通过在任何docker-machine服务器上运行此命令来执行此操作。

$ docker logs -ft mongoContainerName

现在我们已经启动并运行了一个MongoDB副本设置服务,让我们修改用户,或者您可以创建另一个用户并授予一些权限来对数据库执行Crud操作,因此,仅出于说明目的,这是一个不好的做法,让我添加一个的管理员用户的超级角色。

# we are going to assign the root role to our admin user
# we enter to the container
$ docker exec -it mongoNode1 bash -c 'mongo -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'
# Then we execute the following in the mongo shell
# Mongo 3.4.1 shell
> use admin
> db.grantRolesToUser( "cristian", [ "root" , { role: "root", db: "admin" } ] )
>

现在,他拥有一个可以做任何事情的超级用户,因此让我们创建一个数据库并插入一些数据。

$ docker exec -it mongoNode1 bash -c 'mongo -u $MONGO_USER_ADMIN -p $MONGO_PASS_ADMIN --authenticationDatabase "admin"'
# Mongo 3.4.1 shell
> use movies
> db.movies.insertMany([{
  id: '1',
  title: 'Assasins Creed',
  runtime: 115,
  format: 'IMAX',
  plot: 'Lorem ipsum dolor sit amet',
  releaseYear: 2017,
  releaseMonth: 1,
  releaseDay: 6
}, {
  id: '2',
  title: 'Aliados',
  runtime: 124,
  format: 'IMAX',
  plot: 'Lorem ipsum dolor sit amet',
  releaseYear: 2017,
  releaseMonth: 1,
  releaseDay: 13
}, {
  id: '3',
  title: 'xXx: Reactivado',
  runtime: 107,
  format: 'IMAX',
  plot: 'Lorem ipsum dolor sit amet',
  releaseYear: 2017,
  releaseMonth: 1,
  releaseDay: 20
}, {
  id: '4',
  title: 'Resident Evil: Capitulo Final',
  runtime: 107,
  format: 'IMAX',
  plot: 'Lorem ipsum dolor sit amet',
  releaseYear: 2017,
  releaseMonth: 1,
  releaseDay: 27
}, {
  id: '5',
  title: 'Moana: Un Mar de Aventuras',
  runtime: 114,
  format: 'IMAX',
  plot: 'Lorem ipsum dolor sit amet',
  releaseYear: 2016,
  releaseMonth: 12,
  releaseDay: 2
}])
# inserted 5 documents
> 

现在,我们有了一个电影数据库,其中包含包含5部电影:D的电影集合。

#回顾的时间

我们所做的…

我们使用自动脚本使用Docker配置并启动带有身份验证MongoDB副本集

在安全方面,我们创建:

  • 两种用户类型,即管理数据库集群管理数据库。
  • 我们创建一个密钥文件,并在启用身份验证的情况下启动副本

如果为数据库正确配置了访问控制,则攻击者应该无法访问您的数据。查看我们的安全检查表,以帮助发现潜在的漏洞。— @MongoDB文件

如果我们想为我们的架构增加更多的安全性,我们可以使用docker-machines 创建一个Swarm集群,并且docker swarm可以很好地处理网络通信,还可以在容器中创建非root用户,并且可以启用加密数据在mongoDB中,但是此主题不在本文的范围之内。


#结论

现在,我们有了一个可用的MongoDB复制集。您可以随时将节点添加到此副本集。您甚至可以停止mongo容器或主要mongoNode1中的一个,然后看着另一个mongoNode接管新的主要容器。由于数据写在docker卷上,因此重启这些节点中的任何一个都不是问题。数据将保留并重新加入副本集。

给我们带来的好处是,我们看到了如何使用bash文件使整个过程自动化。

您面临的一个挑战是修改bash脚本并使其更加动态,因为该脚本非常适合本文的规范,而另一个挑战是向体系结构中添加一个任意Mongo节点


Github仓库

要获取本文的完整脚本文件,可以在以下仓库中进行检查。

github-Crizstian / mongo-replica-with-docker:如何使用Docker部署MongoDB副本集github.com

进一步阅读


翻译自:https://towardsdatascience.com/how-to-deploy-a-mongodb-replica-set-using-docker-6d0b9ac00e49

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容