>  기사  >  CMS 튜토리얼  >  Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법

Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법

藏色散人
藏色散人앞으로
2021-06-08 15:29:332873검색

다음 튜토리얼 칼럼인 WordPress에서는 Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법을 소개합니다. 필요한 분들께 도움이 되길 바랍니다!

WordPress는 웹 콘텐츠 편집 및 게시를 위한 주류 플랫폼입니다. 이 튜토리얼에서는 Kubernetes를 사용하여 고가용성(HA) WordPress 배포를 구축하는 방법을 살펴보겠습니다.


WordPress는 WordPress PHP 서버와 사용자 정보, 게시물 및 웹 사이트 데이터를 저장하는 데 사용되는 데이터베이스라는 두 가지 주요 구성 요소로 구성됩니다. 내결함성을 유지하면서 전체 애플리케이션의 두 구성 요소를 모두 고가용성으로 만들어야 합니다.

하드웨어와 주소가 변경되면 고가용성 서비스를 실행하는 것이 어려울 수 있습니다. 유지 관리가 매우 어렵습니다. Kubernetes와 Kubernetes의 강력한 네트워킹 구성 요소를 사용하면 단일 IP 주소를 거의 입력하지 않고도 가용성이 높은 WordPress 사이트와 MySQL 데이터베이스를 배포할 수 있습니다.

이 튜토리얼에서는 Kubernetes에서 스토리지 클래스, 서비스, 구성 맵 및 컬렉션을 생성하는 방법, 고가용성 MySQL을 실행하는 방법, 고가용성 WordPress 클러스터를 데이터베이스 서비스에 마운트하는 방법을 보여 드리겠습니다. 아직 Kubernetes 클러스터가 없다면 Amazon, Google 또는 Azure에서 쉽게 찾아서 시작하거나 모든 서버에서 Rancher Kubernetes Engine(RKE)를 사용할 수 있습니다 Rancher Kubernetes Engine (RKE)

架构概述

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

该体系架构如下所示:

Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법

在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

아키텍처 개요이제 우리가 사용할 기술과 그 기능을 간략하게 소개하겠습니다.
WordPress 애플리케이션 파일 저장: GCE 영구 디스크 백업이 포함된 NFS 저장소
데이터베이스 클러스터: 패리티 포함 Proven xtrabackup for MySQL 애플리케이션 레벨: NFS 스토리지에 마운트된 WordPress DockerHub 이미지
로드 밸런싱 및 네트워킹: Kubernetes 기반 로드 밸런서 및 서비스 네트워크 🎜🎜아키텍처는 다음과 같습니다: 🎜 🎜Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법🎜 K8s에서 스토리지 클래스, 서비스 및 구성 매핑 생성 🎜Kubernetes에서 상태 세트는 포드 초기화 순서를 정의하는 방법을 제공합니다. 데이터 노드가 시작 시 이전 포드의 레코드를 복제할 수 있는 충분한 시간을 갖도록 상태 저장 MySQL 컬렉션을 사용합니다. MySQL 마스터가 다른 슬레이브 머신보다 먼저 시작되는 방식으로 이 상태 세트를 구성하므로, 규모 확장 시 클론이 마스터에서 슬레이브 머신으로 직접 전송될 수 있습니다. 🎜🎜먼저 필요에 따라 마스터-슬레이브 구성을 적용하려면 영구 볼륨 스토리지 클래스와 구성 맵을 생성해야 합니다. 우리는 데이터베이스의 데이터가 클러스터의 특정 포드에 연결되는 것을 방지하기 위해 영구 볼륨을 사용합니다. 이 접근 방식은 MySQL 호스트 포드가 손실된 경우 데이터베이스가 데이터를 손실하는 것을 방지합니다. 호스트 포드가 손실되면 xtrabackup을 사용하여 슬레이브 머신에 다시 연결하고 슬레이브 머신에서 호스트로 데이터를 복사할 수 있습니다. MySQL 복제는 호스트-슬레이브 복제를 담당하고 xtrabackup은 슬레이브-호스트 복제를 담당합니다. 🎜🎜영구 볼륨을 동적으로 할당하기 위해 GCE 영구 디스크를 사용하여 스토리지 클래스를 만듭니다. 그러나 Kubernetes는 영구 볼륨을 위한 다양한 스토리지 솔루션을 제공합니다. 🎜
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 🎜 클래스를 생성하고 <code>$ kubectl create -f Storage-class.yaml</code> 명령을 사용하여 배포합니다. 🎜🎜다음으로 MySQL 구성 파일에 설정된 일부 변수를 지정하는 configmap을 생성하겠습니다. 이러한 다양한 구성은 포드 자체에서 선택되지만 잠재적인 구성 변수를 관리하는 편리한 방법도 제공합니다. 🎜🎜<code>mysql-configmap.yaml</code>이라는 YAML 파일을 생성하여 다음과 같이 구성을 처리합니다. 🎜<pre class="brush:php;toolbar:false"># 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>    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</ip>
🎜 configmap을 생성하고 다음 명령을 사용합니다: $ kubectl create - f mysql-configmap.yaml
을 배포합니다. 🎜🎜다음으로 MySQL 포드가 서로 통신할 수 있도록 서비스를 설정하고, WordPress 포드가 mysql-services.yaml을 사용하여 MySQL과 통신할 수 있도록 하겠습니다. 그러면 MySQL 서비스에 대한 서비스 로드 밸런서도 시작됩니다. 🎜rrreee🎜이 서비스 선언을 통해 우리는 다중 쓰기, 다중 읽기 MySQL 인스턴스 클러스터를 구현하기 위한 기반을 마련했습니다. 각 WordPress 인스턴스가 데이터베이스에 쓸 수 있으므로 이 구성이 필요하므로 각 노드는 읽고 쓸 준비가 되어 있어야 합니다. 🎜🎜위 서비스를 생성하려면 $ kubectl create -f mysql-services.yaml 명령을 실행하세요. 🎜🎜이 시점에서 우리는 영구 디스크를 요청하는 모든 컨테이너에 영구 디스크를 전달하는 볼륨 선언 스토리지 클래스를 생성하고, configmap을 구성하고, MySQL 구성 파일에 일부 변수를 설정했으며, 네트워크 계층 서비스는 MySQL 서버에 대한 요청의 부하를 분산하도록 구성됩니다. 위 내용은 Stateful Set을 준비하기 위한 프레임워크일 뿐이며 실제로 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 <p>将该文件存为<code>mysql-statefulset.yaml</code>,输入<code>kubectl="" create="" -f="" mysql-statefulset.yaml</code>并让kubernetes部署你的数据库。<br>现在当你调用<code>$="" kubectl="" get="" pods</code>,你应该看到3个pods启动或者准备好,其中每个pod上都有两个容器。主节点pod表示为mysql-0,而附属的pods为<code>mysql-1</code>和<code>mysql-2</code>.让pods执行几分钟来确保<code>xtrabackup</code>服务在pod之间正确同步,然后进行wordpress的部署。<br>您可以检查单个容器的日志来确认没有错误消息抛出。 查看日志的命令为<code>$="" logs="" <container_name></container_name></code></p><p>主节点<code>xtrabackup</code>容器应显示来自附属的两个连接,并且日志中不应该出现任何错误。</p><h2>部署高可用的WordPress</h2><p>整个过程的最后一步是将我们的WordPress pods部署到集群上。为此我们希望为WordPress的服务和部署进行定义。</p><p>为了让WordPress实现高可用,我们希望每个容器运行时都是完全可替换的,这意味着我们可以终止一个,启动另一个而不需要对数据或服务可用性进行修改。我们也希望能够容忍至少一个容器的失误,有一个冗余的容器负责处理slack。</p><p>WordPress将重要的站点相关数据存储在应用程序目录<code>/var/www/html</code>中。对于要为同一站点提供服务的两个WordPress实例,该文件夹必须包含相同的数据。</p><p>当运行高可用WordPress时,我们需要在实例之间共享<code>/var/www/html</code>文件夹,因此我们定义一个NGS服务作为这些卷的挂载点。<br>下面是设置NFS服务的配置,我提供了纯英文的版本:</p><p><img src="https://img.php.cn/upload/image/456/243/673/1623137239811988.png" title="1623137239811988.png" alt="Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법"></p><p><img src="https://img.php.cn/upload/image/229/961/277/1623137243449231.png" title="1623137243449231.png" alt="Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법"></p><p><img src="https://img.php.cn/upload/image/737/299/982/1623137248223155.png" title="1623137248223155.png" alt="Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법"></p><p><img src="https://img.php.cn/upload/image/282/959/213/1623137253150095.png" title="1623137253150095.png" alt="Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법"></p><p>使用指令<code>$ kubectl create -f nfs.yaml</code>部署NFS服务。现在,我们需要运行<code>$ kubectl describe services nfs-server</code>获得IP地址,这在后面会用到。</p><p>注意:将来,我们可以使用服务名称讲这些绑定在一起,但现在你需要对IP地址进行硬编码。</p><pre class="brush:php;toolbar:false"># 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>    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</ip>

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

WordPress 인스턴스를 배포하려면 $ kubectl create -f wordpress.yaml 명령을 사용하세요. 기본 배포는 하나의 WordPress 인스턴스만 실행합니다. $ kubectl scale --replicas=<number of="" replicas=""></number>$ kubectl create -f wordpress.yaml部署WordPress实例。默认部署只会运行一个WordPress实例,可以使用指令$ kubectl scale --replicas=<number of="" replicas=""></number>
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/htmldeployment/wordpress WordPress 인스턴스 수를 확장합니다.

WordPress 서비스 로드 밸런서의 주소를 얻으려면 $ kubectl get services wordpress

를 입력하여 WordPress로 이동하고 결과에서 EXTERNAL-IP 필드를 가져와야 합니다.

복원력 테스트

자, 이제 서비스를 배포했으므로 서비스를 분해하고 고가용성 아키텍처가 혼란을 어떻게 처리하는지 살펴보겠습니다. 이 배포에서 유일하게 남아 있는 단일 실패 지점은 NFS 서비스입니다(이유는 문서 끝 부분의 결론에 요약되어 있습니다). 애플리케이션이 어떻게 응답하는지 확인하기 위해 다른 서비스를 테스트할 수 있어야 합니다. 이제 WordPress 서비스의 복제본 3개와 MySQL 서비스의 마스터 노드 및 슬레이브 노드 2개를 시작했습니다.

먼저, 다른 노드를 종료하고 WordPress 노드 하나만 남겨두고 애플리케이션이 어떻게 반응하는지 살펴보겠습니다. : $ kubectl scale --replicas=1 배포/wordpress 이제 WordPress 배포를 확인해야 합니다. 감소했습니다. $ kubectl get pods WordPress Pod 실행이 1/1로 변경된 것을 확인할 수 있습니다.


워드프레스 서비스 IP를 클릭하면 이전과 동일한 사이트와 데이터베이스가 표시됩니다. 복구를 확장하려면 $ kubectl scale --replicas=3 배포/wordpress를 사용하면 됩니다. 다시, 패킷이 3개의 인스턴스에 남아 있는 것을 볼 수 있습니다.

다음은 MySQL 상태 저장 세트에 대한 테스트입니다. $ kubectl scale statefulsets mysql --replicas=1 명령을 사용하여 두 개의 복제본이 손실된 것을 볼 수 있습니다. 이 시점에서 마스터 노드가 손실되면 보유하고 있는 데이터는 GCE 영구 디스크에 저장됩니다. 그러나 데이터는 디스크에서 수동으로 복원해야 합니다. 🎜🎜MySQL 노드 3개가 모두 다운되면 새 노드가 올라올 때 복제가 불가능합니다. 하지만 마스터 노드에 장애가 발생하면 새 마스터 노드가 자동으로 시작되고 xtrabackup을 통해 슬레이브 노드의 데이터가 재구성됩니다. 따라서 프로덕션 데이터베이스를 실행할 때 복제 인수를 3 미만으로 실행하는 것은 권장하지 않습니다. 마지막 단락에서는 Kubernetes가 실제로 상태용으로 설계되지 않았기 때문에 상태 저장 데이터를 위한 더 나은 솔루션이 무엇인지 이야기하겠습니다. 🎜

결론 및 권장 사항

🎜지금까지 Kubernetes에서 가용성이 뛰어난 WordPress 및 MySQL 설치를 빌드하고 배포하는 작업을 완료했습니다! 🎜🎜그러나 그러한 결과에도 불구하고 귀하의 연구 여정은 아직 끝나지 않았을 수도 있습니다. 눈치채지 못한 경우를 대비해 설치에는 여전히 단일 실패 지점이 있습니다. NFS 서버는 WordPress 포드 간에 /var/www/html 디렉터리를 공유합니다. 이 서비스가 실행되고 있지 않으면 이를 사용하는 포드에서 html 디렉터리가 누락되기 때문에 단일 실패 지점을 나타냅니다. 튜토리얼에서는 프로덕션 환경에서 사용할 수 있는 매우 안정적인 서버 이미지를 선택했지만 실제 프로덕션 배포에서는 GlusterFS를 사용하여 WordPress에서 공유하는 디렉터리에서 다중 읽기 및 다중 쓰기를 활성화하는 것을 고려할 수 있습니다. 사례. 🎜🎜이 프로세스에는 실제로 Kubernetes로 구축되지 않은 Kubernetes에서 분산 스토리지 클러스터를 실행하는 작업이 포함되므로 잘 작동하지만 장기 배포에는 적합하지 않습니다. 🎜🎜데이터베이스의 경우 개인적으로 관리형 관계형 데이터베이스 서비스를 사용하여 MySQL 인스턴스를 호스팅하는 것이 좋습니다. Google의 CloudSQL이든 AWS의 RDS이든 더 합리적인 가격에 고가용성과 중복 처리를 제공하고, 그럴 필요가 없기 때문입니다. 데이터 무결성에 대해 걱정하세요. Kuberntes는 상태 저장 애플리케이션을 중심으로 설계되지 않았으며 여기에 구축된 모든 상태는 나중에 고려하는 것입니다. 현재 데이터베이스 서비스를 선택할 때 필요한 보증을 제공할 수 있는 다양한 솔루션이 있습니다. 🎜🎜즉, 위에 설명된 내용은 Kubernetes 튜토리얼과 웹에서 찾은 예제를 통해 관련성이 높고 현실적인 Kubernetes 예제를 생성하고 Kubernetes 1.8.x의 모든 새로운 기능을 포함하는 이상적인 프로세스입니다. 🎜🎜이 가이드를 통해 WordPress 및 MySQL을 배포할 때 놀라운 경험을 할 수 있기를 바라며 모든 것이 정상적으로 실행되기를 바랍니다. 🎜🎜🎜

위 내용은 Kubernetes에서 고가용성 WordPress 및 MySQL을 실행하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제