Self-Hosting Gitlab on Cycle
A walkthrough for deploying GitLab Community Edition on Cycle using theĀ Cycle portal.
End state: a stateful GitLab container running in an isolated environment, addressable over a TLS-terminated hostname, and backing itself up on a schedule.
Prerequisites
You need:
- An account on a Cycle and access to a hub with at least one cluster and one server attached. If you're new to Cycle, run throughĀ Getting StartedĀ first.
- A DNS zone added to the hub. SeeĀ Configuring a DNS Zone.
- A backup destination integration (Backblaze) connected at the hub level if you want automated backups. SeeĀ Configure Backblaze.
- Capacity for GitLab CE's minimum recommended resources: 4 GB RAM, 4 cores. 8 GB+ is comfortable. (Keep in mind that CycleOS and services will take up a few hundred MB of RAM and a bit of CPU).
1. Sign in to the Hub
OpenĀ US portalĀ orĀ EU portalĀ and sign in. Custom-cluster hubs use a different URL ā check with your teams admin.
The left-hand nav is where the rest of this guide happens. The entries you'll use:Ā Images,Ā Environments,Ā DNS,Ā Integrations.
2. Create the image source
An image source tells Cycle where to fetch an image from. Each source can be imported repeatedly to produce point-in-time images, which makes pinning and rollback straightforward.
- Left nav:Ā ImagesĀ āĀ Sources.
- ClickĀ CreateĀ in the top right.
- Fill in:
- Name:Ā
GitLab CE - Source type:Ā Docker Hub
- Target:Ā
gitlab/gitlab-ce:latest, or a pinned tag likeĀgitlab/gitlab-ce:17.5.0-ce.0Ā for reproducibility - The image is public, so no credentials are needed. ClickĀ Create Image Source.
Creating the source doesn't pull anything yet. That happens in the next step.
Docs:Ā Image sourcesĀ Ā·Ā Creating an image source
3. Import the image
On the image source detail page, find theĀ Import ImageĀ button at the top.
Click and holdĀ the button until it triggers. A single click does nothing, this is intentional friction to prevent accidental re-pulls.
Cycle pulls the image, processes it, and the resulting image lands inĀ liveĀ state. It's now selectable when you create a container.
Each import produces a new point-in-time copy. Old copies aren't replaced; they accumulate until you prune them.
Docs:Ā Importing an image
4. Create the environment
An environment is Cycle's network boundary. Containers in the same environment share a private, encrypted network. Containers in different environments don't see each other by default.
- Left nav:Ā EnvironmentsĀ āĀ Create.
- Fill in:
- Name:Ā
gitlab - Cluster:Ā the cluster that should host this environment
- Description:Ā optional
- LeaveĀ Legacy NetworkingĀ off unless you have a specific reason to enable IPv4 inside the private network.
- ClickĀ Create Environment.
Docs:Ā Create an environmentĀ Ā·Ā Introduction to environmentsĀ Ā·Ā Legacy Environments
5. Create the GitLab container (stateful)
From the environment dashboard, clickĀ Deploy ContainerĀ in the top right.
In the deploy wizard:
- Container Name:Ā
gitlab - Stateful:Ā ChooseĀ StatefulĀ from the dropdown, the container needs persistent volumes for config, data, and logs.
- Deployment StrategyĀ can be left as default.
- Image:Ā select the GitLab image you imported in step 3 from theĀ Recent ImagesĀ dropdown.
- Desired Instances:Ā 1
Volumes
GitLab omnibus needs three persistent paths:
Mount path | Size for Demo | Suggested for Production | Purpose |
|---|---|---|---|
| 5 GB | 5 GB | configuration |
| 5 GB | 100 GB+ | repositories, database, attachments, CI artifacts |
| 5 GB | 10 GB | logs |
Network
Mark theĀ Public NetworkĀ setting to enabled for this demo as we will be reaching this container over public networking. Gitlab can be run behind theĀ Cycle VPN serviceĀ if preferred but that configuration is not covered here.
ClickĀ Deploy ContainerĀ to finish the wizard. The container is created but not yet running.
Docs:Ā Deploying a containerĀ Ā·Ā Container volumes
6. Start the environment
From the environment dashboard, clickĀ Start AllĀ in the top right. This boots Discovery and the GitLab container.
Because the Gitlab container has the public network setting of "Enabled", the load balancer will automatically start here. Give it 10-15 seconds to negotiate its IP from the provider.
Docs:Ā Managing containers
7. Verify the container is running
Open the GitLab container from the containers dashboard (environment dashboard - clickĀ ContainersĀ from the horizontal nav), then go to theĀ InstancesĀ tab.
The instance row shows health status. Click into the instance to open theĀ Instance Console, live stdout/stderr from the running process. The first boot takes a few seconds to minutes depending on GitLab's omnibus initialĀ reconfigure.
The container is healthy when:
- Instance state isĀ
running - The console shows GitLab's reconfigure completing without errors
- Requesting the container's internal address returns the GitLab login page
If the instance is stuck inĀ startingĀ or restarting on a loop, check the Instance Console for the actual error. Common causes: under-sized volumes, malformedĀ GITLAB_OMNIBUS_CONFIG, port conflicts.
Docs:Ā Container instances
8. Add a LINKED DNS record
A LINKED record is a Cycle DNS record type that associates a domain with container(s). It resolves to the environment's Load Balancer and can terminate TLS automatically using Let's Encrypt or user uploaded certificates like Cloudflare's Origin certs.
- Left nav:Ā DNSĀ āĀ ZonesĀ ā select your zone.
- ClickĀ Add Record.
- In the wizard:
- Type:Ā LINKED
- Name:Ā the subdomain.Ā
gitlabĀ forĀgitlab.yourdomain.com, orĀ@Ā for the zone apex. - Environment:Ā the environment from step 4
- Link to Container:Ā the GitLab container
- TLS Enabled:Ā ON
- ClickĀ Create.
DNS propagation takes a few minutes. TLS cert generation is rate-limited to 3 certs per domain per hour; if you exceed it, Cycle backs off for an hour before retrying.
Docs:Ā Creating a LINKED recordĀ Ā·Ā DNS records
9. Configure automated backups
Cycle's backup model is command-based, not snapshot-based. The container declares a backup command that writes to stdout and a restore command that reads from stdin. Cycle runs them on a schedule and ships the result to your backup destination.
GitLab's native backup tooling streams cleanly into this model. The canonical commands are:
backup
gitlab-backup create BACKUP=streamed_backup SKIP=registry >/dev/stderr 2>&1 && tar -czf - /etc/gitlab /var/log/gitlab /var/opt/gitlab/backups/streamed_backup_gitlab_backup.tar && rm /var/opt/gitlab/backups/streamed_backup_gitlab_backup.tar restore
tar -xzf - -C && gitlab-ctl stop puma && gitlab-ctl stop sidekiq && gitlab-backup restore BACKUP=streamed_backup force=yes >/dev/stderr && gitlab-ctl reconfigure && gitlab-ctl restart Setup in the Hub:
- Open the GitLab container.
- Go to theĀ BackupsĀ tab.
- Configure:
- Backup command:Ā the streaming backup one-liner from the runbook
- Restore command:Ā the streaming restore one-liner from the runbook
- Schedule:Ā daily is typical. Pick an off-peak hour.
- Destination:Ā the Backblaze integration configured at the hub level
- Save.
The first scheduled run produces a backup. Restores are also done through theĀ BackupsĀ tab ā Cycle pipes the archive into your restore command on stdin.
Restoring doesĀ notĀ restart the container automatically. After a restore, GitLab may needĀ gitlab-ctl reconfigureĀ and a restart.
Docs:Ā Container backups conceptĀ Ā·Ā Backup/restore commandsĀ Ā·Ā Configure Backblaze
Operating notes
A few things worth knowing once GitLab is running:
Resources.Ā GitLab CE is heavy. 4 GB RAM is the floor; 8 GB or more is comfortable. Storage forĀ /var/opt/gitlabĀ grows with the number of repos and CI artifacts.
Upgrades.Ā Re-import the image source to pull a newer Docker Hub tag. The import produces a new image;Ā reimage the containerĀ if needed.
Git over SSH.Ā GitLab's SSH listens on port 22 inside the container. If you want git-over-SSH externally, either remap it viaĀ gitlab_rails['gitlab_shell_ssh_port']Ā inĀ GITLAB_OMNIBUS_CONFIG, or have the Load Balancer expose a different external port.
Backup destination housekeeping.Ā Manage the Backblaze bucket from the Cycle Portal only. Editing or deleting backup files directly in Backblaze de-syncs Cycle's record of what exists.