Tutorial: Deploy Access Server on GKE with the Helm Chart
Overview
This tutorial guides you through deploying OpenVPN Access Server on a Google Kubernetes Engine (GKE) Standard cluster using the Access Server Helm chart.
The deployment uses Ubuntu nodes, persistent storage, a regional static IP, and a single mixed-protocol external load balancer that exposes:
TCP 943 for the Admin Web UI and Client Web UI.
TCP 443 for web services and OpenVPN TCP connections.
UDP 1194 for OpenVPN UDP connections.
At the end of the tutorial, you'll have one Access Server pod running in GKE with persistent storage and a stable public IP for VPN and web traffic.
For other Kubernetes platforms, refer to the Kubernetes Helm tutorial. If you'd rather deploy Access Server on a Compute Engine VM instead of Kubernetes, refer to the Google Cloud VM guide.
How the GKE deployment works
The Helm chart creates:
One Access Server pod.
Persistent storage for Access Server data.
A Kubernetes
LoadBalancerService.One public IP for TCP 943, TCP 443, and UDP 1194.
Because the Service contains both TCP and UDP ports, this is a mixed-protocol load balancer.
This tutorial requires GKE version 1.34.1-gke.2190000 or newer. Versions from 1.34.1-gke.2190000 support the external IPv4 mixed-protocol load balancer used in this tutorial.
Prerequisites
Before you begin, ensure you have:
A Google Cloud project with billing enabled.
Permission to create GKE clusters, Compute Engine addresses, and load balancers in the project.
GKE version 1.34.1-gke.2190000 or newer.
Google Cloud Shell, or a local machine with:
Google Cloud CLI (
gcloud).kubectl.Helm.
gke-gcloud-auth-plugin.
This tutorial uses Cloud Shell, which provides the required Google Cloud command-line tools.
Limitations and known issues
The following limitations apply when you deploy Access Server from a container image on GKE:
Failover mode: This feature isn't supported.
Layer 2 bridging: This mode isn't supported.
Fixed license keys: This license model isn't supported. Fixed keys can become invalid because a container deployment doesn't provide a persistent hardware fingerprint.
Data Channel Offload (DCO): DCO depends on the Linux kernel running on the GKE node. Containers use the host kernel, so DCO must be available there.
Linux kernel 6.16 or newer: Access Server 3.2.0 and newer uses the DCO implementation based on upstream Linux kernel 6.16+. If the GKE node kernel includes DCO support, Access Server can use it without an additional module.
Linux kernel older than 6.16: Install the DCO module on the Ubuntu GKE node before Access Server can use it. Refer to the DCO tutorial and DCO overview.
Performance: The additional container and Kubernetes networking layers can add latency and overhead. Evaluate performance requirements before using this architecture for heavily loaded deployments.
PAM authentication: Avoid PAM authentication for this deployment because user credentials stored inside the container aren't persistent.
Logs: Access Server sends logs to the container output. Retrieve them with:
kubectl logs <POD_NAME>
For more information about container deployment behavior, refer to the Docker guide.
Troubleshooting
Submit a support ticket if you need assistance.
Start by checking the pod and Service status:
Check the Access Server pod:
kubectl get podsIf the pod doesn't start or become ready, describe it:
kubectl describe pod <POD_NAME>Review its logs:
kubectl logs <POD_NAME>For load balancer problems, inspect the Service and its events:
kubectl describe svc my-openvpn-as-openvpn-as
Use the following common issues to identify the next step.
Issue | Cause or resolution |
|---|---|
| Kubernetes couldn't retrieve the Access Server container image. Verify the image is available and that outbound network access works. |
| Verify the pod is running with |
| Ensure the cluster is running GKE |
Service | Describe the Service and review its Events section. Verify the regional static IP, GKE version, and backend service-based load balancer configuration. |
| Verify that you created a GKE Standard cluster rather than an Autopilot cluster and that |
Pod remains | Verify that the node has sufficient CPU and memory and that the persistent volume can attach. |
Pod stays | Check the pod events and logs. Verify |
Client connects, but the connection profile contains a private IP | Configure the public hostname or regional static IP in Step 8, then issue an updated connection profile as needed. |
For additional Google Cloud troubleshooting, refer to the GCP FAQ.