Создайте кластер Redis на K8S

контейнер Kubernetes

место для рекламы

Хотите вместе создать новую бессерверную систему исследований и разработок? Добро пожаловать в команду беспроводных серверов Alibaba CBU, мы ищем старших инженеров / технических экспертов по исследованиям и разработкам, отправьте свое резюме на yuanyan.lmh@alibaba-inc.com

Сегодня попробуем развернуть кластер Redis в k8s и узнать больше о деталях и возможностях k8s.

Среда: minikube v0.30 (kubernetes 1.10)

Примечание. Базовые знания и подробности, связанные с redis-cluster, здесь повторяться не будут, вы можете обратиться кпредыдущая статьяНебольшой обзор

анализ проблемы

По сути, нет большой разницы между развёртыванием redis-кластера на k8s и развёртыванием обычного приложения, но нужно обратить внимание на следующие моменты:

  1. REDIS — это приложение с отслеживанием состояния

    Это самая важная проблема, на которую мы должны обратить внимание при развертывании кластера Redis.Когда мы развертываем Redis в виде подов в k8s, данные, кэшированные в каждом поде, разные, и IP-адрес пода может измениться в любое время. , В то время, если вы используете обычное развертывание и службу для развертывания redis-кластера, будет много проблем, поэтому вам нужно использовать StatefulSet + Headless Service для ее решения.

  2. сохранение данных

    Хотя Redis — это кеш в памяти, ему по-прежнему необходимо полагаться на диск для сохранения данных, чтобы кешированные данные можно было восстановить, когда у службы возникнет проблема и она перезапустится. В кластере нам нужно использовать метод общей файловой системы + PV (постоянный том), чтобы позволить всем модулям во всем кластере совместно использовать одно и то же постоянное хранилище.

Введение концепции

Прежде чем мы начнем, давайте подробно познакомимся с некоторыми понятиями и принципами.

Headless Service

Проще говоря, безголовая служба — это служба, которая не указывает IP-адрес кластера, соответственно, в dns-маппинге k8s результатом разрешения безголовой службы является не IP-адрес кластера, а список IP-адресов всех подов, связанных с ним.

StatefulSet

StatefulSetЭто ресурс в k8s, посвященный решению задач развертывания приложений с отслеживанием состояния.Deployment/RCВариант , который имеет следующие особенности:

  1. Каждый под, управляемый StatefulSet, имеет уникальный идентификатор документа/сети, который генерируется в соответствии с числовым законом, вместо того, чтобы иметь случайные имена и IP-адреса, как в развертывании (например, если имя StatefulSet — redis, то имя пода — redis). 0, редис -1...)

  2. Последовательность запуска и остановки ReplicaSet в StatefulSet строго контролируется, и работа N-го модуля должна ожидать выполнения первых N-1 модулей.

  3. Поды в StatefulSet используют стабильное постоянное хранилище, и соответствующий PV не будет уничтожен при удалении пода.

Кроме того, следует отметить, что StatefulSet необходимо использовать с Headless Service.Это добавит еще один уровень к сопоставлению DNS, предоставляемому Headless Service, и, наконец, сформирует сопоставление доменных имен, точное для каждого модуля.Формат выглядит следующим образом:

$(podname).$(headless service name)

С помощью этого сопоставления вы можете использовать доменное имя вместо IP-адреса при настройке кластера для управления кластерами приложений с отслеживанием состояния.

план

С помощью StatefulSet и Headless Service схема развертывания кластера построена следующим образом (картинка из справочной статьи):

Шаги настройки примерно перечислены ниже:

  1. Настройка общей файловой системы NFS
  2. Создание PV и PVC
  3. Создать карту конфигурации
  4. Создать безголовый сервис
  5. Создать StatefulSet
  6. Инициализировать кластер Redis

Фактическая операция

Поскольку используется одноузловая среда minikube, для упрощения сложности в этот раз PV и PVC не настраиваются, а данные монтируются напрямую через обычный Volume.

Создать карту конфигурации

создать первыйredis.confконфигурационный файл

appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

потомkubectl create configmap redis-conf --from-file=redis.confдля создания ConfigMap

Создать безголовый сервис

apiVersion: v1
kind: Service
metadata:
  name: redis-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    port: 6379
  clusterIP: None
  selector:
    app: redis
    appCluster: redis-cluster

Создать StatefulSet

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: redis-app
spec:
  serviceName: "redis-service"
  replicas: 6
  template:
    metadata:
      labels:
        app: redis
        appCluster: redis-cluster
    spec:
      terminationGracePeriodSeconds: 20
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - redis
              topologyKey: kubernetes.io/hostname
      containers:
      - name: redis
        image: "registry.cn-qingdao.aliyuncs.com/gold-faas/gold-redis:1.0"
        command:
          - "redis-server"
        args:
          - "/etc/redis/redis.conf"
          - "--protected-mode"
          - "no"
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
        ports:
            - name: redis
              containerPort: 6379
              protocol: "TCP"
            - name: cluster
              containerPort: 16379
              protocol: "TCP"
        volumeMounts:
          - name: "redis-conf"
            mountPath: "/etc/redis"
          - name: "redis-data"
            mountPath: "/var/lib/redis"
      volumes:
      - name: "redis-conf"
        configMap:
          name: "redis-conf"
          items:
            - key: "redis.conf"
              path: "redis.conf"
      - name: "redis-data"
        emptyDir: {} 

Инициализировать кластер Redis

После создания StatefulSet видно, что запущено 6 подов, но в это время весь кластер redis не инициализирован, нужно использовать официально предоставленныйredis-tribинструмент.

Мы, конечно, можем запустить соответствующий инструмент на любом узле redis для инициализации всего кластера, но это явно не подходит, мы хотим, чтобы обязанности каждого узла были как можно более едиными, поэтому лучше иметь отдельный pod для запуска все инструменты управления кластером.

Здесь нам нужно представитьredis-trib, это официальный инструмент управления кластером Redis, который может создавать и обновлять кластеры Redis.redis-trib.rbТо, как работает этот ruby-скрипт (можно и python-версию на pip тянуть, но мне не удалось его запустить), сейчас (использую5.0.3) был официально интегрирован вredis-cliсередина.

Начните инициализировать кластер, сначала создайте ubuntu pod на k8s в качестве узла управления:

kubectl run -i --tty redis-cluster-manager --image=ubuntu --restart=Never /bin/bash

Войдите в модуль и сначала установите некоторые инструменты, в том числеwget,dnsutils, затем загрузите и установите Redis:

wget http://download.redis.io/releases/redis-5.0.3.tar.gz
tar -xvzf redis-5.0.3.tar.gz
cd redis-5.0.3.tar.gz && make

После компиляцииredis-cliбудет помещен вsrcкаталог, поместите его в/usr/local/binудобно для последующих операций

Затем, чтобы получить IP-адрес хоста из 6 созданных узлов, вы можете пройтиnslookupВ сочетании с правилами доменного имени StatefulSet для поиска, например, для поискаredis-app-0Для IP-адреса этого модуля выполните следующую команду:

root@redis-cluster-manager:/# nslookup redis-app-0.redis-service
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	redis-app-0.redis-service.gold.svc.cluster.local
Address: 172.17.0.10

172.17.0.10это соответствующий ip. В этом развертывании мы используем 0, 1 и 2 в качестве главных узлов и 3, 4 и 5 в качестве подчиненных узлов.Сначала выполните следующую команду, чтобы инициализировать главный узел кластера:

redis-cli --cluster create 172.17.0.10:6379 172.17.0.11:6379 172.17.0.12:6379

Затем прикрепите к ним соответствующие узлы Slave соответственно, здесьcluster-master-idПри создании на предыдущем шаге он даст:

redis-cli --cluster add-node 172.17.0.13:6379 172.17.0.10:6379 --cluster-slave --cluster-master-id adf443a4d33c4db2c0d4669d61915ae6faa96b46
redis-cli --cluster add-node 172.17.0.14:6379 172.17.0.11:6379 --cluster-slave --cluster-master-id 6e5adcb56a871a3d78343a38fcdec67be7ae98f8
redis-cli --cluster add-node 172.17.0.16:6379 172.17.0.12:6379 --cluster-slave --cluster-master-id c061e37c5052c22f056fff2a014a9f63c3f47ca0

После инициализации кластера введите узел по желанию, чтобы проверить информацию о кластере:

На этом инициализация кластера завершена, вводим ноду на пробу, обратите внимание на режим кластераredis-cliнеобходимо добавить-cпараметры для доступа к данным на других узлах:

Создать сервис

Теперь введите любой кластер Node Redis Cluster можно напрямую, но, чтобы иметь возможность предоставить доступ к кластерам других услуг, также необходимо установить услугу для достижения службы открытия и балансировки нагрузки (обратите внимание, что обслуживание здесь и без головы, которое мы создали более раннее обслуживание, не вещь)

Файл yaml выглядит следующим образом:

apiVersion: v1
kind: Service
metadata:
  name: gold-redis
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    protocol: "TCP"
    port: 6379
    targetPort: 6379
  selector:
    app: redis
    appCluster: redis-cluster

Проведите тест после развертывания:

Очень красиво, вся работа сделана здесь~

Справочная статья: