Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

This repository sets up a geo-distributed Wordpress installation running across three Google Cloud regions. It is intended to showcase the feasibilty of using NewSQL databases to build fault-tolerant systems.

NOTE: the project is intended as an experiment, and is nowhere near ready for production.

Terraform is used to spawn three Kubernetes clusters in three separate Google Cloud regions.

After this, Kubernetes manifests for a geo-wordpress stack are rendered and deployed to the clusters. A separate geo-wordpress stack is run on each cluster and it consists of:

  • TiDB: a MySQL-compatible distributed database offering high availability and strong (ACID) consistency. TiDB operates in a distributed manner and uses the Raft protocol to agree on and order transactions. One instance is run in each region, meaning that the database can tolerate the loss of one region and still be able to form a quorum and, hence, remain available.
  • nfs-provisioner: A dynamic provisioner of NFS volumes for use by Wordpress pods.
  • Wordpress: Uses TiDB as a drop-in replacement for MySQL and mounts an NFS volume created by the nfs-provisioner.
  • SyncThing: forms a "file synchronization group" with the SyncThing processes on the other clusters and listens for filesystem notifications (inotify) on the Wordpress volume. Whenever a change is detected, the change is propagated to its peers. Think of it as a bidirectional rsync. If a peer gets disconnected from its group it should be able to catch up when it gets back, given that the system clocks on the hosts are fairly well synchronized.

The whole setup is fronted by a global cloud load-balancer set up to spread traffic across all regions. The load-balancer uses a health check to detect failed nodes and, if detected, take that target out of rotation.

The setup is illustrated by the following image:

architecture

Bring up Kubernetes clusters

  1. Prepare a credentials file for GCE. You can fill out the gce-secrets.var. The parameters can be found in infra/terraform/main.tf.

  2. Add selected regions (and any additional variables) to clusters.var.

  3. Bring up Kubernetes clusters in AWS, GCE, and Azure. Refer to infra/terraform/main.tf for all the variables.

     terraform init infra/terraform
    terraform apply --var-file gce-secrets.var --var-file clusters.var \
    infra/terraform
    

When terraform completes, note the ip address of the cloud load-balancer.

Install the geo-wordpress stack onto the Kubernetes clusters

If Terraform finished successfully, just run:

 ./bin/install-wp-stack.sh

The script will output a kubeconfig file which can be used to communicate with the clusters using kubectl. To use it, set

export KUBECONFIG=$PWD/kubeconfig

You can now wait for all pods to enter the Running state. In separate terminal windows, issue the following commands:

KUBECONFIG=/tmp/cluster0.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster1.config watch kubectl get pods -n wp
KUBECONFIG=/tmp/cluster2.config watch kubectl get pods -n wp

When everything is Running, navigate your web browser to http://$(terraform output loadbalancer_ip). This should take you to the Wordpress installation page and your ready to go.

Verify

You can verify that files are properly synchronized by, for instance, uploading media and checking, for each cluster, that they have the same content in their upload folder. For each cluster, run something like (replace pod name):

watch kubectl exec -n wp wordpress-654b4dd45b-7j9fp -- ls -al /var/www/html/wp-content/uploads/2018/11

Tear down clusters

Start by stopping instances and deleting the geokube-* created routes in Google Cloud, since terraform will otherwise fail:

gcloud compute instances list --filter="name~geokube" --format=json | jq -r .[].selfLink | xargs gcloud compute instances stop
gcloud compute routes list --filter="name~geokube" --format=json | jq -r '.[].name' | xargs gcloud compute routes delete --quiet

Then run:

terraform destroy --force --var-file gce-secrets.var --var-file clusters.var infra/terraform

About

A toy sample that sets up a geo-distributed Wordpress across three Kubernetes clusters in three GCE regions

Topics

Resources

Stars

12 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages