Skip to content

Commit 16a4216

Browse files
authored
feat(GKE): add multitenant quickstart (#633)
1 parent bf504ee commit 16a4216

File tree

3 files changed

+525
-0
lines changed

3 files changed

+525
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START gke_quickstart_multitenant_backend]
16+
apiVersion: v1
17+
kind: ConfigMap
18+
metadata:
19+
name: backend-configmap
20+
namespace: backend-team
21+
labels:
22+
app: backend
23+
data:
24+
go.mod: |
25+
module multitenant
26+
27+
go 1.22
28+
29+
require github.com/go-sql-driver/mysql v1.8.1
30+
31+
require filippo.io/edwards25519 v1.1.0 // indirect
32+
33+
go.sum: |
34+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
35+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
36+
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
37+
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
38+
39+
backend.go: |
40+
package main
41+
42+
import (
43+
"database/sql"
44+
"fmt"
45+
"log"
46+
"math/rand"
47+
"net/http"
48+
"os"
49+
50+
_ "github.com/go-sql-driver/mysql"
51+
)
52+
53+
func main() {
54+
mux := http.NewServeMux()
55+
mux.HandleFunc("/", frontend)
56+
57+
port := "8080"
58+
59+
log.Printf("Server listening on port %s", port)
60+
log.Fatal(http.ListenAndServe(":"+port, mux))
61+
}
62+
63+
func frontend(w http.ResponseWriter, r *http.Request) {
64+
log.Printf("Serving request: %s", r.URL.Path)
65+
66+
host, _ := os.Hostname()
67+
fmt.Fprintf(w, "Backend!\n")
68+
fmt.Fprintf(w, "Hostname: %s\n", host)
69+
70+
// Open database using cloud-sql-proxy sidecar
71+
db, err := sql.Open("mysql", "multitenant-app@tcp/multitenant-app")
72+
if err != nil {
73+
fmt.Fprintf(w, "Error: %v\n", err)
74+
return
75+
}
76+
77+
// Create metadata Table if not exists
78+
_, err = db.Exec("CREATE TABLE IF NOT EXISTS metadata (metadata_key varchar(255) NOT NULL, metadata_value varchar(255) NOT NULL, PRIMARY KEY (metadata_key))")
79+
if err != nil {
80+
fmt.Fprintf(w, "Error: %v\n", err)
81+
return
82+
}
83+
84+
// Pick random primary color
85+
var color string
86+
randInt := rand.Intn(3) + 1
87+
switch {
88+
case randInt == 1:
89+
color = "red"
90+
case randInt == 2:
91+
color = "green"
92+
case randInt == 3:
93+
color = "blue"
94+
}
95+
96+
// Set color in database
97+
_, err = db.Exec(fmt.Sprintf("REPLACE INTO metadata (metadata_key, metadata_value) VALUES ('color', '%s')", color))
98+
if err != nil {
99+
fmt.Fprintf(w, "Error: %v\n", err)
100+
return
101+
}
102+
103+
fmt.Fprintf(w, "Set Color: %s\n", color)
104+
}
105+
106+
---
107+
apiVersion: apps/v1
108+
kind: Deployment
109+
metadata:
110+
name: backendweb
111+
namespace: backend-team
112+
labels:
113+
app: backend
114+
spec:
115+
selector:
116+
matchLabels:
117+
app: backend
118+
tier: web
119+
template:
120+
metadata:
121+
labels:
122+
app: backend
123+
tier: web
124+
spec:
125+
containers:
126+
- name: backend-container
127+
image: golang:1.22
128+
command: ["go"]
129+
args: ["run", "."]
130+
workingDir: "/tmp/backend"
131+
volumeMounts:
132+
- name: backend-configmap
133+
mountPath: /tmp/backend/
134+
readOnly: true
135+
- name: cloud-sql-proxy
136+
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11.4
137+
args:
138+
- "--structured-logs"
139+
- "--port=3306"
140+
- "$(CONNECTION_NAME_KEY)"
141+
securityContext:
142+
runAsNonRoot: true
143+
env:
144+
- name: CONNECTION_NAME_KEY
145+
valueFrom:
146+
configMapKeyRef:
147+
name: database-configmap
148+
key: CONNECTION_NAME
149+
volumes:
150+
- name: backend-configmap
151+
configMap: { name: backend-configmap }
152+
---
153+
apiVersion: v1
154+
kind: Service
155+
metadata:
156+
name: backendweb
157+
namespace: backend-team
158+
labels:
159+
app: backend
160+
annotations:
161+
networking.gke.io/load-balancer-type: "Internal" # Remove to create an external loadbalancer
162+
spec:
163+
selector:
164+
app: backend
165+
tier: web
166+
ports:
167+
- port: 80
168+
targetPort: 8080
169+
type: LoadBalancer
170+
# [END gke_quickstart_multitenant_backend]
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START gke_quickstart_multitenant_frontend]
16+
apiVersion: v1
17+
kind: ConfigMap
18+
metadata:
19+
name: frontend-configmap
20+
namespace: frontend-team
21+
labels:
22+
app: frontend
23+
data:
24+
go.mod: |
25+
module multitenant
26+
27+
go 1.22
28+
29+
require github.com/go-sql-driver/mysql v1.8.1
30+
31+
require filippo.io/edwards25519 v1.1.0 // indirect
32+
33+
go.sum: |
34+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
35+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
36+
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
37+
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
38+
39+
frontend.go: |
40+
package main
41+
42+
import (
43+
"database/sql"
44+
"fmt"
45+
"log"
46+
"net/http"
47+
"os"
48+
49+
_ "github.com/go-sql-driver/mysql"
50+
)
51+
52+
func main() {
53+
mux := http.NewServeMux()
54+
mux.HandleFunc("/", frontend)
55+
56+
port := "8080"
57+
58+
log.Printf("Server listening on port %s", port)
59+
log.Fatal(http.ListenAndServe(":"+port, mux))
60+
}
61+
62+
func frontend(w http.ResponseWriter, r *http.Request) {
63+
log.Printf("Serving request: %s", r.URL.Path)
64+
65+
host, _ := os.Hostname()
66+
fmt.Fprintf(w, "Frontend!\n")
67+
fmt.Fprintf(w, "Hostname: %s\n", host)
68+
69+
// Open database using cloud-sql-proxy sidecar
70+
db, err := sql.Open("mysql", "multitenant-app@tcp/multitenant-app")
71+
if err != nil {
72+
fmt.Fprint(w, "Error: %v\n", err)
73+
return
74+
}
75+
76+
// Retrieve color from the database
77+
var color string
78+
err = db.QueryRow("SELECT metadata_value FROM metadata WHERE metadata_key='color'").Scan(&color)
79+
switch {
80+
case err == sql.ErrNoRows:
81+
fmt.Fprintf(w, "Error: color not found in database\n")
82+
case err != nil:
83+
fmt.Fprintf(w, "Error: %v\n", err)
84+
default:
85+
fmt.Fprintf(w, "Got Color: %s\n", color)
86+
}
87+
}
88+
89+
---
90+
apiVersion: apps/v1
91+
kind: Deployment
92+
metadata:
93+
name: frontendweb
94+
namespace: frontend-team
95+
labels:
96+
app: frontend
97+
spec:
98+
selector:
99+
matchLabels:
100+
app: frontend
101+
tier: web
102+
template:
103+
metadata:
104+
labels:
105+
app: frontend
106+
tier: web
107+
spec:
108+
containers:
109+
- name: frontend-container
110+
image: golang:1.22
111+
command: ["go"]
112+
args: ["run", "."]
113+
workingDir: "/tmp/frontend"
114+
volumeMounts:
115+
- name: frontend-configmap
116+
mountPath: /tmp/frontend/
117+
readOnly: true
118+
- name: cloud-sql-proxy
119+
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11.4
120+
args:
121+
- "--structured-logs"
122+
- "--port=3306"
123+
- "$(CONNECTION_NAME_KEY)"
124+
securityContext:
125+
runAsNonRoot: true
126+
env:
127+
- name: CONNECTION_NAME_KEY
128+
valueFrom:
129+
configMapKeyRef:
130+
name: database-configmap
131+
key: CONNECTION_NAME
132+
volumes:
133+
- name: frontend-configmap
134+
configMap: { name: frontend-configmap }
135+
---
136+
apiVersion: v1
137+
kind: Service
138+
metadata:
139+
name: frontendweb
140+
namespace: frontend-team
141+
labels:
142+
app: frontend
143+
annotations:
144+
networking.gke.io/load-balancer-type: "Internal" # Remove to create an external loadbalancer
145+
spec:
146+
selector:
147+
app: frontend
148+
tier: web
149+
ports:
150+
- port: 80
151+
targetPort: 8080
152+
type: LoadBalancer
153+
# [END gke_quickstart_multitenant_frontend]

0 commit comments

Comments
 (0)