Deploying self-managed GitLab on Google Cloud: when a single VM is enough and when it is not
A single VM is enough when one team, a modest user count and light CI load are the whole requirement, and a reference architecture is needed once availability, scale or recovery targets outgrow one machine. A platform or DevOps lead keeping source control and CI/CD inside a Google Cloud estate should decide the shape from load and recovery needs, not from the install method. The Linux package is the documented method that bundles PostgreSQL, Redis and Sidekiq on the same host, which keeps a first deployment simple. Its bundled components are also why a single VM has a ceiling: as the user count and API request rate grow, the components compete for the same CPU, memory and disk.
The range runs from that single VM to the published reference architectures, which start at 1,000 users and scale to 50,000 users. GitLab generally recommends a high availability strategy at 3,000 or more users, with Gitaly Cluster, PostgreSQL with Patroni, Redis Sentinel and Consul. On Google Cloud, the reference shape usually moves PostgreSQL and Redis to managed services and object storage to Cloud Storage buckets. Before choosing, confirm with GitLab's reference architecture page which variant matches your user count and whether your target design uses the Cloud Native Hybrid pattern, because stateful components such as PostgreSQL and Redis are not supported inside Kubernetes.
Two questions decide the move beyond one VM: how long the business can tolerate an outage, and whether a second region must hold a warm standby. GitLab Geo, available in the Premium and Ultimate tiers, provides a continuously synchronized secondary site in another region for disaster recovery, so a single VM with only local backups is a different risk position. The GitLab documentation also covers offline and air-gapped operation, which matters if your Google Cloud estate is restricted. Write those requirements down first, then size the deployment to them.
Choosing between a single VM, a hybrid layout and a full reference architecture
The single VM path installs GitLab with the Linux package on one Compute Engine instance. The Linux package bundles PostgreSQL, Redis and Sidekiq, so the instance carries the application, the database and the cache together. This keeps the build small and the number of moving parts low, which suits a team starting with a limited set of projects and a small user base. The trade-off is that one failure takes down source control, code review and pipelines at the same time.
- Components: one VM, one persistent disk for repositories and data, and the bundled PostgreSQL and Redis.
- Operations: you own OS patching, GitLab upgrades, backups and restore testing on the same host.
- Backups: plan snapshots and GitLab backup tasks together, and test restores on a separate instance.
- Limits: scaling means resizing the VM, and recovery depends on that single machine.
- Upgrades: required upgrade stops still apply, so plan each stop as a maintenance window.
Before choosing this path, confirm the expected user count, pipeline load and recovery time objective with your business owners, and check the hardware baseline in the GitLab documentation for your target release.
The hybrid layout keeps GitLab application components on Compute Engine VMs and moves the database and cache to managed services. On Google Cloud that means Cloud SQL for PostgreSQL and a managed Redis service, with GitLab connecting to both over private networking. Managed services take over patching, failover mechanics and some backup tasks, but the GitLab side still needs careful configuration and compatibility checks for the PostgreSQL and Redis versions your release supports.
- Components: GitLab application VMs, Cloud SQL for PostgreSQL, a managed Redis instance and object storage for artifacts and other data types.
- Operations: you still own GitLab upgrades, runner fleets and configuration files such as gitlab.rb.
- Database access: confirm the database roles, extensions and version limits your GitLab release requires before you provision.
- Recovery: managed backups do not replace GitLab backup tasks, so test restores of both sides.
- Availability: the application tier remains a set of single points unless you add redundancy.
Ask your team to confirm which managed service versions your GitLab release supports and whether your organization accepts a managed database in its change and data residency rules.
GitLab's reference architectures are published sizing patterns that scale from 1,000 users at 20 API requests per second to 50,000 users at 1,000 API requests per second. They separate Gitaly, PostgreSQL, Redis, Sidekiq and the web and API tiers so each can grow on its own. For 3,000 or more users, GitLab generally recommends a high availability strategy, which in the documented reference designs uses Gitaly Cluster with Praefect, PostgreSQL with Patroni, Redis Sentinel and Consul. This path is the one most organizations need when source control and CI are business-critical.
- Components: multiple application nodes, Gitaly Cluster, Patroni-managed PostgreSQL, Redis Sentinel, load balancers and monitoring.
- Operations: you run failover testing, rolling upgrades and capacity reviews as routine work.
- Stateful services: PostgreSQL and Redis must run on VMs or managed services, not inside Kubernetes, which the Cloud Native Hybrid architecture accounts for by running only stateless components on Kubernetes.
- Disaster recovery: Geo provides a warm-standby secondary site in another region, available in the Premium and Ultimate tiers.
- Sizing: select the reference architecture from your measured user and API load, not from headcount alone.
Confirm with GitLab's current reference architecture page which sizing matches your load before you budget infrastructure and staff.
How Cloud SQL, managed Redis and Google Cloud Storage fit around GitLab
GitLab splits its state across four places, and each one needs a deliberate home on Google Cloud. Relational data such as users, projects, merge requests and CI metadata lives in PostgreSQL. Transient and cached data, including session and background job coordination, lives in Redis. Git repository data is stored by Gitaly, which on a single VM uses local disk and at larger scale runs on dedicated Gitaly nodes. Large binary objects such as job artifacts, LFS files, container and package registry data, uploads and CI logs go to object storage. Mapping these four stores to Cloud SQL, a managed Redis service and Google Cloud Storage buckets is the core design decision for any multi-node build, and it should be written down before the first install.
GitLab's reference architectures keep PostgreSQL and Redis on virtual machines or managed services rather than inside Kubernetes. The GitLab reference architectures documentation states that running stateful components such as PostgreSQL and Redis in Kubernetes is not supported, and the Cloud Native Hybrid pattern runs stateless components on Kubernetes while stateful services stay outside it. For a Google Cloud build, this means Cloud SQL and a managed Redis service are the natural stateful tier, with GKE used only for stateless workloads if you choose that pattern. Confirm that your chosen Cloud SQL PostgreSQL version and managed Redis version are supported for your exact GitLab release, because supported versions change between releases and the GitLab reference architectures page is the authoritative check.
Object storage is configured per data type, so a single bucket setting does not automatically cover everything. GitLab offers a consolidated object storage form for common data types, but some data types still need separate settings, and the exact list depends on the GitLab version. Plan one Google Cloud Storage bucket per object type where your retention, access or lifecycle rules differ, and confirm in the object storage guidance which types the consolidated form covers and which need their own configuration. Test a backup and restore that touches every bucket before go-live, because a missing object type often surfaces only during recovery.
Setup sequence for a Google Cloud GitLab deployment
This sequence takes a self-managed GitLab instance from a confirmed target version to a tested, backed-up installation on Google Cloud, with a check at each step so problems surface before users depend on the system. It is built so the infrastructure, the application and the recovery path are verified in order.
Confirm the target version and upgrade stop
Before any infrastructure is created, the team picks the GitLab version to install and checks it against the required upgrade stops in the upgrade paths documentation. Because GitLab requires upgrades to pass through required stops, a fresh install on the newest release may still leave the team needing to plan a path later. The team also checks the maintenance policy to confirm which releases receive security fixes. The step closes with a written version decision, the list of stops the team expects to cross over the instance's life, and a named owner for upgrades. Confirm the choice with GitLab's current documentation at the time you build.
Size the VM or reference architecture
The team estimates user count, API load and CI volume, then chooses between a single VM for a small instance and a reference architecture for larger ones. GitLab's reference architectures start at 1,000 users and the documentation generally recommends a high availability strategy for 3,000 or more users, so headcount is the first input to check. Machine types, Gitaly storage and the database layout follow from that choice. The output is a sizing note that names the machine families, disk types and the component layout, reviewed against the server requirements guidance. Ask the vendor or your architect to confirm current sizing tables for the chosen release.
Create network and IAM boundaries
A VPC, subnets, firewall rules and a dedicated service account are created so that GitLab components can reach each other and their managed services without broad access. Administrative access is restricted to named groups, and outbound paths for package and container pulls are documented, which matters if the instance must later run offline. Private connectivity to Cloud SQL and Redis is set up at this stage rather than exposing them publicly. The check is a network diagram reviewed by the security team and a test instance that can resolve and reach the subnet it will use, with no unexpected open ports.
Provision Cloud SQL and managed Redis
The team creates the PostgreSQL instance on Cloud SQL and the managed Redis service in the same region as the GitLab VMs, then confirms that the PostgreSQL version and extensions are supported by the GitLab release chosen in step one. Database users, passwords stored in a secrets manager, backup windows and high availability settings are configured here. Confirm the supported PostgreSQL and Redis versions in GitLab's documentation for your release, since they change between releases. The check is a successful connection from the GitLab host using the private address and a documented backup schedule on the database.
Create one bucket per object type
GitLab stores several kinds of data in object storage, so the team creates a separate Google Cloud Storage bucket for each object type, such as artifacts, LFS objects, uploads, packages, registry and backups. Each bucket gets its own access binding for the GitLab service account, uniform access controls, retention settings and encryption choices reviewed against internal policy. Bucket names and lifecycle rules are recorded so that backup and restore procedures can refer to them later. The check is a write and read test from the GitLab host to every bucket, and a listing that shows the buckets exist with the intended settings.
Install and configure GitLab
GitLab is installed on the VMs using the installation method chosen for the environment, with external PostgreSQL, Redis and object storage pointed at the resources from the earlier steps. The team sets the external URL, object storage connections and backup settings in the central configuration file and applies them with a reconfigure run. Initial administrator access, sign-up restrictions and HTTPS certificates are configured before the instance is opened to users. The check is that the health checks report all components healthy, the sign-in page loads over HTTPS, and a test project can be created, pushed to and browsed.
Connect runners
Runners are registered to the new instance and matched to the runner executors the team has chosen, such as Docker Autoscaler on cloud VMs. Runner versions are aligned with the GitLab version, as the documentation advises, and runners are placed on their own network segment with the service account they need and no more. A test pipeline runs a simple job, pulls an image, writes an artifact to the artifacts bucket and reports success back to the project. The check is a green pipeline that produces an artifact visible in the GitLab interface and stored in the expected bucket.
Run backup and restore tests
The team takes a full backup of the instance, including the database, repositories and object storage data, and then restores it into a separate test environment to prove the procedure works end to end. Secrets files are captured separately and the restore is checked for repository access, pipeline history and attachments. Results are documented with timings and any manual steps, so the recovery runbook reflects what was actually tested. The check is a restored test instance that passes the same health checks and a sampled set of projects, issues and artifacts that match the source. Repeat this test after every upgrade and configuration change.
Configuration options and when each fits
This table compares the main layout choices for self-managed GitLab on Google Cloud, from a single VM to a Cloud Native Hybrid setup on GKE. Read each row by asking when the option fits your user count, your team's operating skills and your recovery requirements. The main takeaway is that managed services reduce some operating work but still leave backups, upgrade stops and configuration with your team.
| Option | When it fits | Trade-off | What to confirm in GitLab documentation |
|---|---|---|---|
| Single VM with the Linux package | Small teams with modest load and a team that can run a single Linux host | Bundled PostgreSQL, Redis and Sidekiq share one host, so one failure affects everything and scaling means a larger VM | Installation method and bundled component versions for your GitLab release |
| Cloud SQL for PostgreSQL | Teams that want Google to run the database engine, patching and backups for PostgreSQL | Admin roles, required extensions and supported versions are constrained by the provider, and pg_dump behavior affects backups | Supported PostgreSQL versions per GitLab release and the roles and extensions GitLab needs on managed services |
| Self-managed PostgreSQL on Compute Engine | Teams that need full control over database configuration or a high availability layout they already operate | Your team owns patching, failover, backups and monitoring of the database | Reference architecture guidance for PostgreSQL high availability and the tooling GitLab expects |
| Managed Redis service | Teams that want a managed cache and queue layer separate from the GitLab host | Connection, authentication and TLS settings must be matched to GitLab configuration, and some managed options may not suit every component | Supported Redis versions per GitLab release and whether your chosen service meets the required settings |
| Bundled Redis | Single node or small installs where a separate Redis service adds more work than it removes | Redis fails with the host and scales with it, so recovery depends on the VM | Redis role in the Linux package and when a dedicated Redis is recommended for your user count |
| Google Cloud Storage buckets per object type | Multi-node or larger installs that store artifacts, LFS, uploads, packages and registry data outside the VM | Each data type needs its own bucket and settings, and some types need separate configuration | Consolidated object storage form, which GCS settings GitLab tests, and the data types that still need separate settings |
| Helm chart on GKE in Cloud Native Hybrid pattern | Teams that already run GKE and want stateless components on Kubernetes | Stateful services such as PostgreSQL and Redis must stay on VMs or managed services, so the cluster does not replace them | Cloud Native Hybrid architecture requirements and the reference architecture size that matches your user count |
| Geo secondary site | Organizations that need a warm standby in another region for disaster recovery | Requires a second full environment, continuous synchronization and a tested failover procedure, and Geo is available in Premium and Ultimate | Geo licensing by tier, supported topology in your target region and the failover steps for your version |
Security controls to plan before go-live
These controls decide who can sign in, what the instance can reach, and how sensitive values are stored and changed. Plan them together, because identity, network exposure, IAM and runner isolation each limit the blast radius of the others. Confirm each one in your own project before the first production user signs in.
Choose the sign-in method and provisioning
Decide whether users authenticate through SAML, a generic OAuth 2.0 provider or LDAP, and whether SCIM will deprovision accounts when people leave. Sign-in through your identity provider keeps access tied to your joiner and leaver process rather than to local GitLab passwords. Confirm which providers your identity platform supports and test deprovisioning with a disposable account before go-live.
Scope service account IAM
Give the instance VM, its backup job and any object storage access only the Google Cloud roles each task needs, and bind them to dedicated service accounts rather than default project identities. Restrict bucket access per object type so a compromised component cannot read every data class. Ask your cloud team to document each binding and review it during change control.
Limit network exposure
Open only the ports users and runners need, keep PostgreSQL, Redis and Gitaly reachable from the GitLab nodes alone, and place administrative SSH behind a bastion or an identity-aware path. Check that the Cloud SQL and Redis endpoints are private and not reachable from the internet. Test the firewall rules from outside the project as well as from inside it.
Apply hardening gradually
GitLab's hardening guidance covers application settings, CI/CD, the operating system and NIST SP 800-53 alignment, and GitLab describes it as a work in progress. Start with the application and sign-up settings that affect every user, then roll out operating system and CI/CD controls in stages with a record of each change. Keep a baseline so each stage can be verified and reverted.
Protect secrets and gitlab.rb
The gitlab.rb file and the secrets file hold database credentials, object storage keys and encryption keys that restore depends on. Store them outside the repository, restrict read access to the administrators who need it, and keep an encrypted copy of the secrets file with your backups. Ask who may edit gitlab.rb, how changes are reviewed, and how a lost secrets file would be recovered.
Isolate runners from the instance
Runners execute untrusted pipeline code, so run them on separate Compute Engine VMs or a separate Kubernetes cluster rather than on the GitLab host. Give runner VMs their own service accounts with no access to the GitLab data buckets, and use autoscaling so ephemeral machines are discarded after jobs. Keep the Runner version aligned with GitLab as the Runner documentation advises.
Keeping the instance upgradable and backed up on Google Cloud
Plan upgrades around GitLab's release cadence before the first deployment. GitLab ships a major release yearly, a minor release on the third Thursday of each month and patch releases twice a month, and it maintains the current three minor lines (currently 19.5, 19.4 and 19.3). Bug fixes are backported only to the current stable release, while security fixes also reach the previous two monthly releases. That means a VM that falls behind can miss fixes it needs. Required upgrade stops also apply: since GitLab 17.5 they fall at x.2, x.5, x.8 and x.11, so a jump from 18.1 to 18.6, for example, must pass through 18.2 and 18.5. On Google Cloud, decide who owns the upgrade calendar, how a staging instance is kept on the same version, and whether snapshots are taken before each step. Confirm the current stops in GitLab's upgrade paths documentation before scheduling.
Back up every data store GitLab depends on, then prove the restore works. On a Google Cloud deployment, the database may sit on Cloud SQL, Redis on a managed service, repositories on the instance disk and objects in Google Cloud Storage buckets. A standard GitLab backup task does not cover everything: the secrets file (/etc/gitlab/gitlab-secrets.json), the gitlab.rb configuration, and the object storage buckets each need their own backup path, and the bucket contents must match the metadata in the database. Use Cloud SQL backups and point-in-time recovery for the database, Google Cloud Storage object versioning or replication for buckets, and disk snapshots for repositories. Schedule regular restore tests into a separate project, and record how long a restore took and which steps needed manual work. Confirm the backup procedure for your GitLab version in the GitLab backup and restore documentation.
Put monitoring, health checks and maintenance windows into the operating plan. Upgrades and restores are only as safe as the checks that show the instance is healthy before and after them. Define which health endpoints, logs and Prometheus metrics your team watches, where alerts go, and who responds outside business hours. Document how maintenance mode is entered and exited, and how Cloud Monitoring alerts map to GitLab components. Assign owners for the upgrade calendar, the backup job and restore tests, and the response to a failed patch. Ask your partner or platform team to confirm the monitoring setup against the exact GitLab release you run, since the metrics and log locations change between versions.
Questions teams ask before deploying GitLab on Google Cloud
What drives the cost of deploying self-managed GitLab on Google Cloud?
The cost has three parts: the software licence, the cloud resources and the people who build and run the system. GitLab Free costs 0 US dollars, Premium costs 29 US dollars per user per month billed annually according to GitLab's pricing page, and Ultimate is custom priced. Cloud spend covers compute, Cloud SQL, a managed Redis service, Google Cloud Storage buckets, networking and backups, and it recurs every month. Engineering effort is mostly one-time, but upgrades and support recur. Ask any partner for a quote built from a written scope that lists each component and who pays for it.
Is a single virtual machine enough for GitLab on Google Cloud?
A single VM can serve a small team or a pilot, but it puts every GitLab service on one host, so an outage or a failed upgrade affects everything at once. Larger user counts and heavier CI load move you toward a reference architecture that separates Gitaly, PostgreSQL, Redis and Sidekiq. GitLab recommends a high availability strategy for 3,000 or more users, using Gitaly Cluster with Praefect, PostgreSQL with Patroni, Redis Sentinel and Consul. Confirm the user count, peak API load and CI volume with your team before choosing a topology.
How long does a GitLab deployment on Google Cloud take?
Duration depends on the target topology, how many integrations you need, and how many decisions your team can make quickly. A single-VM setup with default settings takes far less effort than a reference architecture with managed databases, object storage per data type, backup testing and authentication. Migrations from other Git hosts or CI tools add time for repository, issue and pipeline mapping. Agree on a timeline only after a written scope exists, because the scope sets the work. Ask for milestones and the assumptions behind each one.
What does the work need from our own team?
Expect to supply people who can decide, not just approve. You need a named owner for GitLab, access to a Google Cloud project with the right IAM roles, network design input, your identity provider details for SAML, LDAP or OAuth 2.0, and someone who can own DNS, TLS certificates and backup retention rules. Your security team should review hardening settings and the outbound request policy. Engineers who will run upgrades should attend the build so the operating knowledge stays in your organization.
Can our own team deploy GitLab on Google Cloud without a partner?
Yes, many teams do. GitLab publishes installation methods, reference architectures and upgrade paths, so a capable platform team can install the Linux package or the Helm chart and follow the documentation. The harder parts are the ones teams underestimate: choosing the right reference architecture, configuring object storage for each data type, testing restores, planning required upgrade stops and keeping Runners aligned with GitLab versions. Compare the internal hours against those tasks, and consider whether the people who would own the system have the time to do it.
Does GitLab on Google Cloud support Cloud SQL for PostgreSQL?
Confirm this against the current GitLab documentation for your target release before you design around it, because support for managed PostgreSQL services depends on the provider, required extensions, admin roles and the GitLab version. Plan the database layer with Cloud SQL requirements in mind, including the roles GitLab needs, supported PostgreSQL versions and how pg_dump backups will work. Ask the partner to show the documented compatibility for your exact GitLab release and to test a restore from the managed database.
What recurring work follows a GitLab deployment on Google Cloud?
Recurring work includes monthly minor releases, patch releases twice a month, and required upgrade stops at versions x.2, x.5, x.8 and x.11 according to GitLab's upgrade paths. GitLab backports bug fixes only to the current stable release, while security fixes also reach the previous two monthly releases, so your upgrade cadence matters. Other ongoing work covers backup restore tests, certificate renewal, Runner upgrades, Google Cloud cost review, monitoring and access reviews. Ask whether the quote includes a retainer for these tasks or whether your team will own them.
How DeployOpen scopes and delivers a GitLab deployment on Google Cloud
DeployOpen plans, implements, hardens, backs up, documents and supports self-managed GitLab inside your own Google Cloud projects. Engagements start with a written scope that fixes the architecture tier, the managed services and the handover deliverables before any build begins.
How we scope
- We confirm user count, CI load and whether you need a single VM or a multi-node layout with Cloud SQL and Memorystore.
- We record which Google Cloud projects, networks, regions and object storage buckets the deployment will use.
- Engagements are fixed-scope, so the written scope lists deliverables, responsibilities and timelines before work starts.
How we build
- We install GitLab with the method your team has chosen, then configure gitlab.rb, external PostgreSQL, Redis and per-type object storage.
- We set up backups, restore tests and monitoring, and check the reference architecture or sizing against your agreed user and API load.
- We apply the hardening guidance in a staged way, recording each setting and the reason for it in the build record.
How we hand over
- You receive architecture diagrams, configuration documentation, the runbook for upgrades that pass through required upgrade stops, and backup and restore instructions.
- We walk your platform team through restore tests, maintenance mode steps and how to read health checks and logs.
- Handover covers access, credentials ownership and a list of open items agreed with your team in writing.
How we support
- Ongoing support, upgrades and continuous testing are available as retainers, scoped separately from the build.
- Retainers can cover planning for monthly and patch releases and each required upgrade stop on your chosen track.
- Ask us to confirm support terms, response expectations and what the retainer excludes before you sign.

