لماذا GitLab CE بدلًا من GitHub أو Bitbucket
GitHub وBitbucket خدمتان مُدارتان: عمليتان في البداية، لكن نموذج أسعارهما يتطور مع حجم الفريق، ودقائق CI محدودة في الخطط المجانية، وشفرتك مستضافة على بنية تحتية تابعة لجهة خارجية. يعكس GitLab CE هذه المعادلة: تنشر المنصة على VPS الخاص بك، وتحتفظ بالتحكم الكامل في الكود والبيانات، وCI/CD مدمجة دون حصص دقائق مفروضة من طرف ثالث. للوكالات والفرق التي تتعامل مع بيانات حساسة أو تفوتر العملاء، هذا التحكم غير قابل للتفاوض في أغلب الأحيان. GitLab CE هو اليوم أحد أكثر منصات git self-hosted انتشارًا: قاعدة كوده مفتوحة المصدر، ونواته حرة، وعشر سنوات من الوجود جعلت مجتمعه المساهم نشطاً.
ما يتضمنه GitLab CE افتراضيًا
- منصة git كاملة: مستودعات خاصة وعامة، طلبات دمج، مراجعة الكود، حماية الفروع وCODEOWNERS.
- CI/CD مدمجة بلا حد مفروض للدقائق: pipelines بصيغة YAML (
.gitlab-ci.yml)، environments، deploy tokens والـartifacts. - سجل Docker خاص مستضاف على نطاقك:
docker pull git.yourdomain.com/group/image:tagدون حساب Docker Hub. - Wiki وصفحات لكل مشروع ومجموعة، مع عرض Markdown كامل.
- تتبع المشكلات والمراحل: لوحة kanban، تسميات، تكرارات ومخطط burndown مضمّنة.
- Runners متوازية: سجّل أي عدد من الـrunners على بنيتك التحتية أو عمال CI.
- Webhooks لإشعار أداة خارجية (Slack، PagerDuty، خادم النشر) عند كل push أو merge.
- RBAC دقيق بخمسة مستويات وصول (Guest، Reporter، Developer، Maintainer، Owner) ودعم اختياري لـLDAP/SAML.
المتطلبات الأساسية قبل البدء
GitLab CE كثيف الاستهلاك للذاكرة — وهذا من أبرز عيوبه مقارنةً بـForgejo أو Gitea. خطّط لـ4 غيغابايت RAM كحد أدنى للاستخدام الخفيف (أقل من عشرة مستخدمين نشطين)؛ يُوصى بـ8 غيغابايت بمجرد إضافة runners على الجهاز نفسه أو تفعيل سجل Docker. تحت 4 غيغابايت، يتنافس Puma وSidekiq على الذاكرة ويستجيب GitLab بـ502 تحت الحمل. للتخزين، خصص 20 غيغابايت على الأقل للتثبيت والمستودعات الأولية — خطط لـ50 غيغابايت إن كنت ستخزّن صور Docker في السجل. تحتاج أيضًا إلى: اسم نطاق يشير إلى IP الـVPS (مثلاً git.yourdomain.com) لكي تُصدر Let's Encrypt شهادة TLS؛ وفتح المنافذ 80 و443 و22 في جدار الحماية؛ وتثبيت Docker Engine وإضافة Compose v2.
من التثبيت إلى أول مشروع
إنشاء هيكل المجلدات
أنشئ مجلدًا مخصصًا والمجلدات الثلاثة الدائمة التي يستخدمها GitLab:
mkdir -p /opt/gitlab/{config,logs,data}. ستُوصل هذه المجلدات داخل الحاوية؛ دونها تختفي الإعدادات والمستودعات عند كلdocker compose down.كتابة ملف docker-compose.yml
أنشئ
/opt/gitlab/docker-compose.yml. يُركّز مفتاحGITLAB_OMNIBUS_CONFIGكل الإعدادات الخاصة بنسختك — استبدلgit.yourdomain.comبنطاقك الفعلي. عرّف خدمة gitlab بالصورةgitlab/gitlab-ce:17.2.1-ce.0،restart: unless-stopped، اسم المضيف، متغيرات البيئة، المنافذ 80 و443 و22، الـvolumes الثلاثة،shm_size: 256mوenv_file: .env.ضبط GITLAB_OMNIBUS_CONFIG
داخل
GITLAB_OMNIBUS_CONFIG، عرّف على الأقل:external_url 'https://git.yourdomain.com'؛letsencrypt['enable'] = true؛ معاملات SMTP —gitlab_rails['smtp_enable'] = true، العنوان، المنفذ 587، اسم المستخدم، كلمة المرور من ENV، المصادقةlogin،smtp_enable_starttls_auto = true. يجب أن تكون جميع الأسطر داخل كتلةGITLAB_OMNIBUS_CONFIG.إنشاء ملف .env للأسرار
أنشئ
/opt/gitlab/.envوقيّد صلاحياته:touch /opt/gitlab/.env && chmod 600 /opt/gitlab/.env. أضف متغيراتك الحساسة — كحد أدنىGITLAB_SMTP_PASSWORD=كلمة_مرور_smtp.تشغيل GitLab والانتظار حتى اكتمال الإعداد
أطلق الـstack:
docker compose -f /opt/gitlab/docker-compose.yml up -d. انتظر نحو 5 دقائق قبل الوصول إلى واجهة الويب. تابع التقدم بـdocker compose -f /opt/gitlab/docker-compose.yml logs -f gitlabوانتظر رسالةgitlab Reconfigured!.استرداد كلمة مرور root الأولية
استرجع كلمة المرور بـ:
docker exec -it gitlab-gitlab-1 grep 'Password:' /etc/gitlab/initial_root_password. يُحذف هذا الملف تلقائيًا بعد 24 ساعة — دوّن كلمة المرور فورًا.تسجيل الدخول وتغيير كلمة المرور وتعطيل التسجيل المفتوح
افتح
https://git.yourdomain.com. سجّل دخولك بـroot. غيّر كلمة المرور من User Settings → Password. عطّل التسجيل العام: Admin Area → Settings → General → Sign-up restrictions.تسجيل GitLab Runner
ثبّت
gitlab-runnerواسترجع رمز التسجيل من Admin Area → Runners. سجّل الـrunner:gitlab-runner register --url https://git.yourdomain.com --registration-token YOUR_TOKEN --executor docker --docker-image alpine:latest.التحقق من إرسال البريد الإلكتروني
اختبر SMTP من وحدة تحكم Rails:
docker exec -it gitlab-gitlab-1 gitlab-rails consoleثمNotify.test_email('your@email.com', 'Test GitLab', 'Hello').deliver_now.
النسخ الاحتياطي التلقائي. يتضمن GitLab أمر نسخ احتياطي كامل: docker exec -t gitlab-gitlab-1 gitlab-backup create. جدوله في crontab -e بالسطر 0 3 * * * docker exec -t gitlab-gitlab-1 gitlab-backup create CRON=1. زامن مجلد النسخ مع تخزين خارجي (S3، rclone) — النسخة المحلية وحدها ليست نسخةً احتياطية.
إعداد runner Docker وكتابة أول pipeline CI/CD
يُعدّ منفّذ Docker الخيار الموصى به لمعظم المشاريع: يعمل كل job في حاوية معزولة. بعد تسجيل الـrunner، يحتوي ملف /etc/gitlab-runner/config.toml على كتلة [runners.docker]. أضف volumes = ["/cache"] للاحتفاظ بالـcache بين الـbuilds، وpull_policy = ["if-not-present"] لتجنب سحب الصورة في كل job.
مثال pipeline أساسي بـ.gitlab-ci.yml:
stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
test:unit:
stage: test
image: node:20-alpine
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- node_modules/
script:
- npm ci
- npm test
only:
- merge_requests
- main
build:image:
stage: build
image: docker:26
services:
- docker:26-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
only:
- main
deploy:prod:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
script:
- ssh -o StrictHostKeyChecking=no user@yourserver.com "docker pull $DOCKER_IMAGE && docker compose up -d"
only:
- main
when: manualتُحقن المتغيرات CI_REGISTRY_USER وCI_REGISTRY_PASSWORD وCI_REGISTRY تلقائيًا من GitLab CE. أما SSH_PRIVATE_KEY فتُعرَّف في Settings → CI/CD → Variables مع تفعيل Masked. job النشر deploy:prod مضبوط على when: manual — لا يُطلق تلقائيًا.
ضبط إشعارات SMTP بالتفصيل
يُرسل GitLab بريدًا إلكترونيًا عند كل merge request أو ذكر أو pipeline مكتمل أو تنبيه أمني. إعداد SMTP غائب أو خاطئ يقطع هذه الإشعارات في صمت.
الكتلة الكاملة في GITLAB_OMNIBUS_CONFIG لخادم SMTP مصادَق بـSTARTTLS على المنفذ 587:
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'smtp.yourdomain.com'
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = 'gitlab@yourdomain.com'
gitlab_rails['smtp_password'] = ENV['GITLAB_SMTP_PASSWORD']
gitlab_rails['smtp_authentication'] = 'login'
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['gitlab_email_from'] = 'gitlab@yourdomain.com'
gitlab_rails['gitlab_email_reply_to'] = 'noreply@yourdomain.com'إن كان المُرحِّل يشترط TLS مباشر (المنفذ 465)، استبدل smtp_enable_starttls_auto = true بـsmtp_tls = true. المفاتيح خارج كتلة omnibus تُهمَل في صمت — اختبر دائمًا بـNotify.test_email(…).deliver_now من وحدة تحكم Rails.
النسخ الاحتياطي واستعادة GitLab
ينشئ الأمر docker exec -t gitlab-gitlab-1 gitlab-backup create أرشيف tar كاملًا يضم المستودعات وقاعدة بيانات PostgreSQL والـartifacts. تنبيه: لا يشمل الأرشيف ملفَّي /etc/gitlab/gitlab.rb و/etc/gitlab/gitlab-secrets.json — احتفظ بهما بشكل منفصل:
tar czf /opt/gitlab/config-secrets-$(date +%Y%m%d).tar.gz \
/opt/gitlab/config/gitlab.rb \
/opt/gitlab/config/gitlab-secrets.jsonالاستعادة — ثلاث خطوات بالترتيب: ثبّت نفس الإصدار الذي أنتج النسخة؛ انسخ الأرشيف إلى /opt/gitlab/data/backups/؛ ثم:
docker exec -it gitlab-gitlab-1 gitlab-ctl stop puma
docker exec -it gitlab-gitlab-1 gitlab-ctl stop sidekiq
docker exec -it gitlab-gitlab-1 gitlab-backup restore BACKUP=<timestamp>_<version>
docker exec -it gitlab-gitlab-1 gitlab-ctl restart
docker exec -it gitlab-gitlab-1 gitlab-rake gitlab:check SANITIZE=trueجدول النسخ الاحتياطي الكامل ليلًا وزامنه مع تخزين خارجي.
استكشاف الأخطاء: أكثر ثلاث مشكلات شيوعًا
502 Bad Gateway عند الإقلاع. يستغرق GitLab نحو 5 دقائق ليصبح جاهزًا. إن استمر الـ502، تحقق من بدء Puma: docker exec gitlab-gitlab-1 gitlab-ctl status puma. نقص الذاكرة هو السبب الأكثر شيوعًا. SMTP لا يعمل. تحقق أولًا: هل كتلة gitlab_rails['smtp_*'] داخل GITLAB_OMNIBUS_CONFIG؟ مفتاح خارج الكتلة يُهمَل في صمت. Runner غير متصل. تحقق بـgitlab-runner verify --url https://git.yourdomain.com. شهادة TLS موقّعة ذاتيًا أو نطاق غير قابل للحل هما السببان المعتادان.
استكشاف متقدم: Sidekiq متوقف وPuma timeout وOOM على Gitaly
Sidekiq queue stuck. تحقق من الحالة:
docker exec gitlab-gitlab-1 gitlab-ctl status sidekiq
docker exec gitlab-gitlab-1 gitlab-rake gitlab:sidekiq:checkلتفريغ قائمة انتظار بعينها: docker exec -it gitlab-gitlab-1 gitlab-rails console -e production ثم Sidekiq::Queue.new('mailers').clear. لإعادة تشغيله دون فقدان الـjobs المعلّقة: docker exec gitlab-gitlab-1 gitlab-ctl restart sidekiq.
Puma timeout. أضف في GITLAB_OMNIBUS_CONFIG: puma['worker_timeout'] = 90 (الافتراضي 60 ثانية). إن استمرت الـtimeouts، السبب في الغالب نقص RAM أو عدد workers غير ملائم.
OOM على Gitaly. تحقق بـdmesg | grep -i kill. قلّل الـcache: gitaly['configuration']['git']['catfile_cache_size'] = 5 (الافتراضي 100).
حاوية تخرج فور الإقلاع. راجع السجلات: docker compose logs gitlab | tail -50. الأسباب الشائعة: تعارض المنفذ 22، volume غير قابل للكتابة، أو صيغة Ruby خاطئة في GITLAB_OMNIBUS_CONFIG.
تحسين استخدام RAM: الـswap وعمال Puma
تقليل عمال Puma. في GITLAB_OMNIBUS_CONFIG:
puma['worker_processes'] = 2
puma['min_threads'] = 1
puma['max_threads'] = 4كل عامل Puma يستهلك 200 إلى 300 ميغابايت. عاملان يكفيان لأقل من خمسة عشر مستخدمًا نشطًا.
إضافة swap. على VPS بلا swap:
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstabتوصيات RAM وCPU حسب حجم الفريق
| حجم الفريق | RAM موصى بها | vCPU | ملاحظات |
|---|---|---|---|
| 1–5 مطورين | 4 غيغابايت | 2 | Runners على الجهاز ذاته ممكنة مع swap |
| 5–15 مطورًا | 8 غيغابايت | 4 | Runner مخصص منصوح به فوق 8 pipelines/يوم |
| 15–30 مطورًا | 16 غيغابايت | 8 | سجل Docker نشط، Gitaly تحت الحمل |
| 30+ مطورًا | 32 غيغابايت+ | 16+ | فصل Gitaly وSidekiq على أجهزة مخصصة |
GitLab CE أو Forgejo أو Gitea: كيف تختار
مرّر الجدول أفقيًا
| المعيار | GitLab CE | Forgejo / Gitea |
|---|---|---|
| الرخصة | MIT / EE Core | MIT |
| ذاكرة الخمول | 300–600 ميغابايت (Puma + Sidekiq) | 30–50 ميغابايت |
| CI/CD أصيلة | نعم (`.gitlab-ci.yml`، runners) | Forgejo: نعم عبر Woodpecker CI؛ Gitea: لا يوجد |
| سجل Docker مدمج | نعم | Forgejo: نعم؛ Gitea: غير أصيل |
| Wiki لكل مشروع | نعم | نعم |
| LDAP / SAML | نعم (CE) | Forgejo: نعم؛ Gitea: LDAP نعم، SAML لا |
| منحنى التعلم | مرتفع (واجهة غنية) | منخفض إلى متوسط |
| الأنسب لـ | فرق 5+ تحتاج CI وسجل Docker وRBAC | فرق خفيفة، منصة بسيطة، بصمة RAM منخفضة |
متى تختار GitLab CE ومتى تختار Forgejo
GitLab CE هو الاختيار الصحيح إن احتاج فريقك إلى CI/CD قوية مدمجة مباشرةً في المنصة، وسجل Docker خاص على نطاقك، وpipelines نشر مع environments، أو إدارة مشاريع بمشكلات ومراحل ولوحة kanban دون أداة خارجية. بصمته الذاكرية (4–8 غيغابايت) هي ثمن هذا الثراء الوظيفي. Forgejo أو Gitea هما الخيار حين تكون الذاكرة القيد الرئيسي، وحين المنصة هي الحاجة الوحيدة (دون CI مدمجة). على VPS بـ2 غيغابايت، GitLab CE غير قابل للتطبيق؛ Forgejo يعمل بـ256 ميغابايت. على VPS بـ8 غيغابايت مخصص لفريق تطوير، يوفر GitLab CE بيئة كاملة تضعها GitHub على منصتها SaaS — تحت سيطرتك ودون اشتراك شهري بحسب عدد المستخدمين.