我应该如何在docker swarm中为多任务数据库服务设置卷?

我应该如何在docker swarm中为多任务数据库服务设置卷?

我是 Docker 新手,我想用 Docker Swarm 做一个小项目。我用我的 Django 应用程序构建了 docker 镜像。在 dockerfile 中,我添加了项目文件,迁移了所有模型,然后运行了服务器。现在是时候为 django 准备 SQL 数据库作为堆栈中的新服务了。现在我只使用 MariaDB 镜像中的一个副本构建。它具有配置数据库所需的环境变量,并安装了一个本地卷以在运行容器的机器上存储数据。在 django 设置中,我将 DB 后端更改为 mysql,将 DB 主机更改为数据库服务的名称。目前一切正常。

但是如果我想拥有更多 DB 引擎副本怎么办?我应该如何处理来自不同节点的存储数据?如果我使用现有配置,则存储在第一个节点上的数据将与存储在第二个节点上的数据不同。

这里有一个问题:我应该如何在Compose文件中配置音量以让所有任务使用相同的数据。

我读过一些博客和讨论,很多人说,docker swarm 不是处理 DB 的好的编排器,但这是真的吗?

当前撰写文件:

version: "3"

services:

    django-site:
            image: questionsite:maria
            ports:
                    - 8080:8080
            deploy:
                    replicas: 1
            depends_on:
                    - database
            networks:
                    - site

    database:
            image: mariadb:latest
            ports:
                    - 3306:3306
            networks:
                    - site
            deploy:
                    replicas: 1
            environment:
                    MYSQL_HOST: "database"
                    MYSQL_DATABASE: 'djangosite'
                    MYSQL_USER: 'xxxx'
                    MYSQL_PASSWORD: 'xxxxxx'
                    MYSQL_ROOT_PASSWORD: 'xxxxx'
                    MYSQL_ROOT_HOST: "%"
                    MYSQL_PORT: "3306"

            volumes:
                    - db_loc:/var/lib/mysql
networks:
            site:
                    external: true
volumes:
            db_loc:
                    driver: local

答案1

不能,对于这种类型的配置,您需要一个集群。数据库进程无法访问与另一个进程相同的数据(当然是在同一磁盘中),因为存在显式锁定以避免数据损坏。

这意味着你需要配置不是副本数据库服务,而是为每个需要的节点提供另一种服务。

数据库对于扩展是一个挑战,MySQL 有两个最常见的选项:InnoDB Cluster 或 Galera Cluster。由于您使用的是 MariaDB,因此 Galera Cluster 是最佳选择,但这是一个多主集群,大多数时候无法很好地扩展写入。

对于 Galera 集群,你需要启动第一个集群作为主要的带着旗帜--wsrep-新集群,然后是另外两个。然后重新启动第一个没有该标志的。另一个缺点是,您需要创建一个配置- 或卷,或具有自定义配置的您自己的映像 - 指定指向所有实例的“集群地址”。每个实例都有自己的卷。

使用 MySQL 8.0,您可以使用 InnoDB 集群,该集群可以是多主或单主。在编排器中配置起来更方便一些,例如一群或者Kubernetes

一个缺点一群缺少“负载平衡器”,对于这种类型的配置(三个服务,而不是副本),您需要创建一个 tcp 负载平衡器(如 HAProxy)或在应用程序驱动程序中配置负载平衡。这可以在Kubernetes

我在这里使用 PHP 创建了一个小功能示例,但没问题:

文件

docker-compose.yaml

version: '3.0'

services:
  app:
    image: alpine
    command: /bin/sh -c 'apk add php-cli php-mysqli && php -S 0.0.0.0:80 -t /app'
    ports:
    - 8080:80
    environment:
      DB_HOST: balancer
      DB_USER: root
      DB_PASS: dragonfly
    volumes:
    - ./app:/app
  balancer: 
    image: haproxy:alpine
    volumes:
    - ./etc/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
  db0:
    image: mariadb:10.3
    command: --wsrep-new-cluster --wsrep_node_address=db0
    #command: --wsrep_node_address=db0
    hostname: db0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: dragonfly
    volumes:
    - ./etc/galera.cnf:/etc/mysql/mariadb.conf.d/galera.cnf
#  db1:
#    image: mariadb:10.3
#    command: --wsrep_node_address=db1 --user=mysql
#    hostname: db1
#    restart: always
#    entrypoint: mysqld
#    environment:
#      MYSQL_ROOT_PASSWORD: dragonfly
#    volumes:
#    - ./etc/galera.cnf:/etc/mysql/mariadb.conf.d/galera.cnf
#  db2:
#    image: mariadb:10.3
#    command: --wsrep_node_address=db2 --user=mysql
#    hostname: db2
#    restart: always
#    entrypoint: mysqld
#    environment:
#      MYSQL_ROOT_PASSWORD: dragonfly
#    volumes:
#    - ./etc/galera.cnf:/etc/mysql/mariadb.conf.d/galera.cnf

haproxy配置文件

defaults
mode http
log global
retries 2
timeout connect 3000ms
timeout server 5000ms
timeout client 5000ms

frontend mysql
bind 0.0.0.0:3306
option tcplog
mode tcp
default_backend galera

backend galera
mode tcp
balance roundrobin
option tcp-check
server mariadb0 db0:3306 check fall 3 rise 2
server mariadb1 db1:3306 check fall 3 rise 2
server mariadb2 db2:3306 check fall 3 rise 2

galera.cnf

[galera]
wsrep_on=ON
wsrep_provider=/usr/lib/libgalera_smm.so
wsrep_cluster_name=dragonfly
wsrep_cluster_address=gcomm://db0:4567,db1:4567,db2:4567
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
wsrep_provider_options="pc.wait_prim_timeout=PT120S;evs.install_timeout=PT15S"
wsrep_sst_auth=root:dragonfly

索引.php

<?php

$mysql = new mysqli(getenv('DB_HOST'), getenv('DB_USER'), getenv('DB_PASS'));

if ($mysql->connect_errno) {
  echo "Error: {$mysql->connect_errno} - {$mysql->connect_error}";
  exit(1);
}

$res = $mysql->query('SELECT @@hostname');

while ($rs = $res->fetch_row())
  echo "<h1>{$rs[0]}</h1>";

第一步-主控

Compose 文件的大部分内容都已注释,应该在第一个主服务器启动之前一直如此。在 Galera Cluster 中,第一台机器(也只有第一台机器)应该从--wsrep-new-cluster

docker-compose up

平衡器将失败,只需忽略它。您可以使用选项-d分离进程,但最好查看日志。

第二步-其他大师

在上述命令看起来稳定后,编辑撰写文件,从 db1 和 db2 服务中删除所有注释,然后在另一个终端中执行 - 如果您不使用-d

docker-compose up -d

这里使用这个-d来分离进程,我们启动的第一个容器的日志就足够了。测试

为了测试这个小集群,您可以转到浏览器并打开 127.0.0.1:8080,每次刷新页面时,都会出现三个数据库主机名之一。

从终端你可以执行以下操作:

curl localhost:8080

相关内容