Prepare Postgres for Gitlab
# --- CONFIGURATION ---
NAMESPACE="databases-prod"
POD_NAME="postgres-0" # Change to your actual postgres pod name
DB_NAME="gitlabhq_production"
DB_USER="gitlab"
# Use single quotes to handle special characters like $ or @
DB_PASS='gitlab-db-password'
echo "Checking if database $DB_NAME exists..."
# Execute SQL inside the pod
kubectl exec -i $POD_NAME -n $NAMESPACE -- psql -U postgres -d template1 <<EOF
-- Create User if not exists
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '$DB_USER') THEN
CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';
END IF;
END
$$;
-- Create Database
SELECT 'CREATE DATABASE $DB_NAME OWNER $DB_USER'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DB_NAME')gexec
-- Grant Permissions
GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;
ALTER ROLE $DB_USER WITH LOGIN CREATEDB;
-- Connect to new DB to add extensions
c $DB_NAME
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE EXTENSION IF NOT EXISTS plpgsql;
-- Ensure gitlab user has schema permissions
GRANT ALL ON SCHEMA public TO $DB_USER;
EOF
Generate keys and secret for gitlab-shell
# Generate keys and generate secret for gitlab-shell
mkdir -p ./keys
ssh-keygen -q -N "" -t rsa -f ./keys/ssh_host_rsa_key
ssh-keygen -q -N "" -t ecdsa -f ./keys/ssh_host_ecdsa_key
ssh-keygen -q -N "" -t ed25519 -f ./keys/ssh_host_ed25519_key
# Force update the secret
kubectl create secret generic gitlab-gitlab-shell-host-keys
--from-file=ssh_host_rsa_key=./keys/ssh_host_rsa_key
--from-file=ssh_host_ecdsa_key=./keys/ssh_host_ecdsa_key
--from-file=ssh_host_ed25519_key=./keys/ssh_host_ed25519_key
-n devops-prod --dry-run=client -o yaml | kubectl apply -f -
rm -rf ./keys
The Codes
# infrastructure/devops/gitlab/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- traefik-ingressroute.yaml
helmCharts:
- name: gitlab
repo: "https://charts.gitlab.io"
version: 9.11.2
releaseName: gitlab
valuesFile: gitlab-values.yaml
includeCRDs: true
# infrastructure/devops/gitlab/base/gitlab-values.yaml
# Disable all heavy/internal features
installCertmanager: false
gitlab-runner: { install: false }
traefik: { install: false }
gitlab-zoekt: { install: false }
openbao: { install: false }
ai-gateway: { install: false }
postgresql: { install: false }
redis: { install: false }
grafana: { enabled: false }
gitlab-exporter: { enabled: false }
metrics: { enabled: false }
registry: { enabled: false }
certmanager-issuer: { enabled: false }
upgradeCheck: { enabled: false }
certmanager: { installCRDs: false }
nginx-ingress: { enabled: false }
nginx-ingress-geo: { enabled: false }
haproxy: { install: false }
prometheus: { install: false }
global:
edition: ce
application: { create: false }
shell: { concurrency: 1 }
keda: { enabled: false }
monitoring: { enabled: false }
minio: { enabled: true }
serviceAccount: { enabled: false }
openbao: { enabled: false }
geo: { enabled: false }
workspaces: { enabled: false }
spamcheck: { enabled: false }
registry: { enabled: false }
# Ensure the application doesn't try to load every feature
extraEnv: { GITLAB_CONTINUATION_ADVISOR: "true" }
hosts:
domain: example.com
https: false
# Disable Rails bootsnap cache (temporary)
rails:
bootsnap:
enabled: true
# Disable internal Ingress/Cert-Manager (use external Traefix/Cert-Manager)
ingress:
enabled: false
configureCertmanager: false
useNewIngressForCerts: false
tls:
enabled: false
secretName: wildcard-example-com-tls
# Database (External PostgreSQL)
psql:
host: postgres.databases-prod.svc.cluster.local
port: 5432
database: gitlabhq_production
username: gitlab
password:
secret: gitlab-auth
key: POSTGRES_PASSWORD
# Redis (External Redis)
redis:
host: redis.databases-prod.svc.cluster.local
port: 6379
auth:
enabled: true
secret: gitlab-auth
key: REDIS_PASSWORD
gitaly:
enabled: true
service:
name: gitaly
type: ClusterIP
externalPort: 8075
internalPort: 8075
tls:
externalPort: 8076
internalPort: 8076
tls:
enabled: false
secretName: wildcard-example-com-tls
## Rails based portions of this chart share many settings
appConfig:
relativeUrlRoot: ""
enableUsagePing: true
enableSeatLink: true
enableImpersonation:
applicationSettingsCacheSeconds: 60
usernameChangingEnabled: true
issueClosingPattern:
defaultProjectsFeatures:
issues: true
mergeRequests: true
wiki: true
snippets: true
builds: true
contentSecurityPolicy:
enabled: false
report_only: true
object_store: { enabled: false }
microsoft_graph_mailer: { enabled: false }
incomingEmail: { enabled: false }
serviceDeskEmail: { enabled: false }
ldap: { preventSignin: false }
duoAuth: { enabled: false }
knowledgeGraph: { enabled: false }
iamAuthService: { enabled: false }
cell: { enabled: false }
omniauth: { enabled: false }
kerberos: { enabled: false }
sentry: { enabled: false }
gitlab_docs: { enabled: false }
smartcard: { enabled: false }
gitlab_kas: { enabled: true }
pages:
enabled: false
accessControl: false
# SMTP Configuration
smtp:
enabled: true
address: smtp.gmail.com
port: 587
user_name:
secret: gitlab-auth
key: SMTP_USERNAME
password:
secret: gitlab-auth
key: SMTP_PASSWORD
domain: example.com
authentication: login
starttls_auto: true
email:
display_name: admin@GitLab
from: example@gmail.com
reply_to: admin@example.com
subject_suffix: " | Company"
time_zone: 'Australia/Sydney'
webservice: { workerTimeout: 60 }
workhorse:
serviceName: webservice-default
tls:
enabled: false
kas:
enabled: true
service:
apiExternalPort: 8153
tls:
enabled: false
verify: true
secretName: wildcard-example-com-tls
## End of global
shared-secrets:
enabled: true
minio:
install: true
ingress:
tls:
enabled: false
secretName: wildcard-example-com-tls
persistence:
enabled: true
storageClass: "rook-ceph-block-external-retain"
accessMode: ReadWriteOnce
size: 10Gi
resources:
requests:
memory: 64Mi
cpu: 10m
# Fine-tuning Web and Background workers
gitlab:
webservice:
tests:
enabled: false
test-runner:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
workerProcesses: 2
minReplicas: 1
maxReplicas: 1
service:
type: ClusterIP
ingress:
enabled: false
tls:
enabled: false
secretName: wildcard-example-com-tls
resources:
requests:
cpu: 200m
memory: 1.5Gi
limits:
cpu: 1000m
memory: 2.5Gi
workhorse:
resources:
limits:
memory: 100M
requests:
cpu: 10m
memory: 10M
sidekiq:
concurrency: 5
minReplicas: 1
maxReplicas: 1
resources:
requests:
cpu: 100m
memory: 750Mi
limits:
cpu: 500m
memory: 1.5Gi
toolbox:
replicas: 1
persistence:
enabled: true
storageClass: "rook-ceph-block-external-retain"
accessMode: ReadWriteOnce
size: 5Gi
antiAffinityLabels:
matchLabels:
app: gitaly
gitaly:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
persistence:
enabled: true
storageClass: "rook-ceph-block-external-retain"
accessMode: ReadWriteOnce
size: 10Gi
resources:
requests:
cpu: 100m
memory: 500Mi
limits:
cpu: 500m
memory: 1.5Gi
gitlab-shell:
minReplicas: 1
maxReplicas: 1
tests:
enabled: false
service:
externalPort: 10022
resources:
limits:
memory: 200Mi
# infrastructure/devops/gitlab/overlay/prod/kustomize.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: devops-prod
resources:
- namespace.yaml
- ../../base
labels:
- includeSelectors: true
includeTemplates: true
pairs:
app.kubernetes.io/name: gitlab
app.kubernetes.io/component: devops
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/instance: prod-instance
env: prod
app: gitlab
commonAnnotations:
owner: "Owner"
team.contact: "team@example.com"
runbook.url: "https://example.com"
deployment.priority: "high"
last-updated-by: "Owner"
secretGenerator:
- name: gitlab-auth
envs:
- .env.prod.secrets
generatorOptions:
disableNameSuffixHash: true
# infrastructure/devops/gitlab/overlay/prod/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: devops-prod
Install with Kustomize
kustomize build infrastructure/devops/gitlab/overlays/prod --enable-helm | kubectl apply -f -