GitLab Helm Chart Tutorial: Step-by-Step Guide
Deploying GitLab on Kubernetes using the official Helm chart provides a robust, scalable, and manageable solution. This tutorial provides a comprehensive, step-by-step guide to deploying GitLab using Helm, covering everything from prerequisites to advanced configuration and troubleshooting. We’ll focus on a practical, working deployment, explaining the choices made along the way.
1. Prerequisites:
Before you begin, ensure you have the following:
- A running Kubernetes cluster: This could be Minikube, Kind, a managed Kubernetes service (like GKE, EKS, or AKS), or a self-managed cluster. You should have
kubectl
configured to access your cluster. This tutorial assumes you have a cluster with at least 4 vCPUs and 8GB of RAM available for the GitLab deployment (although you can scale it down, especially for testing). More resources are generally better, especially for larger deployments. - Helm v3 installed: Check with
helm version
. If not installed, follow the official Helm installation instructions for your operating system (https://helm.sh/docs/intro/install/). - Persistent Volume Provisioner: Your Kubernetes cluster needs a way to provision Persistent Volumes (PVs). Most managed Kubernetes services provide this out of the box. If using Minikube, you’ll need to ensure the
default
storage class is configured (it usually is). You can check withkubectl get storageclass
. -
Ingress Controller (Recommended): While not strictly required, an Ingress Controller (like Nginx Ingress, Traefik, or Istio) makes exposing GitLab to the outside world much easier. This tutorial will use Nginx Ingress as an example, but you can adapt it to your preferred controller. If you don’t have one, install it before deploying GitLab:
bash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace \
--set controller.replicaCount=2 \
--set controller.nodeSelector."kubernetes\.io/os"=linux # Adjust for your OS -
DNS Record (Recommended): If you want to access GitLab via a domain name (e.g.,
gitlab.example.com
), you’ll need to create a DNS record that points to the external IP address of your Ingress Controller. This external IP can be obtained after the Ingress Controller is installed (usingkubectl get svc -n ingress-nginx
, look for theEXTERNAL-IP
of the service of typeLoadBalancer
).
2. Adding the GitLab Helm Repository:
First, add the official GitLab Helm repository:
bash
helm repo add gitlab https://charts.gitlab.io/
helm repo update
3. Creating a Custom values.yaml
file:
The GitLab Helm chart is highly configurable. While you can deploy with default settings, it’s strongly recommended to create a custom values.yaml
file to tailor the deployment to your needs. This is crucial for production deployments.
Create a file named values.yaml
. Here’s a well-commented example, explaining key options. Start with this, then modify as needed:
“`yaml
values.yaml
global:
# — General GitLab Settings —
hosts:
domain: example.com # REPLACE with your domain name
externalIP: # Optional: If you have a static IP, specify it here. Otherwise, leave blank to use the Ingress Controller’s IP.
https: true # Enable HTTPS
gitlab:
name: gitlab # Subdomain for GitLab itself (gitlab.example.com)
registry:
name: registry # Subdomain for the Container Registry (registry.example.com)
minio:
enabled: true # Use MinIO for object storage (recommended for ease of setup)
name: minio # Subdomain for MinIO (minio.example.com)
ingress:
enabled: true # Enable Ingress
configureCertmanager: false # Set to true if you have cert-manager installed and want it to handle certificates.
annotations:
kubernetes.io/ingress.class: “nginx” # Use Nginx Ingress (change if using a different Ingress controller)
# Add other Ingress annotations as needed (e.g., for TLS configuration)
tls:
enabled: true # Enable TLS
secretName: gitlab-tls # Name of the TLS secret (will be created if configureCertmanager is false)
# — Resource Limits and Requests —
# Adjust these based on your cluster resources and expected load. These are examples.
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 250m
memory: 512Mi
# — Storage Settings —
# Use persistent volumes. Adjust size and storage class as needed.
storage:
size: 10Gi # Size of the persistent volume for GitLab data
storageClass: default # Use the default storage class (change if needed)
— Component Specific Configurations —
GitLab (Gitaly, Workhorse, Shell, etc.)
gitlab:
gitaly:
persistence:
size: 10Gi # Persistent volume size for Gitaly (Git repositories)
storageClass: default
webservice:
ingress:
enabled: true # Enable Ingress for the GitLab web interface
# Annotations and TLS settings inherited from global.ingress
minReplicas: 1 # Minimum number of replicas for the web service
maxReplicas: 2 # Maximum number of replicas
gitlab-shell:
minReplicas: 1 # Minimum number of replicas for GitLab Shell (SSH access)
maxReplicas: 2 # Maximum number of replicas
sidekiq:
minReplicas: 1
maxReplicas: 2
toolbox:
backups:
cron:
enabled: true # Enable automatic backups
schedule: “0 0 * * *” # Run backups daily at midnight (adjust as needed)
persistence:
enabled: false #Toolbox don’t require persistence.
storageClass: null
Registry
registry:
enabled: true # Enable the Container Registry
ingress:
enabled: true # Enable Ingress for the Registry
# Annotations and TLS settings inherited from global.ingress
hpa:
minReplicas: 1 # Minimum number of replicas for the Registry
maxReplicas: 2 # Maximum number of replicas
persistence:
enabled: true
size: 10Gi # Persistent volume size for the Registry
storageClass: default
MinIO (Object Storage)
minio:
enabled: true # Enable MinIO for object storage
ingress:
enabled: true # Enable Ingress for MinIO
# Annotations and TLS settings inherited from global.ingress
persistence:
enabled: true
size: 10Gi # Persistent volume size for MinIO
storageClass: default
Prometheus (Monitoring – Optional but Recommended)
prometheus:
install: true # Install Prometheus for monitoring GitLab
# Configure Prometheus as needed
Cert-Manager Integration (Optional – Requires cert-manager)
If configureCertmanager is true in global.ingress, configure issuer here.
certmanager:
install: false # Don’t install cert-manager with GitLab (install it separately if needed).
issuers:
email: [email protected] # REPLACE with your email address for Let’s Encrypt
server: https://acme-v02.api.letsencrypt.org/directory # Let’s Encrypt ACME server
privateKeySecretRef: letsencrypt-prod # Name of the secret to store the Let’s Encrypt private key
solvers:
– http01:
ingress:
class: nginx # Use Nginx Ingress for the HTTP-01 challenge
— PostgreSQL (Database) —
By default, GitLab Chart includes a PostgreSQL instance. You can use an external database instead.
postgresql:
install: true # Install the included PostgreSQL instance
persistence:
enabled: true
size: 10Gi # Persistent volume size for PostgreSQL
storageClass: default
# Configure PostgreSQL as needed (e.g., authentication, resource limits)
— Redis —
GitLab Chart includes a Redis instance.
redis:
install: true # Install included Redis.
cluster:
enabled: false # We don’t need a Redis cluster for a basic setup.
slaveCount: 1
persistence:
enabled: true
size: 2Gi # Persistent volume size for Redis
storageClass: default
“`
Key Points about values.yaml
:
global.hosts.domain
: This is critical. Set it to your domain name.global.hosts.https
: Enable HTTPS (recommended).global.ingress
: Configure Ingress. The example uses Nginx Ingress.global.ingress.tls
: Enable TLS (HTTPS). IfconfigureCertmanager
isfalse
, you’ll need a TLS certificate and key (discussed later).global.resources
: Adjust resource requests and limits to match your cluster’s capacity. Start small and scale up as needed.global.storage
: Configure persistent volume sizes. 10Gi is a reasonable starting point, but adjust based on your expected usage.gitlab.toolbox.backups.cron.enabled
: Enabling scheduled backups is highly recommended. Adjust theschedule
as needed.postgresql.install
andredis.install
: These control whether to install the bundled PostgreSQL and Redis instances. For a simple setup, leave them astrue
. For larger deployments, consider using external managed databases.minio.enabled
: MinIO acts as the default object storage, handling uploads and artifacts.
4. Installing GitLab:
Now, install GitLab using the values.yaml
file:
bash
helm install gitlab gitlab/gitlab -n gitlab --create-namespace -f values.yaml
* helm install gitlab ...
: This installs the chart, naming the release gitlab
.
* -n gitlab
: Specifies the namespace to install GitLab into (recommended for organization).
* --create-namespace
: Creates the namespace if it doesn’t exist.
* -f values.yaml
: Specifies the custom values.yaml
file.
5. Monitoring the Installation:
The installation can take several minutes (10-20 minutes is common). Monitor the progress:
bash
kubectl get pods -n gitlab -w
Wait until all pods are in the Running
or Completed
state. You can also check the status of individual deployments:
bash
kubectl get deployments -n gitlab
And services:
bash
kubectl get svc -n gitlab
6. Obtaining the Initial Root Password:
GitLab generates a random initial root password. Retrieve it:
bash
kubectl get secret -n gitlab gitlab-gitlab-initial-root-password -o jsonpath='{.data.password}' | base64 -d ; echo
This command retrieves the secret, decodes it from base64, and prints it to the console. Copy this password immediately and store it securely! You’ll need it to log in for the first time.
7. Accessing GitLab:
Once everything is running, access GitLab in your browser:
- With Ingress: If you configured Ingress, navigate to
https://gitlab.example.com
(replace with your domain). -
Without Ingress (port-forwarding): If you didn’t use Ingress (not recommended for production), you can use port forwarding for temporary access:
bash
kubectl port-forward -n gitlab svc/gitlab-webservice-default 8080:80Then access GitLab at
http://localhost:8080
. This is only for testing; do not use port forwarding in production.
8. First Login and Initial Configuration:
- Log in using the username
root
and the initial root password you obtained earlier. - Immediately change the root password! Go to your profile settings (click on your avatar in the top right) and change the password.
- Configure any other initial settings you need (e.g., email settings, user registration settings).
9. TLS Certificate (Without cert-manager):
If you set global.ingress.configureCertmanager
to false
in your values.yaml
, you need to provide a TLS certificate and key. Here’s how:
-
Obtain a TLS certificate and key: You can use Let’s Encrypt (recommended) or another certificate authority. For Let’s Encrypt, you can use
certbot
:bash
sudo certbot certonly --manual --preferred-challenges dns -d gitlab.example.com -d registry.example.com -d minio.example.com
Follow the instructions to verify your domain ownership (usually by adding a TXT record to your DNS). This will generate the certificate and key files.
2. Create a Kubernetes Secret: Create a secret containing the certificate and key:bash
kubectl create secret tls -n gitlab gitlab-tls \
--cert=/path/to/fullchain.pem \
--key=/path/to/privkey.pemReplace
/path/to/fullchain.pem
and/path/to/privkey.pem
with the actual paths to your certificate and key files. ThesecretName
in yourvalues.yaml
(e.g.,gitlab-tls
) must match the name of the secret you create here.
10. Using cert-manager (Recommended):
If you have cert-manager installed, setting global.ingress.configureCertmanager
to true
and configuring the certmanager
section in your values.yaml
(as shown in the example) will automate certificate issuance and renewal. Make sure you have installed and configured cert-manager before deploying GitLab. You’ll need to create a ClusterIssuer
or Issuer
resource. The values.yaml
example shows how to define an issuer.
11. Upgrading GitLab:
To upgrade GitLab to a newer version:
- Update the Helm repository:
bash
helm repo update - Check for available upgrades:
bash
helm search repo gitlab/gitlab - Backup your GitLab data! (See next section).
- Upgrade using
helm upgrade
:
bash
helm upgrade gitlab gitlab/gitlab -n gitlab -f values.yaml
This will upgrade the release to the latest version. You can specify a specific version using--version <version>
. - Monitor the pods as described above in step 5 to confirm they are running as expected.
12. Backups and Restore:
Regular backups are essential. GitLab provides built-in backup utilities.
- Automatic Backups (Recommended): The
values.yaml
example enables automatic backups using the GitLab Toolbox. These backups are stored in object storage (MinIO in this example). - Manual Backups: You can create manual backups using the GitLab Toolbox:
bash
kubectl exec -it -n gitlab $(kubectl get pods -n gitlab -l app=toolbox -o jsonpath='{.items[0].metadata.name}') -- backup-utility - Restore: To restore from a backup, you’ll generally need to:
- Deploy a new, empty GitLab instance.
- Stop the relevant services (Sidekiq, Puma/Unicorn).
- Use the
backup-utility
with the--restore
flag and the backup ID:
bash
kubectl exec -it -n gitlab $(kubectl get pods -n gitlab -l app=toolbox -o jsonpath='{.items[0].metadata.name}') -- backup-utility --restore -t <backup_id> - Restart the services.
13. Scaling GitLab:
You can scale GitLab components horizontally by adjusting the minReplicas
and maxReplicas
values in your values.yaml
file and then running helm upgrade
. For example, to scale the web service:
yaml
gitlab:
webservice:
minReplicas: 2 # Increase from 1 to 2
maxReplicas: 4 # Increase from 2 to 4
Then run:
bash
helm upgrade gitlab gitlab/gitlab -n gitlab -f values.yaml
14. Troubleshooting:
- Check pod logs: Use
kubectl logs -n gitlab <pod_name>
to examine the logs of a specific pod. Add-f
to follow the logs in real time. - Describe pods and deployments: Use
kubectl describe pod -n gitlab <pod_name>
andkubectl describe deployment -n gitlab <deployment_name>
to get detailed information about pods and deployments, including events and errors. - Check service status: Use
kubectl get svc -n gitlab
to check the status of services. - GitLab Rake tasks: For GitLab-specific issues, you can often use Rake tasks. These are run inside the
gitlab-task-runner
pod:
bash
kubectl exec -it -n gitlab $(kubectl get pods -n gitlab -l app=task-runner -o jsonpath='{.items[0].metadata.name}') -- gitlab-rake <rake_task>
For example,gitlab-rake gitlab:check
performs various checks. Consult the GitLab documentation for available Rake tasks. - Review GitLab Documentation: The official GitLab documentation is a comprehensive resource for troubleshooting: https://docs.gitlab.com/
15. Using an External Database (PostgreSQL and Redis):
For production deployments, using external managed databases (like AWS RDS for PostgreSQL or ElastiCache for Redis) is often preferable for scalability, reliability, and ease of management. To use external databases:
1. Provision the external databases. Create your PostgreSQL and Redis instances. Note the connection details (host, port, username, password, database name).
-
Modify your
values.yaml
:“`yaml
postgresql:
install: false # Disable the bundled PostgreSQLredis:
install: false # Disable the bundled Redisglobal:
psql:
host: your-postgresql-host # REPLACE
port: 5432 # REPLACE (if different)
database: gitlabhq_production # Or your chosen database name
username: your-postgresql-user # REPLACE
password: your-postgresql-password # REPLACE
redis:
host: your-redis-host # REPLACE
port: 6379 # REPLACE (if different)
password: your-redis-password #REPLACE. Use “” for none.
“`
3. Create Kubernetes secrets (optional but recommended):bash
kubectl create secret generic -n gitlab gitlab-postgresql-secret \
--from-literal=password='your-postgresql-password'
kubectl create secret generic -n gitlab gitlab-redis-secret \
--from-literal=password='your-redis-password'
You can then reference them invalues.yaml
viapassword.secret
andpassword.key
. -
Re-deploy GitLab:
bash
helm upgrade gitlab gitlab/gitlab -n gitlab -f values.yaml
This comprehensive guide provides a solid foundation for deploying and managing GitLab using Helm. Remember to adapt the configurations to your specific requirements and consult the official GitLab documentation for more advanced options and troubleshooting. Good luck!