# Deploying GitLab CE on Kubernetes: A Step-by-Step Guide

Deploying GitLab CE on Kubernetes can be achieved using both Helm charts and manual manifests. This guide will walk you through the process step-by-step, ensuring that you have a functioning GitLab CE instance. We will focus on creating a ConfigMap, setting up a Deployment, exposing it via a Service, and finally, binding a domain with an Ingress.

### ConfigMap

First, you need to create a ConfigMap that will be used as the core GitLab file `/etc/gitlab/gitlab.rb`. I will disable many internal tools and modules to make the core GitLab UI function as a Git server.

Please note that, you will also require a persistent PostgreSQL database connection parameters.

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: gitlab-config
data:
  EXTERNAL_URL: https://gitlab.example.com
  GITLAB_OMNIBUS_CONFIG: |
    # disable heavy features
    postgresql['enable'] = false
    registry['enable'] = false
    redis['enable'] = false
    nginx['enable'] = false
    logrotate['enable'] = false
    gitlab_kas['enable'] = false
    monitoring_role['enable'] = false
    prometheus['enable'] = false
    alertmanager['enable'] = false
    node_exporter['enable'] = false
    redis_exporter['enable'] = false
    postgres_exporter['enable'] = false
    gitlab_exporter['enable'] = false
    prometheus_monitoring['enable'] = false
    grafana['enable'] = false

    # web    
    gitlab_workhorse['listen_network'] = "tcp"
    gitlab_workhorse['listen_addr'] = "0.0.0.0:8181"
    
    # timezone
    gitlab_rails['time_zone'] = 'Asia/Dhaka'

    # database
    gitlab_rails['db_database'] = 'db_gitlab'
    gitlab_rails['db_username'] = 'user_gitlab'
    gitlab_rails['db_password'] = '0987abcd1234wxyz'
    gitlab_rails['db_host'] = '10.10.10.1'
    gitlab_rails['db_port'] = 5432
```

### Deployment

Now we will create a deployment that will use the ConfigMap mentioned above. As you can see, I have added three extra volumes to persistently store the `etc`, `log`, and `data` directories. This is very important; otherwise, you will lose all your data every time you restart the pod. You are welcome to use any other volume type like `hostPath`, `glusterfs`, `nfs`, etc.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: gitlab
  name: gitlab
spec:
  selector:
    matchLabels:
      app: gitlab
  template:
    metadata:
      labels:
        app: gitlab
    spec:
      containers:
      - envFrom:
        - configMapRef:
            name: gitlab-config
        image: gitlab/gitlab-ce
        name: app
        ports:
        - containerPort: 8181
          name: http
        volumeMounts:
        - mountPath: /etc/gitlab
          name: etc
        - mountPath: /var/opt/gitlab
          name: data
        - mountPath: /var/log/gitlab
          name: log
      volumes:
      - name: etc
        hostPath:
          path: /etc
      - name: data
        hostPath:
          path: /data
      - name: log
        hostPath:
          path: /var/log
```

### Service

Once the pods are up and running, we need to expose the Deployment as a Service. You will notice that we have exposed port `8181` of the containers to forward web traffic to Gitlab `workhorse`.

```yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: gitlab
  name: gitlab
spec:
  ports:
    - name: http
      port: 8181
      targetPort: 8181
  selector:
    app: gitlab
```

### Ingress

Finally, you need to bind a domain with the ingress.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gitlab
spec:
  rules:
    - host: gitlab.example.com
      http:
        paths:
          - path: /
            backend:
              serviceName: gitlab
              servicePort: http
  tls:
    - hosts:
        - gitlab.example.com
      secretName: example-com-ssl
```
