GitLab Helm Chart Tutorial: Step-by-Step Guide

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 with kubectl 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 (using kubectl get svc -n ingress-nginx, look for the EXTERNAL-IP of the service of type LoadBalancer).

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). If configureCertmanager is false, 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 the schedule as needed.
  • postgresql.install and redis.install: These control whether to install the bundled PostgreSQL and Redis instances. For a simple setup, leave them as true. 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:80

    Then access GitLab at http://localhost:8080. This is only for testing; do not use port forwarding in production.

8. First Login and Initial Configuration:

  1. Log in using the username root and the initial root password you obtained earlier.
  2. Immediately change the root password! Go to your profile settings (click on your avatar in the top right) and change the password.
  3. 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:

  1. 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.pem

    Replace /path/to/fullchain.pem and /path/to/privkey.pem with the actual paths to your certificate and key files. The secretName in your values.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:

  1. Update the Helm repository:
    bash
    helm repo update
  2. Check for available upgrades:
    bash
    helm search repo gitlab/gitlab
  3. Backup your GitLab data! (See next section).
  4. 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>.
  5. 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:
    1. Deploy a new, empty GitLab instance.
    2. Stop the relevant services (Sidekiq, Puma/Unicorn).
    3. 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>
    4. 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> and kubectl 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).

  1. Modify your values.yaml:

    “`yaml
    postgresql:
    install: false # Disable the bundled PostgreSQL

    redis:
    install: false # Disable the bundled Redis

    global:
    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 in values.yaml via password.secret and password.key.

  2. 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!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top