Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Last active April 8, 2024 03:57
Show Gist options
  • Save mikesparr/9a23ba82ea0b396881b9b91938b7bd88 to your computer and use it in GitHub Desktop.
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
#!/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 &copy; 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 &copy; 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