目录
架构概述
在K8s中创建存储类、服务和配置映射
配置有状态集的MySQL
部署高可用的WordPress
弹性测试
结论和建议
首页 CMS教程 &#&按 如何在Kubernetes上运行高可用的WordPress和MySQL

如何在Kubernetes上运行高可用的WordPress和MySQL

Jun 08, 2021 pm 03:29 PM
wordpress

下面由WordPress教程栏目给大家介绍在Kubernetes上运行高可用的WordPress和MySQL,希望对需要的朋友有所帮助!

WordPress是用于编辑和发布Web内容的主流平台。在本教程中,我将逐步介绍如何使用Kubernetes来构建高可用性(HA)WordPress部署。


WordPress由两个主要组件组成:WordPress PHP服务器和用于存储用户信息、帖子和网站数据的数据库。我们需要让整个应用程序中这两个组件在高可用的同时都具备容错能力。

在硬件和地址发生变化的时候,运行高可用服务可能会很困难:非常难维护。借助Kubernetes以及其强大的网络组件,我们可以部署高可用的WordPress站点和MySQL数据库,而无需(几乎无需)输入单个IP地址。

在本教程中,我将向你展示如何在Kubernetes中创建存储类、服务、配置映射和集合,如何运行高可用MySQL,以及如何将高可用WordPress集群挂载到数据库服务上。如果你还没有Kubernetes集群,你可以在Amazon、Google或者Azure上轻松找到并且启动它们,或者在任意的服务器上使用Rancher Kubernetes Engine (RKE)

架构概述

现在我来简要介绍一下我们将要使用的技术及其功能:
WordPress应用程序文件的存储:具有GCE持久性磁盘备份的NFS存储
数据库集群:带有用于奇偶校验的xtrabackup的MySQL
应用程序级别:挂载到NFS存储的WordPress DockerHub映像
负载均衡和网络:基于Kubernetes的负载均衡器和服务网络

该体系架构如下所示:

7428e277eb790f9c1ee6446eccb4faf.png

在K8s中创建存储类、服务和配置映射

在Kubernetes中,状态集提供了一种定义pod初始化顺序的方法。我们将使用一个有状态的MySQL集合,因为它能确保我们的数据节点有足够的时间在启动时复制先前pods中的记录。我们配置这个状态集的方式可以让MySQL主机在其他附属机器之前先启动,因此当我们扩展时,可以直接从主机将克隆发送到附属机器上。

首先,我们需要创建一个持久卷存储类和配置映射,以根据需要应用主从配置。我们使用持久卷,避免数据库中的数据受限于集群中任何特定的pods。这种方式可以避免数据库在MySQL主机pod丢失的情况下丢失数据,当主机pod丢失时,它可以重新连接到带xtrabackup的附属机器,并将数据从附属机器拷贝到主机中。MySQL的复制负责主机-附属的复制,而xtrabackup负责附属-主机的复制。

要动态分配持久卷,我们使用GCE持久磁盘创建存储类。不过,Kubernetes提供了各种持久性卷的存储方案:

# storage-class.yamlkind: StorageClassapiVersion: storage.k8s.io/v1metadata:
 name: slowprovisioner: kubernetes.io/gce-pdparameters:
 type: pd-standard  zone: us-central1-a
登录后复制

创建类,并且使用指令:$ kubectl create -f storage-class.yaml部署它。

接下来,我们将创建configmap,它指定了一些在MySQL配置文件中设置的变量。这些不同的配置由pod本身选择有关,但它们也为我们提供了一种便捷的方式来管理潜在的配置变量。

创建名为mysql-configmap.yaml的YAML文件来处理配置,如下:

# mysql-configmap.yamlapiVersion: v1kind: ConfigMapmetadata:
 name: mysql  labels:
   app: mysqldata:
 master.cnf: |    # Apply this config only on the master.
   [mysqld]
   log-bin
   skip-host-cache
   skip-name-resolve  slave.cnf: |    # Apply this config only on slaves.
   [mysqld]
   skip-host-cache
   skip-name-resolve
登录后复制

创建configmap并使用指令:$ kubectl create -f mysql-configmap.yaml
来部署它。

接下来我们要设置服务以便MySQL pods可以互相通信,并且我们的WordPress pod可以使用mysql-services.yaml与MySQL通信。这也为MySQL服务启动了服务负载均衡器。

# mysql-services.yaml# Headless service for stable DNS entries of StatefulSet members.apiVersion: v1kind: Servicemetadata:
 name: mysql  labels:
   app: mysqlspec:
 ports:
 - name: mysql    port: 3306  clusterIP: None  selector:
   app: mysql
登录后复制

通过此服务声明,我们就为实现一个多写入、多读取的MySQL实例集群奠定了基础。这种配置是必要的,每个WordPress实例都可能写入数据库,所以每个节点都必须准备好读写。

执行命令 $ kubectl create -f mysql-services.yaml来创建上述的服务。

到这为止,我们创建了卷声明存储类,它将持久磁盘交给所有请求它们的容器,我们配置了configmap,在MySQL配置文件中设置了一些变量,并且我们配置了一个网络层服务,负责对MySQL服务器请求的负载均衡。上面说的这些只是准备有状态集的框架, MySQL服务器实际在哪里运行,我们接下来将继续探讨。

配置有状态集的MySQL

本节中,我们将编写一个YAML配置文件应用于使用了状态集的MySQL实例。
我们先定义我们的状态集:
1, 创建三个pods并将它们注册到MySQL服务上。
2, 按照下列模版定义每个pod:
♢ 为主机MySQL服务器创建初始化容器,命名为init-mysql.
♢  给这个容器使用mysql:5.7镜像
♢  运行一个bash脚本来启动xtrabackup
♢  为配置文件和configmap挂载两个新卷

3, 为主机MySQL服务器创建初始化容器,命名为clone-mysql.
♢  为该容器使用Google Cloud Registry的xtrabackup:1.0镜像
♢ 运行bash脚本来克隆上一个同级的现有xtrabackups
♢  为数据和配置文件挂在两个新卷
♢  该容器有效地托管克隆的数据,便于新的附属容器可以获取它

4, 为附属MySQL服务器创建基本容器
♢  创建一个MySQL附属容器,配置它连接到MySQL主机
♢  创建附属xtrabackup容器,配置它连接到xtrabackup主机

5, 创建一个卷声明模板来描述每个卷,每个卷是一个10GB的持久磁盘
下面的配置文件定义了MySQL集群的主节点和附属节点的行为,提供了运行附属客户端的bash配置,并确保在克隆之前主节点能够正常运行。附属节点和主节点分别获得他们自己的10GB卷,这是他们在我们之前定义的持久卷存储类中请求的。

apiVersion: apps/v1beta1kind: StatefulSetmetadata:
 name: mysqlspec:
 selector:
   matchLabels:
     app: mysql  serviceName: mysql  replicas: 3  template:
   metadata:
     labels:
       app: mysql    spec:
     initContainers:
     - name: init-mysql        image: mysql:5.7        command:
       - bash        - "-c"
       - |
         set -ex          # Generate mysql server-id from pod ordinal index.
         [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
         ordinal=${BASH_REMATCH[1]}
         echo [mysqld] > /mnt/conf.d/server-id.cnf          # Add an offset to avoid reserved server-id=0 value.
         echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf          # Copy appropriate conf.d files from config-map to emptyDir.
         if [[ $ordinal -eq 0 ]]; then
           cp /mnt/config-map/master.cnf /mnt/conf.d/
         else
           cp /mnt/config-map/slave.cnf /mnt/conf.d/
         fi        volumeMounts:
       - name: conf          mountPath: /mnt/conf.d        - name: config-map          mountPath: /mnt/config-map      - name: clone-mysql        image: gcr.io/google-samples/xtrabackup:1.0        command:
       - bash        - "-c"
       - |
         set -ex          # Skip the clone if data already exists.
         [[ -d /var/lib/mysql/mysql ]] && exit 0          # Skip the clone on master (ordinal index 0).
         [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
         ordinal=${BASH_REMATCH[1]}
         [[ $ordinal -eq 0 ]] && exit 0          # Clone data from previous peer.
         ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql          # Prepare the backup.
         xtrabackup --prepare --target-dir=/var/lib/mysql        volumeMounts:
       - name: data          mountPath: /var/lib/mysql          subPath: mysql        - name: conf          mountPath: /etc/mysql/conf.d      containers:
     - name: mysql        image: mysql:5.7        env:
       - name: MYSQL_ALLOW_EMPTY_PASSWORD          value: "1"
       ports:
       - name: mysql          containerPort: 3306        volumeMounts:
       - name: data          mountPath: /var/lib/mysql          subPath: mysql        - name: conf          mountPath: /etc/mysql/conf.d        resources:
         requests:
           cpu: 500m            memory: 1Gi        livenessProbe:
         exec:
           command: ["mysqladmin", "ping"]
         initialDelaySeconds: 30          periodSeconds: 10          timeoutSeconds: 5        readinessProbe:
         exec:
           # Check we can execute queries over TCP (skip-networking is off).
           command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
         initialDelaySeconds: 5          periodSeconds: 2          timeoutSeconds: 1      - name: xtrabackup        image: gcr.io/google-samples/xtrabackup:1.0        ports:
       - name: xtrabackup          containerPort: 3307        command:
       - bash        - "-c"
       - |
         set -ex
         cd /var/lib/mysql          # Determine binlog position of cloned data, if any.
         if [[ -f xtrabackup_slave_info ]]; then            # XtraBackup already generated a partial "CHANGE MASTER TO" query
           # because we're cloning from an existing slave.
           mv xtrabackup_slave_info change_master_to.sql.in            # Ignore xtrabackup_binlog_info in this case (it's useless).
           rm -f xtrabackup_binlog_info
         elif [[ -f xtrabackup_binlog_info ]]; then            # We're cloning directly from master. Parse binlog position.
           [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
           rm xtrabackup_binlog_info
           echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\                  MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
         fi          # Check if we need to complete a clone by starting replication.
         if [[ -f change_master_to.sql.in ]]; then
           echo "Waiting for mysqld to be ready (accepting connections)"
           until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done

           echo "Initializing replication from clone position"
           # In case of container restart, attempt this at-most-once.
           mv change_master_to.sql.in change_master_to.sql.orig
           mysql -h 127.0.0.1 <<EOF
         $(<change_master_to.sql.orig),
           MASTER_HOST=&#39;mysql-0.mysql&#39;,
           MASTER_USER=&#39;root&#39;,
           MASTER_PASSWORD=&#39;&#39;,
           MASTER_CONNECT_RETRY=10;
         START SLAVE;
         EOF
         fi          # Start a server to send backups when requested by peers.
         exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \            "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
       volumeMounts:
       - name: data          mountPath: /var/lib/mysql          subPath: mysql
       - name: conf          mountPath: /etc/mysql/conf.d        resources:
         requests:
           cpu: 100m            memory: 100Mi      volumes:
     - name: conf        emptyDir: {}
     - name: config-map        configMap:
         name: mysql  volumeClaimTemplates:
 - metadata:
     name: data    spec:
     accessModes: ["ReadWriteOnce"]
     resources:
       requests:
         storage: 10Gi
登录后复制

将该文件存为mysql-statefulset.yaml,输入kubectl="" create="" -f="" mysql-statefulset.yaml并让kubernetes部署你的数据库。
现在当你调用$="" kubectl="" get="" pods,你应该看到3个pods启动或者准备好,其中每个pod上都有两个容器。主节点pod表示为mysql-0,而附属的pods为mysql-1mysql-2.让pods执行几分钟来确保xtrabackup服务在pod之间正确同步,然后进行wordpress的部署。
您可以检查单个容器的日志来确认没有错误消息抛出。 查看日志的命令为$="" logs="" <container_name=""><p>主节点<code>xtrabackup容器应显示来自附属的两个连接,并且日志中不应该出现任何错误。

部署高可用的WordPress

整个过程的最后一步是将我们的WordPress pods部署到集群上。为此我们希望为WordPress的服务和部署进行定义。

为了让WordPress实现高可用,我们希望每个容器运行时都是完全可替换的,这意味着我们可以终止一个,启动另一个而不需要对数据或服务可用性进行修改。我们也希望能够容忍至少一个容器的失误,有一个冗余的容器负责处理slack。

WordPress将重要的站点相关数据存储在应用程序目录/var/www/html中。对于要为同一站点提供服务的两个WordPress实例,该文件夹必须包含相同的数据。

当运行高可用WordPress时,我们需要在实例之间共享/var/www/html文件夹,因此我们定义一个NGS服务作为这些卷的挂载点。
下面是设置NFS服务的配置,我提供了纯英文的版本:

93d34768a751e24a088b12f9a1ed2f8.png

e86e43b49585c73b08fed132723b229.png

e2d53a02b91c92817532f6d2879e9eb.png

c2ff0b7d440911bfac020374d97b228.png

使用指令$ kubectl create -f nfs.yaml部署NFS服务。现在,我们需要运行$ kubectl describe services nfs-server获得IP地址,这在后面会用到。

注意:将来,我们可以使用服务名称讲这些绑定在一起,但现在你需要对IP地址进行硬编码。

# wordpress.yamlapiVersion: v1kind: Servicemetadata:
 name: wordpress  labels:
   app: wordpressspec:
 ports:
   - port: 80  selector:
   app: wordpress    tier: frontend  type: LoadBalancer---apiVersion: v1kind: PersistentVolumemetadata:
 name: nfsspec:
 capacity:
   storage: 20G  accessModes:
   - ReadWriteMany  nfs:
   # FIXME: use the right IP
   server: <ip of="" the="" nfs="" service="">    path: "/"---apiVersion: v1kind: PersistentVolumeClaimmetadata:
 name: nfsspec:
 accessModes:
   - ReadWriteMany  storageClassName: ""
 resources:
   requests:
     storage: 20G---apiVersion: apps/v1beta1 # for versions before 1.8.0 use apps/v1beta1kind: Deploymentmetadata:
 name: wordpress  labels:
   app: wordpressspec:
 selector:
   matchLabels:
     app: wordpress      tier: frontend  strategy:
   type: Recreate  template:
   metadata:
     labels:
       app: wordpress        tier: frontend    spec:
     containers:
     - image: wordpress:4.9-apache        name: wordpress        env:
       - name: WORDPRESS_DB_HOST          value: mysql        - name: WORDPRESS_DB_PASSWORD          value: ""
       ports:
       - containerPort: 80          name: wordpress        volumeMounts:
       - name: wordpress-persistent-storage          mountPath: /var/www/html      volumes:
     - name: wordpress-persistent-storage        persistentVolumeClaim:
           claimName: nfs
登录后复制

我们现在创建了一个持久卷声明,和我们之前创建的NFS服务建立映射,然后将卷附加到WordPress pod上,即/var/www/html根目录,这也是WordPress安装的地方。这里保留了集群中WordPress pods的所有安装和环境。有了这些配置,我们就可以对任何WordPress节点进行启动和拆除,而数据能够留下来。因为NFS服务需要不断使用物理卷,该卷将保留下来,并且不会被回收或错误分配。

使用指令$ kubectl create -f wordpress.yaml部署WordPress实例。默认部署只会运行一个WordPress实例,可以使用指令$ kubectl scale --replicas=<number of="" replicas="">
deployment/wordpress扩展WordPress实例数量。

要获得WordPress服务负载均衡器的地址,你需要输入$ kubectl get services wordpress
并从结果中获取EXTERNAL-IP字段来导航到WordPress。

弹性测试

OK,现在我们已经部署好了服务,那我们来拆除一下它们,看看我们的高可用架构如何处理这些混乱。在这种部署方式中,唯一剩下的单点故障就是NFS服务(原因总结在文末结论中)。你应该能够测试其他任何的服务来了解应用程序是如何响应的。现在我已经启动了WordPress服务的三个副本,以及MySQL服务中的一个主两个附属节点。

首先,我们先kill掉其他而只留下一个WordPress节点,来看看应用如何响应:$ kubectl scale --replicas=1 deployment/wordpress现在我们应该看到WordPress部署的pod数量有所下降。$ kubectl get pods应该能看到WordPress pods的运行变成了1/1。

点击WordPress服务IP,我们将看到与之前一样的站点和数据库。如果要扩展复原,可以使用$ kubectl scale --replicas=3 deployment/wordpress再一次,我们可以看到数据包留在了三个实例中。

下面测试MySQL的状态集,我们使用指令缩小备份的数量:$ kubectl scale statefulsets mysql --replicas=1我们会看到两个附属从该实例中丢失,如果主节点在此时丢失,它所保存的数据将保存在GCE持久磁盘上。不过就必须手动从磁盘恢复数据。

如果所有三个MySQL节点都关闭了,当新节点出现时就无法复制。但是,如果一个主节点发生故障,一个新的主节点就会自动启动,并且通过xtrabackup重新配置来自附属节点的数据。因此,在运行生产数据库时,我不建议以小于3的复制系数来运行。在结论段中,我们会谈谈针对有状态数据有什么更好的解决方案,因为Kubernetes并非真正是为状态设计的。

结论和建议

到现在为止,你已经完成了在Kubernetes构建并部署高可用WordPress和MySQL的安装!

不过尽管取得了这样的效果,你的研究之旅可能还远没有结束。可能你还没注意到,我们的安装仍然存在着单点故障:NFS服务器在WordPress pods之间共享/var/www/html目录。这项服务代表了单点故障,因为如果它没有运行,在使用它的pods上html目录就会丢失。教程中我们为服务器选择了非常稳定的镜像,可以在生产环境中使用,但对于真正的生产部署,你可以考虑使用GlusterFS对WordPress实例共享的目录开启多读多写。

这个过程涉及在Kubernetes上运行分布式存储集群,实际上这不是Kubernetes构建的,因此尽管它运行良好,但不是长期部署的理想选择。

对于数据库,我个人建议使用托管的关系数据库服务来托管MySQL实例,因为无论是Google的CloudSQL还是AWS的RDS,它们都以更合理的价格提供高可用和冗余处理,并且不需担心数据的完整性。Kuberntes并不是围绕有状态的应用程序设计的,任何建立在其中的状态更多都是事后考虑。目前有大量的解决方案可以在选择数据库服务时提供所需的保证。

也就是说,上面介绍的是一种理想的流程,由Kubernetes教程、web中找到的例子创建一个有关联的现实的Kubernetes例子,并且包含了Kubernetes 1.8.x中所有的新特性。

我希望通过这份指南,你能在部署WordPress和MySQL时获得一些惊喜的体验,当然,更希望你的运行一切正常。

以上是如何在Kubernetes上运行高可用的WordPress和MySQL的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP 与 Flutter 的比较:移动端开发的最佳选择 PHP 与 Flutter 的比较:移动端开发的最佳选择 May 06, 2024 pm 10:45 PM

PHP和Flutter是移动端开发的流行技术。Flutter胜在跨平台能力、性能和用户界面,适合需要高性能、跨平台和自定义UI的应用程序。PHP则适用于性能较低、不跨平台的服务器端应用程序。

wordpress如何修改页面宽度 wordpress如何修改页面宽度 Apr 16, 2024 am 01:03 AM

通过编辑 style.css 文件,您可以轻松修改 WordPress 页面宽度:编辑 style.css 文件,添加 .site-content { max-width: [您的首选宽度]; }。修改 [您的首选宽度] 以设置页面宽度。保存更改并清除缓存(可选)。

wordpress文章在哪个文件夹 wordpress文章在哪个文件夹 Apr 16, 2024 am 10:29 AM

WordPress 文章存储在 /wp-content/uploads 文件夹中。该文件夹使用子文件夹对不同类型的上传进行分类,包括按年、月和文章 ID 组织的文章。文章文件以纯文本格式 (.txt) 存储,文件名通常包含其 ID 和标题。

wordpress如何做产品页 wordpress如何做产品页 Apr 16, 2024 am 12:39 AM

在 WordPress 中创建产品页面:1. 创建产品(名称、描述、图片);2. 自定义页面模板(添加标题、描述、图片、按钮);3. 输入产品信息(库存、尺寸、重量);4. 创建变体(不同颜色、尺寸);5. 设置可见性(公开或隐藏);6. 启用/禁用评论;7. 预览并发布页面。

wordpress模板文件在哪 wordpress模板文件在哪 Apr 16, 2024 am 11:00 AM

WordPress 模板文件位于 /wp-content/themes/[主题名称]/ 目录。它们用于决定网站的外观和功能,包括页眉(header.php)、页脚(footer.php)、主模板(index.php)、单个文章(single.php)、页面(page.php)、存档(archive.php)、类别(category.php)、标签(tag.php)、搜索(search.php)和 404 错误页面(404.php)。通过编辑和修改这些文件,可以自定义 WordPress 网站的外

wordpress如何搜索作者 wordpress如何搜索作者 Apr 16, 2024 am 01:18 AM

在 WordPress 中搜索作者:1. 登录管理面板后,导航到“文章”或“页面”,使用搜索栏输入作者姓名,在“过滤器”中选择“作者”。2. 其他技巧:使用通配符扩大搜索范围,使用运算符组合条件,或输入作者 ID 以搜索文章。

wordpress哪个版本稳定 wordpress哪个版本稳定 Apr 16, 2024 am 10:54 AM

最稳定的 WordPress 版本是最新版本,因为它包含最新的安全补丁、增强性能并引入新特性和改进。为了更新到最新版本,请登录 WordPress 仪表盘,转到“更新”页面并单击“立即更新”。

wordpress需要备案吗 wordpress需要备案吗 Apr 16, 2024 pm 12:07 PM

WordPress需要备案。根据我国《互联网安全管理办法》,在境内提供互联网信息服务的网站需向所在地省级互联网信息办公室备案,包括WordPress在内。备案流程包括选择服务商、准备信息、提交申请、审核公示、获取备案号等步骤。备案好处有合法合规、提升可信度、满足接入要求、确保正常访问等。备案信息需真实有效,备案后需定期更新。

See all articles