WordPress は、WordPress PHP サーバーと、ユーザー情報、投稿、Web サイト データの保存に使用されるデータベースという 2 つの主要コンポーネントで構成されます。アプリケーション全体の両方のコンポーネントを同時に高可用性とフォールトトレラントにする必要があります。 ハードウェアやアドレスが変更されると、高可用性サービスの実行が困難になる可能性があり、保守が非常に困難になります。 Kubernetes とその強力なネットワーク コンポーネントを使用すると、(ほぼ) 単一の IP アドレスを入力することなく、可用性の高い WordPress サイトと MySQL データベースを展開できます。 このチュートリアルでは、Kubernetes でストレージ クラス、サービス、構成マップ、コレクションを作成する方法、高可用性 MySQL を実行する方法、高可用性 WordPress クラスターをデータベース サービスにマウントする方法を説明します。まだ Kubernetes クラスターをお持ちでない場合は、Amazon、Google、または Azure で簡単に検索して開始するか、
Rancher Kubernetes Engine (RKE)
## 次に、使用するテクノロジーとその機能を簡単に紹介します。
WordPress アプリケーション ファイルのストレージ: GCE 永続ディスク バックアップを備えた NFS ストレージ データベース クラスター: パリティ用にテスト済みの xtrabackup MySQL 用
アプリケーション レベル: NFS ストレージにマウントされた WordPress DockerHub イメージ
ロード バランシングとネットワーキング: Kubernetes ベースのロード バランサーとサービス ネットワーク
アーキテクチャは以下に示されています :
K8s でのストレージ クラス、サービス、構成マッピングの作成
Kubernetes では、状態セットによってポッドが初期化される順序を定義する方法が提供されます。ステートフルな MySQL コレクションを使用します。これにより、データ ノードが起動時に以前のポッドからレコードをレプリケートするのに十分な時間を確保できるようになります。この状態セットは、MySQL マスターが他のスレーブ マシンよりも前に起動するように構成されているため、スケールアウトするときにマスターからスレーブ マシンにクローンを直接送信できます。
まず、必要に応じてマスター/スレーブ構成を適用するために、永続ボリューム ストレージ クラスと構成マッピングを作成する必要があります。永続ボリュームを使用して、データベース内のデータがクラスター内の特定のポッドに関連付けられるのを防ぎます。このアプローチにより、MySQL ホスト ポッドが失われた場合にデータベースがデータを失うことがなくなり、ホスト ポッドが失われた場合、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 を使用してデプロイします。 次に、MySQL 構成ファイルに設定されたいくつかの変数を指定する構成マップを作成します。これらのさまざまな構成はポッド自体によって選択されますが、潜在的な構成変数を管理する便利な方法も提供します。
次のように、構成を処理するために
mysql-configmap.yaml という名前の YAML ファイルを作成します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"># 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</pre><div class="contentsignin">ログイン後にコピー</div></div>
を作成し、ディレクティブを使用します。 $ kubectl create -f mysql-configmap.yaml
を実行してデプロイします。
次に、MySQL ポッドが相互に通信できるようにサービスを設定し、WordPress ポッドが
を使用して MySQL と通信できるようにします。これにより、MySQL サービスのサービス ロード バランサも開始されます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"># 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</pre><div class="contentsignin">ログイン後にコピー</div></div>
このサービス宣言により、マルチ書き込み、マルチリードの MySQL インスタンス クラスターを実装するための基礎を築きました。各 WordPress インスタンスがデータベースに書き込む可能性があるため、この設定が必要です。そのため、各ノードは読み取りと書き込みの準備ができている必要があります。
コマンド
$ kubectl create -f mysql-services.yaml を実行して、上記のサービスを作成します。 これまでのところ、永続ディスクを要求するすべてのコンテナに永続ディスクを渡すボリューム宣言ストレージ クラスを作成し、
を構成し、MySQL 構成ファイルにいくつかの変数を設定しました。そして、MySQL サーバーへのリクエストの負荷分散を担当するネットワーク層サービスを構成しました。上記はステートフル セットを準備するためのフレームワークにすぎませんが、MySQL サーバーが実際にどこで実行されるかを引き続き調査していきます。 <h2>配置有状态集的MySQL</h2>
<p>本节中,我们将编写一个YAML配置文件应用于使用了状态集的MySQL实例。<br>我们先定义我们的状态集:<br>1, 创建三个pods并将它们注册到MySQL服务上。<br>2, 按照下列模版定义每个pod:<br>♢ 为主机MySQL服务器创建初始化容器,命名为<code>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服务需要不断使用物理卷,该卷将保留下来,并且不会被回收或错误分配。
コマンドを使用します$ kubectl create -f wordpress.yaml
WordPress インスタンスをデプロイします。デフォルトのデプロイでは WordPress インスタンスが 1 つだけ実行されます。コマンド $ kubectlscale --replicas=<number of="" plicas=""></number>
deployment/wordpress を使用できます。
WordPress インスタンスの数をスケールします。
WordPress サービス ロード バランサーのアドレスを取得するには、「$ kubectl get services wordpress
」と入力して WordPress に移動し、結果から EXTERNAL-IP フィールドを取得する必要があります。
耐障害性テスト
OK、サービスをデプロイしたので、サービスを分解して、高可用性アーキテクチャが混乱にどのように対処するかを見てみましょう。この展開では、唯一残っている単一障害点は NFS サービスです (理由は記事の最後にまとめた結論にあります)。他のサービスをテストして、アプリケーションがどのように応答するかを確認できるはずです。これで、WordPress サービスの 3 つのレプリカと、MySQL サービスのマスター ノードと 2 つのスレーブ ノードが開始されました。
まず、他のノードを強制終了し、WordPress ノードを 1 つだけ残して、アプリケーションがどのように応答するかを確認しましょう。:$ kubectlscale --replicas=1deployment/wordpress
これで、ポッドの数が表示されるはずです。 WordPress によるデプロイは減少しました。 $ kubectl get pods
WordPress ポッドの実行が 1/1 に変更されたことがわかります。
WordPress サービス IP をクリックすると、以前と同じサイトとデータベースが表示されます。リカバリをスケールしたい場合は、$ kubectlscale --replicas=3deployment/wordpress
を使用できます。もう一度、パケットが 3 つのインスタンスに残っていることがわかります。
MySQL のステートフル セットをテストするには、次のコマンドを使用してバックアップの数を減らします: $ kubectlscale statefulsets mysql --replicas=1
このインスタンスから 2 つのレプリカが失われていることがわかります。 , この時点でマスター ノードが失われた場合、マスター ノードが保持しているデータは GCE 永続ディスクに保存されます。ただし、データはディスクから手動で復元する必要があります。
3 つの MySQL ノードすべてがダウンしている場合、新しいノードが起動したときにレプリケーションを行うことはできません。ただし、マスター ノードに障害が発生した場合は、新しいマスター ノードが自動的に起動され、スレーブ ノードからのデータが xtrabackup を通じて再構成されます。したがって、実稼働データベースを実行する場合、3 未満のレプリケーション係数で実行することはお勧めしません。最後の段落では、Kubernetes は実際には状態向けに設計されていないため、ステートフル データに適したソリューションとは何かについて説明します。
結論と推奨事項
ここまでで、可用性の高い WordPress と MySQL インストールの Kubernetes 上での構築とデプロイが完了しました。
しかし、このような結果にもかかわらず、あなたの研究の旅はまだ終わっていないかもしれません。お気づきでないかもしれませんが、私たちのインストールにはまだ単一障害点があります。それは、NFS サーバーが WordPress ポッド間で /var/www/html
ディレクトリを共有していることです。このサービスが実行されていない場合、このサービスを使用するポッド上に html ディレクトリが存在しないため、単一障害点となります。チュートリアルでは、運用環境で使用できるサーバー用の非常に安定したイメージを選択しましたが、実際の運用環境では、GlusterFS を使用して、WordPress が共有するディレクトリでマルチ読み取りとマルチ書き込みを有効にすることを検討できます。実例。
このプロセスには、Kubernetes 上で分散ストレージ クラスターを実行することが含まれますが、実際には Kubernetes で構築されていないため、うまく機能しますが、長期的な展開には理想的ではありません。
データベースについては、MySQL インスタンスをホストするマネージド リレーショナル データベース サービスを使用することを個人的にお勧めします。Google の CloudSQL であっても、AWS の RDS であっても、より手頃な価格で高可用性と冗長処理を提供するためです。データの整合性について心配する必要があります。 Kuberntes はステートフル アプリケーションを中心に設計されていないため、Kuberntes に組み込まれた状態は後付けのようなものです。現在、データベース サービスを選択する際に必要な保証を提供できるソリューションが多数提供されています。
言い換えれば、上で紹介したものは、Kubernetes チュートリアルや Web 上にある例から関連性のある現実的な Kubernetes 例を作成する理想的なプロセスであり、Kubernetes 1.8.x の特徴のすべての新機能が含まれています。
このガイドを通じて、WordPress と MySQL をデプロイするときに驚くべき経験が得られることを願っています。もちろん、すべてが正常に実行されることを願っています。