Skip to content

Commit 93de68c

Browse files
authored
K8SPS-508 Documented the cross-site replication (#212)
* K8SPS-508 Documented the cross-site replication new file: docs/clusterset-cr.md new file: docs/cr-statuses.md modified: docs/features.md modified: docs/operator.md new file: docs/replication-setup.md new file: docs/replication.md modified: docs/users.md modified: mkdocs-base.yml * Upadted after the review * Upadted after the review p2 * Documented the linitation of restoring on replica as part of CS Updated the delete replica scenario: added steps how to delete offline replica * Removed mermaid diagram, minor fixes * Added a limitation about deleting replica before deleting the CS * Updated CS conditions * Added workaround about deleting the CS finalizer, updated diagram
1 parent 61b0825 commit 93de68c

13 files changed

Lines changed: 1419 additions & 2 deletions
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python3
2+
"""Generate the cross-site replication architecture diagram.
3+
4+
Based on the mockup in docs/assets/images/cross-site-replication-architecture.svg.
5+
6+
Requires:
7+
pip install diagrams
8+
9+
Run from repo root:
10+
python docs/assets/diagrams/cross-site-replication-architecture.py
11+
12+
Output:
13+
docs/assets/images/cross-site-replication-architecture-diagrams.png
14+
"""
15+
16+
from pathlib import Path
17+
18+
from diagrams import Cluster, Diagram, Edge
19+
from diagrams.k8s.compute import Pod
20+
from diagrams.k8s.others import CRD
21+
from diagrams.onprem.client import Client
22+
from diagrams.onprem.database import MySQL
23+
24+
OUTPUT = Path(__file__).resolve().parents[1] / "images" / "cross-site-replication-architecture-diagrams.png"
25+
26+
# Edge styles used across the diagram
27+
ASYNC_EDGE = Edge(label="Async replication", color="darkgreen")
28+
ADMIN_API_EDGE = Edge(label="mysqlsh AdminAPI\n(MySQL protocol)")
29+
30+
31+
def innodb_cluster_nodes():
32+
"""Three linked MySQL instances inside an InnoDB Cluster (Group Replication)."""
33+
primary = MySQL("Primary\n+ PVC")
34+
secondary_1 = MySQL("Secondary\n+ PVC")
35+
secondary_2 = MySQL("Secondary\n+ PVC")
36+
primary - secondary_1 - secondary_2 - primary
37+
return primary, secondary_1, secondary_2
38+
39+
40+
def member_site(cr_label: str):
41+
"""Build one ClusterSet member site: Operator, CR, and InnoDB Cluster."""
42+
operator = Pod("PS Operator")
43+
ps_cr = CRD(cr_label)
44+
with Cluster("InnoDB Cluster"):
45+
primary, secondary_1, secondary_2 = innodb_cluster_nodes()
46+
operator >> ps_cr
47+
operator >> [primary, secondary_1, secondary_2]
48+
return operator, primary, secondary_1, secondary_2
49+
50+
51+
graph_attr = {
52+
"fontsize": "13",
53+
"bgcolor": "white",
54+
"pad": "0.5",
55+
"splines": "spline",
56+
"nodesep": "0.9",
57+
"ranksep": "1.3",
58+
}
59+
60+
with Diagram(
61+
"Cross-site replication architecture",
62+
filename=str(OUTPUT.with_suffix("")),
63+
outformat="png",
64+
show=False,
65+
direction="TB",
66+
graph_attr=graph_attr,
67+
):
68+
app = Client("Application")
69+
70+
with Cluster("InnoDB ClusterSet (PerconaServerMySQLClusterSet)"):
71+
# Orchestration site - pure controller; does not manage Pods in remote clusters
72+
with Cluster("Orchestration site (one Kubernetes namespace)"):
73+
clusterset_cr = CRD("PerconaServerMySQL\nClusterSet CR")
74+
controller = Pod("ClusterSet\ncontroller")
75+
runner = Pod("mysqlshell-\nrunner Pod")
76+
jobs = Pod("Jobs")
77+
clusterset_cr >> controller >> runner >> Edge(style="dashed") >> jobs
78+
79+
# Member sites - independently managed PerconaServerMySQL clusters
80+
with Cluster("Member sites", direction="LR"):
81+
with Cluster("Primary site\nKubernetes cluster / region A"):
82+
op_primary, mysql_p_primary, _, _ = member_site(
83+
"PerconaServerMySQL\nCR (group-replication)",
84+
)
85+
86+
with Cluster("Replica site\nKubernetes cluster / region B"):
87+
op_replica, mysql_r_primary, _, _ = member_site(
88+
"PerconaServerMySQL CR\nbootstrap: manual",
89+
)
90+
91+
with Cluster("Replica site\nDifferent K8s / cloud / on-premises"):
92+
op_remote, mysql_o_primary, _, _ = member_site(
93+
"PerconaServerMySQL\nCR (group-replication)",
94+
)
95+
96+
# mysqlsh AdminAPI reaches MySQL endpoints at every site over the network
97+
runner >> ADMIN_API_EDGE >> [op_primary, op_replica, op_remote]
98+
99+
# Async replication channels from the primary cluster PRIMARY member
100+
mysql_p_primary >> ASYNC_EDGE >> mysql_r_primary
101+
mysql_p_primary >> ASYNC_EDGE >> mysql_o_primary
102+
103+
# Application traffic
104+
app >> Edge(label="Writes") >> mysql_p_primary
105+
app >> Edge(label="Reads") >> mysql_r_primary
106+
app >> Edge(label="Reads") >> mysql_o_primary
107+
108+
print(f"Wrote {OUTPUT}")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
%% Cross-site replication / InnoDB ClusterSet architecture
2+
%% Source for the diagram in docs/replication.md
3+
%% Percona docs palette: fill #D4EDFB, stroke #789CD6
4+
5+
flowchart TB
6+
classDef clusterBox fill:#D4EDFB,stroke:#789CD6,stroke-width:2px,color:#1a1a1a
7+
classDef innerBox fill:#ffffff,stroke:#789CD6,stroke-width:1px,color:#1a1a1a
8+
classDef mgmtBox fill:#E8F4FC,stroke:#326690,stroke-width:2px,color:#1a1a1a
9+
classDef appBox fill:#ffffff,stroke:#326690,stroke-width:2px,color:#1a1a1a
10+
classDef dashedBox fill:#ffffff,stroke:#789CD6,stroke-width:1px,stroke-dasharray:5 5,color:#1a1a1a
11+
12+
APP["Application"]:::appBox
13+
14+
subgraph CS["ClusterSet"]
15+
direction TB
16+
17+
subgraph MGMT["ClusterSet management"]
18+
direction LR
19+
CR["PerconaServerMySQLClusterSet CR<br/>(ps-clusterset)"]:::mgmtBox
20+
CTRL["ClusterSet controller"]:::mgmtBox
21+
RUNNER["mysqlshell-runner Pod"]:::mgmtBox
22+
CR --- CTRL
23+
CTRL --- RUNNER
24+
end
25+
26+
subgraph PRIMARY["Kubernetes cluster — primary"]
27+
direction TB
28+
OP1["PS Operator"]:::innerBox
29+
subgraph GR1["Group Replication"]
30+
direction LR
31+
M1["MySQL Pod<br/>+ PVC"]:::innerBox
32+
M2["MySQL Pod<br/>+ PVC"]:::innerBox
33+
M3["MySQL Pod<br/>+ PVC"]:::innerBox
34+
end
35+
HA1["HAProxy"]:::innerBox
36+
OP1 --> GR1
37+
GR1 --> HA1
38+
end
39+
40+
subgraph REPLICA["Kubernetes cluster — replica"]
41+
direction TB
42+
OP2["PS Operator"]:::innerBox
43+
subgraph GR2["Group Replication"]
44+
direction LR
45+
R1["MySQL Pod<br/>+ PVC"]:::innerBox
46+
R2["MySQL Pod<br/>+ PVC"]:::innerBox
47+
R3["MySQL Pod<br/>+ PVC"]:::innerBox
48+
end
49+
HA2["HAProxy"]:::dashedBox
50+
OP2 --> GR2
51+
GR2 --> HA2
52+
end
53+
54+
subgraph ONPREM["On-premises MySQL"]
55+
direction TB
56+
subgraph NODES["MySQL nodes"]
57+
direction LR
58+
N1["MySQL node"]:::innerBox
59+
N2["MySQL node"]:::innerBox
60+
N3["MySQL node"]:::innerBox
61+
end
62+
HA3["HAProxy"]:::innerBox
63+
NODES --> HA3
64+
end
65+
66+
RUNNER -->|"mysqlsh AdminAPI"| PRIMARY
67+
RUNNER -->|"mysqlsh AdminAPI"| REPLICA
68+
RUNNER -->|"mysqlsh AdminAPI"| ONPREM
69+
70+
PRIMARY ==>|"Async replication"| REPLICA
71+
PRIMARY ==>|"Async replication"| ONPREM
72+
OP1 -.->|"Async replication"| OP2
73+
end
74+
75+
APP -->|"Writes and reads"| HA1
76+
APP -->|"Reads"| HA2
77+
APP -->|"Reads"| HA3
78+
79+
class CS clusterBox
80+
class PRIMARY,REPLICA,ONPREM clusterBox
81+
class MGMT clusterBox
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env python3
2+
"""Generate the cross-site replication ClusterSet architecture diagram.
3+
4+
Requires: pip install diagrams
5+
Run from repo root:
6+
python docs/assets/diagrams/cross-site-replication-clusterset.py
7+
8+
Output: docs/assets/images/cross-site-replication-clusterset-diagrams.png
9+
"""
10+
11+
from pathlib import Path
12+
13+
from diagrams import Cluster, Diagram, Edge
14+
from diagrams.k8s.compute import Pod
15+
from diagrams.k8s.others import CRD
16+
from diagrams.onprem.client import Client
17+
from diagrams.onprem.compute import Server
18+
from diagrams.onprem.database import MySQL
19+
from diagrams.onprem.network import HAProxy
20+
21+
OUTPUT = Path(__file__).resolve().parents[1] / "images" / "cross-site-replication-clusterset-diagrams.png"
22+
23+
graph_attr = {
24+
"fontsize": "13",
25+
"bgcolor": "white",
26+
"pad": "0.4",
27+
"splines": "spline",
28+
"nodesep": "0.8",
29+
"ranksep": "1.2",
30+
}
31+
32+
with Diagram(
33+
"Cross-site replication ClusterSet",
34+
filename=str(OUTPUT.with_suffix("")),
35+
outformat="png",
36+
show=False,
37+
direction="LR",
38+
graph_attr=graph_attr,
39+
):
40+
app = Client("Application")
41+
42+
43+
grouprepl = Edge(label="Group Replication", style="dashed", color="gray")
44+
asyncrepl = Edge(label="async replication", style="solid", color="green")
45+
46+
with Cluster("ClusterSet", direction="LR"):
47+
with Cluster("ClusterSet management", direction="LR"):
48+
clusterset_cr = CRD("PerconaServerMySQL\nClusterSet CR")
49+
controller = Pod("ClusterSet\ncontroller")
50+
runner = Pod("mysqlshell-\nrunner Pod")
51+
clusterset_cr << controller >> runner
52+
53+
54+
with Cluster(""):
55+
with Cluster("Kubernetes cluster — primary"):
56+
op_primary = Pod("PS Operator")
57+
with Cluster("MySQL Cluster primary"):
58+
mysql_primary1 = Pod("Primary")
59+
mysql_primary2 = Pod("Secondary")
60+
mysql_primary3 = Pod("MySQL Pod")
61+
mysql_primary1 - mysql_primary2 - mysql_primary3 - mysql_primary1 << grouprepl
62+
haproxy_primary = HAProxy("HAProxy")
63+
op_primary >> mysql_primary1 >> haproxy_primary
64+
65+
with Cluster("Kubernetes cluster — replica"):
66+
op_replica = Pod("PS Operator")
67+
with Cluster("MySQL Cluster primary"):
68+
mysql_replica1 = Pod("Primary")
69+
mysql_replica2 = Pod("Secondary")
70+
mysql_replica3 = Pod("Secondary")
71+
mysql_replica1 - mysql_replica2 - mysql_replica3 - mysql_replica1 << grouprepl
72+
haproxy_replica = HAProxy("HAProxy")
73+
op_replica >> mysql_replica1 >> haproxy_replica
74+
75+
with Cluster("On-premises MySQL"):
76+
mysql_nodes = Server("MySQL nodes")
77+
haproxy_onprem = HAProxy("HAProxy")
78+
mysql_nodes >> haproxy_onprem
79+
80+
runner >> Edge(label="mysqlsh AdminAPI") >> [op_primary, op_replica, mysql_nodes]
81+
mysql_primary1 >> Edge(label="Async replication", color="darkgreen") >> mysql_replica1
82+
mysql_primary1 >> Edge(label="Async replication", color="darkgreen") >> mysql_nodes
83+
op_primary >> Edge(label="Async replication", style="dashed", color="gray") >> op_replica
84+
85+
app >> Edge(label="Writes and reads") >> mysql_primary1
86+
app >> Edge(label="Reads") >> mysql_replica1
87+
app >> Edge(label="Reads") >> mysql_nodes
88+
89+
print(f"Wrote {OUTPUT}")

docs/assets/images/innodb-clusterset.svg

Lines changed: 4 additions & 0 deletions
Loading
187 KB
Loading

0 commit comments

Comments
 (0)