Last active
April 8, 2024 03:57
-
-
Save mikesparr/9a23ba82ea0b396881b9b91938b7bd88 to your computer and use it in GitHub Desktop.
Snippets from my Cloud Next '24 demo talk "Hello Gateway, Goodbye Ingress" in Las Vegas April 9, 2024
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
##################################################################### | |
# REFERENCES | |
# - https://cloud.google.com/kubernetes-engine/docs/concepts/gateway-api | |
# - https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing | |
# - https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ | |
# - https://cloud.google.com/gemini/docs/quickstart | |
# - https://cloud.google.com/kubernetes-engine/docs/best-practices/rbac | |
# - https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#group_authentication | |
# - https://cloud.google.com/kubernetes-engine/docs/how-to/restrict-resources-access-by-namespace | |
# - https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control | |
##################################################################### | |
export PROJECT_ID="next-24-demo" | |
export IDNS=${PROJECT_ID}.svc.id.goog # workflow identity domain | |
export PROJECT_USER=$(gcloud config get-value core/account) # set current user | |
export GCP_REGION="us-west4" # CHANGEME (OPT) | |
export GCP_ZONE="us-west4-a" # CHANGEME (OPT) | |
export NETWORK_NAME="default" | |
export STATIC_IP_NAME="next-demo-static-ip" | |
export DOMAIN_NAME="next24.msparr.com" # CHANGEME (OPT) | |
export CERT_NAME="next24-msparr-com" # CHANGEME (OPT) | |
export CLUSTER_NAME="next-west" | |
# configure gcloud sdk | |
gcloud config set compute/region $GCP_REGION | |
gcloud config set compute/zone $GCP_ZONE | |
# create project | |
gcloud projects create $PROJECT_ID --folder $FOLDER \ | |
&& linkbilling $PROJECT_ID \ | |
&& gcloud config set project $PROJECT_ID | |
# enable apis | |
gcloud services enable compute.googleapis.com \ | |
storage.googleapis.com \ | |
artifactregistry.googleapis.com \ | |
certificatemanager.googleapis.com \ | |
cloudbuild.googleapis.com \ | |
container.googleapis.com \ | |
containersecurity.googleapis.com \ | |
secretmanager.googleapis.com | |
# provision static ip | |
gcloud compute addresses create $STATIC_IP_NAME --global | |
export STATIC_IP=$(gcloud compute addresses describe $STATIC_IP_NAME \ | |
--format="value(address)" --global) | |
echo "Update DNS for $DOMAIN_NAME with static IP: $STATIC_IP" | |
# create certificate | |
gcloud compute ssl-certificates create $CERT_NAME \ | |
--domains="$DOMAIN_NAME,catsrule.msparr.com,grizrule.msparr.com" \ | |
--global | |
# create cluster | |
gcloud container clusters create $CLUSTER_NAME \ | |
--zone $GCP_ZONE \ | |
--num-nodes 2 \ | |
--enable-ip-alias \ | |
--enable-managed-prometheus \ | |
--enable-network-policy \ | |
--gateway-api standard | |
# create namespaces | |
kubectl create namespace admin | |
kubectl create namespace cats | |
kubectl create namespace griz | |
# customize html for state site | |
cat > configmap-mt.yaml << EOF | kubectl apply -f - | |
apiVersion: v1 | |
kind: ConfigMap | |
metadata: | |
name: website-mt | |
namespace: admin | |
data: | |
index.html: | | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Montana - The Treasure State</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<header> | |
<h1>Montana</h1> | |
<img src="https://www.onlyinyourstate.com/wp-content/uploads/2016/01/Wild-Goose-Island-Glacier-National-Park-Montana-6779913454.jpg?w=720" alt="Scenic Montana Mountains"> | |
</header> | |
<nav> | |
<a href="/griz">Griz</a> | |
<a href="/cats">Cats</a> | |
</nav> | |
</body> | |
</html> | |
style.css: | | |
body { | |
font-family: sans-serif; | |
text-align: center; | |
} | |
header { | |
margin-bottom: 20px; | |
} | |
nav a { | |
display: inline-block; | |
margin: 0 20px; | |
text-decoration: none; | |
} | |
EOF | |
# customize html for each school | |
cat > configmap-cats.yaml << EOF | kubectl apply -f - | |
apiVersion: v1 | |
kind: ConfigMap | |
metadata: | |
name: website-cats | |
namespace: cats | |
data: | |
index.html: | | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Montana State University Bobcats</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<header> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Montana_State_University_Logo.svg/800px-Montana_State_University_Logo.svg.png" alt="Montana State University Bobcats"> | |
</header> | |
<main> | |
<h1>Welcome to Montana State University Bobcats!</h1> | |
<p>We are a public land-grant research university in Bozeman, Montana. Founded in 1893, we are the state's largest university.</p> | |
<p>Our athletic teams compete in the NCAA Division I Football Championship Subdivision (FCS) as a member of the Big Sky Conference.</p> | |
<p>We are proud of our rich history and tradition, and we are committed to providing our students with a world-class education.</p> | |
</main> | |
<footer> | |
<p>Copyright © 2023 Montana State University Bobcats</p> | |
<p><a href="/">Homepage</a></p> | |
</footer> | |
</body> | |
</html> | |
style.css: | | |
body { | |
font-family: sans-serif; | |
text-align: center; | |
} | |
header { | |
margin-bottom: 20px; | |
} | |
nav a { | |
display: inline-block; | |
margin: 0 20px; | |
text-decoration: none; | |
} | |
EOF | |
cat > configmap-griz.yaml << EOF | kubectl apply -f - | |
apiVersion: v1 | |
kind: ConfigMap | |
metadata: | |
name: website-griz | |
namespace: griz | |
data: | |
index.html: | | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>The University of Montana Grizzlies</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<header> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c8/University_of_Montana_logo.png/800px-University_of_Montana_logo.png" alt="The University of Montana Grizzlies"> | |
</header> | |
<main> | |
<h1>Welcome to The University of Montana Grizzlies!</h1> | |
<p>The University of Montana Grizzlies are a Division I FCS football team that competes in the Big Sky Conference. The Grizzlies have won 11 national championships, the most of any FCS team.</p> | |
<p>The Grizzlies play their home games at Washington-Grizzly Stadium in Missoula, Montana. The stadium has a capacity of 25,000 and is one of the most iconic venues in college football.</p> | |
<p>The Grizzlies have a rich tradition of success, and their fans are some of the most passionate in the country. If you're looking for a great college football experience, then come see the Grizzlies play!</p> | |
</main> | |
<footer> | |
<p>Copyright © 2023 The University of Montana Grizzlies</p> | |
<p><a href="/">Homepage</a></p> | |
</footer> | |
</body> | |
</html> | |
style.css: | | |
body { | |
font-family: sans-serif; | |
text-align: center; | |
} | |
header { | |
margin-bottom: 20px; | |
} | |
nav a { | |
display: inline-block; | |
margin: 0 20px; | |
text-decoration: none; | |
} | |
EOF | |
# deploy nginx | |
cat > deployment-mt.yaml << EOF | kubectl apply -f - | |
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: website | |
namespace: admin | |
spec: | |
selector: | |
matchLabels: | |
app: website | |
replicas: 1 | |
template: | |
metadata: | |
labels: | |
app: website | |
spec: | |
containers: | |
- name: website | |
image: nginx | |
ports: | |
- containerPort: 80 | |
volumeMounts: | |
- name: website-index | |
mountPath: /usr/share/nginx/html/ | |
volumes: | |
- name: website-index | |
configMap: | |
name: website-mt | |
EOF | |
cat > deployment-cats.yaml << EOF | kubectl apply -f - | |
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: website | |
namespace: cats | |
spec: | |
selector: | |
matchLabels: | |
app: website | |
replicas: 1 | |
template: | |
metadata: | |
labels: | |
app: website | |
spec: | |
containers: | |
- name: website | |
image: nginx | |
ports: | |
- containerPort: 80 | |
volumeMounts: | |
- name: website-index | |
mountPath: /usr/share/nginx/html/ | |
volumes: | |
- name: website-index | |
configMap: | |
name: website-cats | |
EOF | |
cat > deployment-griz.yaml << EOF | kubectl apply -f - | |
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: website | |
namespace: griz | |
spec: | |
selector: | |
matchLabels: | |
app: website | |
replicas: 1 | |
template: | |
metadata: | |
labels: | |
app: website | |
spec: | |
containers: | |
- name: website | |
image: nginx | |
ports: | |
- containerPort: 80 | |
volumeMounts: | |
- name: website-index | |
mountPath: /usr/share/nginx/html/ | |
volumes: | |
- name: website-index | |
configMap: | |
name: website-griz | |
EOF | |
# create nginx service manifest | |
kubectl expose deployment website --port=80 --target-port=80 --namespace admin | |
kubectl expose deployment website --port=80 --target-port=80 --namespace cats | |
kubectl expose deployment website --port=80 --target-port=80 --namespace griz | |
# annotate services to use container-native load balancing | |
kubectl annotate service website cloud.google.com/neg='{"ingress": true}' --namespace admin | |
kubectl annotate service website cloud.google.com/neg='{"ingress": true}' --namespace cats | |
kubectl annotate service website cloud.google.com/neg='{"ingress": true}' --namespace griz | |
# label namespaces to allow httproute access to gateway | |
kubectl label namespaces admin shared-gateway-access=true --overwrite=true | |
kubectl label namespaces cats shared-gateway-access=true --overwrite=true | |
kubectl label namespaces griz shared-gateway-access=true --overwrite=true | |
# create ingress for state site | |
cat > ingress.yaml << EOF | kubectl apply -f - | |
apiVersion: networking.k8s.io/v1 | |
kind: Ingress | |
metadata: | |
name: website-ingress | |
namespace: admin | |
annotations: | |
kubernetes.io/ingress.global-static-ip-name: $STATIC_IP_NAME | |
ingress.gcp.kubernetes.io/pre-shared-cert: $CERT_NAME | |
ingressClassName: "gce" | |
spec: | |
defaultBackend: | |
service: | |
name: website | |
port: | |
number: 80 | |
EOF | |
# create gateway for state site instead | |
cat > gateway.yaml << EOF | kubectl apply -f - | |
kind: Gateway | |
apiVersion: gateway.networking.k8s.io/v1beta1 | |
metadata: | |
name: external-http | |
namespace: admin | |
spec: | |
gatewayClassName: gke-l7-global-external-managed | |
listeners: | |
- name: https | |
protocol: HTTPS | |
port: 443 | |
tls: | |
mode: Terminate | |
options: | |
networking.gke.io/pre-shared-certs: $CERT_NAME | |
allowedRoutes: | |
namespaces: | |
from: Selector | |
selector: | |
matchLabels: | |
shared-gateway-access: "true" | |
addresses: | |
- type: NamedAddress | |
value: $STATIC_IP_NAME | |
--- | |
kind: HTTPRoute | |
apiVersion: gateway.networking.k8s.io/v1beta1 | |
metadata: | |
name: state-website | |
namespace: admin | |
labels: | |
gateway: external-http | |
spec: | |
parentRefs: | |
- name: external-http | |
namespace: admin | |
hostnames: | |
- "$DOMAIN_NAME" | |
rules: | |
- matches: | |
- path: | |
value: / | |
backendRefs: | |
- name: website | |
port: 80 | |
EOF | |
# add routes for college sites | |
cat > httproute-cats.yaml << EOF | kubectl apply -f - | |
--- | |
kind: HTTPRoute | |
apiVersion: gateway.networking.k8s.io/v1beta1 | |
metadata: | |
name: cats-website | |
namespace: cats | |
labels: | |
gateway: external-http | |
spec: | |
parentRefs: | |
- name: external-http | |
namespace: admin | |
hostnames: | |
- "$DOMAIN_NAME" | |
- catsrule.msparr.com | |
rules: | |
- matches: | |
- path: | |
value: /cats | |
filters: | |
- type: URLRewrite | |
urlRewrite: | |
path: | |
type: ReplacePrefixMatch | |
replacePrefixMatch: / | |
backendRefs: | |
- name: website | |
port: 80 | |
- backendRefs: | |
- name: website | |
port: 80 | |
EOF | |
cat > httproute-griz.yaml << EOF | kubectl apply -f - | |
--- | |
kind: HTTPRoute | |
apiVersion: gateway.networking.k8s.io/v1beta1 | |
metadata: | |
name: griz-website | |
namespace: griz | |
labels: | |
gateway: external-http | |
spec: | |
parentRefs: | |
- name: external-http | |
namespace: admin | |
hostnames: | |
- "$DOMAIN_NAME" | |
- grizrule.msparr.com | |
rules: | |
- matches: | |
- path: | |
value: /griz | |
filters: | |
- type: URLRewrite | |
urlRewrite: | |
path: | |
type: ReplacePrefixMatch | |
replacePrefixMatch: / | |
backendRefs: | |
- name: website | |
port: 80 | |
- backendRefs: | |
- name: website | |
port: 80 | |
EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment