Как настроить Монго реплики на Кубернете?

Я хотел бы установить набор реплик Mongo на Kubernetes. Я хотел бы иметь три реплики. Это означает, что мне нужно запустить 3 экземпляра.

Должен ли я запускать три контейнера, с Mongo в каждом из них, и использовать сервис для основного? Или я должен каким-то образом использовать контроллер репликации?

Ответ 1

Этот ответ устарел. Я написал подробный пошаговый учебник здесь, используя более современные методы. Я настоятельно рекомендую прочитать все это.

В двух словах вы запустите приложение sidecar, чтобы настроить набор реплик для вас, и либо используйте службу на один экземпляр, либо выполните ping API K8s для IP-адресов pod.

Пример:. Это будет работать только в облаке Google. Вам нужно будет внести изменения для других платформ, особенно вокруг томов:

  • Следуйте примеру https://github.com/leportlabs/mongo-k8s-sidecar.git
    • git clone https://github.com/leportlabs/mongo-k8s-sidecar.git
    • cd mongo-k8s-sidecar/example/
    • make add-replica ENV=GoogleCloudPlatform (сделайте это три раза)
  • Подключиться к набору реплик через службы.
    • mongodb://mongo-1,mongo-2,mongo-3:27017/dbname_?
  • Вы также можете использовать IP-адреса raw pod вместо создания службы на каждый блок

Ответ 2

Как правило, для создания кластерного набора таких узлов, как mongo с наборами реплик, вы создадите Service, который отслеживает содержимое под именем службы (например, создайте контроллер репликации MongoDB с тегом mongodb, и Service отслеживание этих экземпляров) Затем сервис может быть запрошен для своих членов (используя сервер API, вы можете искать узлы с помощью

curl -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://kubernetes/api/v1/namespaces/default/endpoints/mongodb

где mongodb - ваш селектор имени службы.

который возвращает объект JSON с кучей полей, поэтому хороший способ легко проанализировать это - использовать jq https://stedolan.github.io/jq/

соединение команды curl с запросом jq, например

jq '.subsets[].addresses[]' | jq '{ip: .ip, host:.targetRef.name}' вернет IP и имена хостов экземпляров mongodb в вашем кластере.

Итак, теперь вы знаете, кто находится в кластере, и вы можете создать набор реплик в своем init script. Очевидно, здесь это означает, что вам нужно сначала запустить Service, ваш запуск script должен ждать, пока все узлы будут вставлены и зарегистрированы в службе, а затем вы можете продолжить. Если вы используете одно изображение с одним script, оно будет запускать n каждый node, поэтому вам нужно проверить, что набор реплик уже не существует или обрабатывает ошибки. Первый блок для регистрации должен выполнять работу. Другой вариант - запустить все узлы как отдельные узлы, затем запустить отдельный загрузочный файл script, который создаст набор реплик.

Наконец, вы вызываете кластер mongodb, вам нужно будет указать URL-адрес с именем набора реплик в качестве опции:

mongodb://mongodb:27017/database?replicaSet=replicaSetName

Поскольку вы не знаете IP-адрес ведущего устройства, вы вызываете его через службу mongodb, которая будет загружать баланс для одного из узлов, и если вы не укажете имя набора реплик, вы закончится ошибками подключения, так как только мастер может получить запросы на запись.

Очевидно, что это не пошаговое руководство, но я надеюсь, что вы начнете.

Ответ 3

Это пример, который я сейчас выполняю.

apiVersion: v1
kind: Service
metadata:
  labels:
    name: mongo
  name: mongo-svc1
spec:
  ports:
    - port: 27017
      targetPort: 27017
  selector:
    type: mongo-rs-A
---
apiVersion: v1
kind: Service
metadata:
  labels:
    name: mongo
  name: mongo-svc2
spec:
  ports:
    - port: 27017
      targetPort: 27017
  selector:
    type: mongo-rs-B
---
apiVersion: v1
kind: Service
metadata:
  labels:
    name: mongo
  name: mongo-svc3
spec:
  ports:
    - port: 27017
      targetPort: 27017
  selector:
    type: mongo-rs-C
---

apiVersion: v1
kind: ReplicationController

metadata:
  name: mongo

spec:
  replicas: 1
  selector:
    name: mongo-nodea
    role: mongo
    environment: test

  template:
    metadata:
      labels:
        name: mongo-nodea
        role: mongo
        environment: test
        type: mongo-rs-A
    spec:
      containers:
        - name: mongo-nodea
          image: mongo
          command:
            - mongod
            - "--replSet"
            - rsABC
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-persistent-storage
              mountPath: /data/db
      volumes:
        - name: mongo-persistent-storage
          flocker:
            datasetName: FlockerMongoVolSetA
---
apiVersion: v1
kind: ReplicationController

metadata:
  name: mongo-1

spec:
  replicas: 1
  selector:
    name: mongo-nodeb
    role: mongo
    environment: test

  template:
    metadata:
      labels:
        name: mongo-nodeb
        role: mongo
        environment: test
        type: mongo-rs-B
    spec:
      containers:
        - name: mongo-nodeb
          image: mongo
          command:
            - mongod
            - "--replSet"
            - rsABC
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-persistent-storage
              mountPath: /data/db
      volumes:
        - name: mongo-persistent-storage
          flocker:
            datasetName: FlockerMongoVolSetB
---
apiVersion: v1
kind: ReplicationController

metadata:
  name: mongo-2

spec:
  replicas: 1
  selector:
    name: mongo-nodec
    role: mongo
    environment: test

  template:
    metadata:
      labels:
        name: mongo-nodec
        role: mongo
        environment: test
        type: mongo-rs-C
    spec:
      containers:
        - name: mongo-nodec
          image: mongo
          command:
            - mongod
            - "--replSet"
            - rsABC
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongo-persistent-storage
              mountPath: /data/db
      volumes:
        - name: mongo-persistent-storage
          flocker:
            datasetName: FlockerMongoVolSetC


kubectl --kubeconfig=clusters/k8s-mongo/kubeconfig get po,svc -L type,role,name
NAME            READY     STATUS    RESTARTS   AGE       TYPE         ROLE      NAME
mongo-1-39nuw   1/1       Running   0          1m        mongo-rs-B   mongo     mongo-nodeb
mongo-2-4tgho   1/1       Running   0          1m        mongo-rs-C   mongo     mongo-nodec
mongo-rk9n8     1/1       Running   0          1m        mongo-rs-A   mongo     mongo-nodea
NAME         CLUSTER_IP   EXTERNAL_IP   PORT(S)     SELECTOR          AGE       TYPE      ROLE      NAME
kubernetes   10.3.0.1     <none>        443/TCP     <none>            21h       <none>    <none>    <none>
mongo-svc1   10.3.0.28    <none>        27017/TCP   type=mongo-rs-A   1m        <none>    <none>    mongo
mongo-svc2   10.3.0.56    <none>        27017/TCP   type=mongo-rs-B   1m        <none>    <none>    mongo
mongo-svc3   10.3.0.47    <none>        27017/TCP   type=mongo-rs-C   1m        <none>    <none>    mongo

В Primary node я собираюсь в оболочку mongo

rs.status() rs.initiate() rs.add( "10.3.0.56:27017" )

В настоящее время я сталкиваюсь с этой проблемой, когда я застрял в статусах Secondary и Startup для двух узлов без первичного.

rs.status()
{
    "set" : "rsABC",
    "date" : ISODate("2016-01-21T22:51:33.216Z"),
    "myState" : 2,
    "term" : NumberLong(1),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "members" : [
        {
            "_id" : 0,
            "name" : "mongo-rk9n8:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 242,
            "optime" : {
                "ts" : Timestamp(1453416638, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2016-01-21T22:50:38Z"),
            "infoMessage" : "could not find member to sync from",
            "configVersion" : 2,
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "10.3.0.56:27017",
            "health" : 1,
            "state" : 0,
            "stateStr" : "STARTUP",
            "uptime" : 45,
            "optime" : {
                "ts" : Timestamp(0, 0),
                "t" : NumberLong(-1)
            },
            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
            "lastHeartbeat" : ISODate("2016-01-21T22:51:28.639Z"),
            "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
            "pingMs" : NumberLong(40),
            "configVersion" : -2
        }
    ],
    "ok" : 1
}

Ответ 5

@Стефен Нгуен

Я просто копирую ваше дело и создаю для него тест пространства имен (я соответствующим образом меняю ваш файл yaml) и инициализирую свои mongo rs:

rs.initiate({
     "_id" : "rsABC",
     "members" : [
          {
               "_id" : 0,
               "host" : "mongo-svc1.test:27017",
               "priority" : 10
          },
          {
               "_id" : 1,
               "host" : "mongo-svc2.test:27017",
               "priority" : 9
          },
          {
               "_id" : 2,
               "host" : "mongo-svc3.test:27017",
                "arbiterOnly" : true
          }
     ]
})

Кажется, он работает:

> rs.status()
{
        "set" : "rsABC",
        "date" : ISODate("2016-05-10T07:45:25.975Z"),
        "myState" : 2,
        "term" : NumberLong(2),
        "syncingTo" : "mongo-svc1.test:27017",
        "heartbeatIntervalMillis" : NumberLong(2000),
        "members" : [
                {
                        "_id" : 0,
                        "name" : "mongo-svc1.test:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 657,
                        "optime" : {
                                "ts" : Timestamp(1462865715, 2),
                                "t" : NumberLong(2)
                        },
                        "optimeDate" : ISODate("2016-05-10T07:35:15Z"),
                        "lastHeartbeat" : ISODate("2016-05-10T07:45:25.551Z"),
                        "lastHeartbeatRecv" : ISODate("2016-05-10T07:45:25.388Z"),
                        "pingMs" : NumberLong(0),
                        "electionTime" : Timestamp(1462865715, 1),
                        "electionDate" : ISODate("2016-05-10T07:35:15Z"),
                        "configVersion" : 1
                },
                {
                        "_id" : 1,
                        "name" : "mongo-svc2.test:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 1171,
                        "optime" : {
                                "ts" : Timestamp(1462865715, 2),
                                "t" : NumberLong(2)
                        },
                        "optimeDate" : ISODate("2016-05-10T07:35:15Z"),
                        "syncingTo" : "mongo-svc1.test:27017",
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "mongo-svc3.test:27017",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 657,
                        "lastHeartbeat" : ISODate("2016-05-10T07:45:25.549Z"),
                        "lastHeartbeatRecv" : ISODate("2016-05-10T07:45:23.969Z"),
                        "pingMs" : NumberLong(0),
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}

Я добавляю mongo node именем службы.

Ответ 6

Как хэдз-ап. Не используйте подход mongo-k8s-sidecar в Production, поскольку он имеет потенциально опасные последствия. Для более актуального подхода к использованию MongoDB с помощью statefulSets k8s см.:

Дополнительная информация о MongoDB и Kubernetes доступна по адресу: http://k8smongodb.net/

Ответ 7

Я использую это как решение. Его продукция НЕ готова.

Настройка репликации MongoDB

Получите весь модуль MongoDB IP kubectl describe pod <PODNAME> | grep IP | sed -E 's/IP:[[:space:]]+//'

и...

Выполнить kubectl exec -i <POD_1_NAME> mongo

и...

rs.initiate({ 
     "_id" : "cloudboost", 
     "version":1,
     "members" : [ 
          {
               "_id" : 0,
               "host" : "<POD_1_IP>:27017",
               "priority" : 10
          },
          {
               "_id" : 1,
               "host" : "<POD_2_IP>:27017",
               "priority" : 9
          },
          {
               "_id" : 2,
               "host" : "<POD_3_IP>:27017",
               "arbiterOnly" : true
          }
     ]
});

Пример:

rs.initiate({  
     "_id" : "cloudboost",
     "version":1,
     "members" : [ 
          {
               "_id" : 0,
               "host" : "10.244.1.5:27017",
               "priority" : 10
          },
          {
               "_id" : 1,
               "host" : "10.244.2.6:27017",
               "priority" : 9
          },
          {
               "_id" : 2,
               "host" : "10.244.3.5:27017",
               "arbiterOnly" : true
          }
     ]
}); 

Обратите внимание: IP может отличаться для вашего кластера.

TODO: Создайте службу безглавых, чтобы автоматически обнаружить узлы и инициализировать репликацию.