Why This Article?
Most tutorials show the happy path – but in reality, getting a Kubernetes service exposed to the internet via a subdomain with SSL (e.g. with Google Managed Certificates on GKE) can be a headache if you miss the right sequence or make changes too early.
Let’s do it right – and learn from real-world war stories.
Scenario:
-
You want to deploy a web service on GKE.
-
You want to access it via a subdomain (e.g.
app.yourdomain.com
). -
You want HTTPS with a Google Managed Certificate (no Let’s Encrypt hassle).
-
You want to avoid all the common pitfalls and “it works, but not really” situations.
1. The Correct Sequence (TL;DR)
-
(Optional, but highly recommended): Reserve a Static IP
-
gcloud compute addresses create my-static-ip --global
-
This ensures your A record and the GCP resources always point to the same IP, even if you recreate things.
-
-
Create the Kubernetes Service
-
Type:
LoadBalancer
-
Set the static IP (if you reserved one) via the annotation:
-
Don’t use
ClusterIP
if you plan to expose the app externally!
-
-
Create the Ingress Resource
-
Reference your Service by name/port.
-
Annotate for:
-
BackendConfig (for things like timeouts, health checks, etc.)
-
SSL certificate (see below)
-
Health check path (e.g.,
/healthz
)
-
-
-
Create the ManagedCertificate resource
-
Example:
-
Reference this cert in your Ingress via annotation:
-
-
Update your DNS A Record
-
Once your Service/Ingress has an external IP, set your DNS A record for
app.yourdomain.com
to this IP. -
Tip: This is why using a static IP is best – it never changes.
-
-
Wait for DNS and SSL Propagation
-
DNS propagation can take minutes to hours.
-
The Google Managed Certificate will show
Provisioning
and only becomeActive
once:-
DNS is set up and
-
Google can validate domain ownership.
-
-
2. Common Pitfalls
-
Mixing up Service Types:
If you start withClusterIP
and later switch toLoadBalancer
, GKE may struggle to set up the necessary cloud resources (NEG, Load Balancer, etc.), or even “ghost” resources can linger. -
Creating Ingress before LoadBalancer Service is Ready:
If you create Ingress too soon, Google tries to wire up the backend before the Service is ready, leading to broken or stuck state. -
DNS A Record points to the wrong IP or not yet set:
The ManagedCertificate will never becomeActive
unless DNS is correct and public. -
Changing resources too quickly (impatience!):
GCP is slow to update cloud resources. Constantly deleting/recreating (while tempting) often makes things worse (stale resources, failed cleanups, race conditions). -
Forgetting to check
kubectl get events
ordescribe
resources:
Most real errors and their causes are only visible in the Kubernetes events or resource descriptions, not in the GCP console.
3. Real-Life Workflow (the “Don’t Get Burned” Checklist)
-
Reserve a static IP (optional, but best).
-
Apply Service.yaml (
type: LoadBalancer
), wait for EXTERNAL-IP. -
Apply ManagedCertificate.yaml.
-
Apply Ingress.yaml (with all proper annotations).
-
Update DNS A record to EXTERNAL-IP.
-
Wait. And then wait more.
-
Check:
-
kubectl get managedcertificate
(should sayActive
) -
kubectl describe ingress
(should show your IP, backends) -
kubectl get events --sort-by=.lastTimestamp
-
-
Test via DNS (not just via raw IP).
4. Debugging Tips
-
Certificate stuck in “Provisioning”?
-
Check if your DNS A record is set and propagated globally.
-
Make sure the certificate domain matches your Ingress host exactly.
-
-
Ingress shows 502/404?
-
Check if Service endpoints are healthy.
-
Health check paths must be accessible (no auth!).
-
-
Everything looks “stuck”?
-
Try deleting both Ingress and Service, then recreating, but only if you’ve waited a while and checked events for errors.
-
Always check for orphaned cloud resources (static IP, BackendConfigs, NEGs) in the GCP console.
-
5. Final Notes
-
Order matters.
Most issues come from steps done out-of-order, or from “fixing” something before the previous change was really ready. -
GKE takes time.
Most resources, especially ManagedCertificates, take several minutes to become ready. -
Don’t panic!
Everyone has struggled with this setup. The more you practice, the better you get at reading events/logs.
Summary Table
Step | What to Do | Why |
---|---|---|
Reserve Static IP | (Optional) Reserve for DNS stability | Avoids IP changes |
Create Service | Use type: LoadBalancer |
Exposes the app |
Create Ingress | Reference Service and Cert, add annots | Routing/SSL setup |
Create Certificate | ManagedCertificate for the subdomain | HTTPS |
Set DNS A Record | Point subdomain to IP | Domain routing |
Wait & Check | Let GCP propagate, use kubectl to check | Sanity check |