Login Logout

Howto GitLab

GitLab est un logiciel libre de gestion de développement de logiciels (appelé souvent une forge) permettant de créer des projets avec un dépôt Git pour le code source, un outil de tickets, un wiki, une collaboration autour de Git (merge/pull requests, etc.). GitLab ressemble sous certains aspects au logiciel propriétaire Github.

Installation

Nous installons la version 9 sous Debian 8 (Jessie) avec une approche multi-instances.

GitLab s’appuie sur Git, Ruby, Go, NodeJS, PostgreSQL et Redis.

Note : dans les exemples ci-dessous, on va créer une instance nommée foo

Dépendances

GitLab nécessite des versions très récentes de Git, Ruby, Go et NodeJS.

On utilise pour l’instant des versions de Jessie Backports et Stretch (ainsi que stretch-security) via un « pinning » APT :

Package: *
Pin: release n=jessie-backports
Pin-Priority: 50


Package: *
Pin: release n=stretch
Pin-Priority: 50

Package: golang golang-doc golang-src golang-go
Pin: release n=jessie-backports
Pin-Priority: 999

Package: git git-man ruby ruby2.3 ruby-dev ruby2.3-dev libruby2.3 rake ruby-test-unit libncurses5 libreadline7 libtinfo5 libncursesw5 libncurses5-dev libtinfo-dev ncurses-bin
Pin: release n=stretch
Pin-Priority: 999

Pour NodeJS, il faut l’installer ainsi.
Il faut aussi installer Yarn.

On peut ainsi installer toutes les dépendances pour Gitlab :

# apt install build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev \
libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev libre2-dev \
logrotate python-docutils pkg-config cmake nodejs bundler ruby2.3 ruby-dev git golang nodejs yarn

Compte UNIX

Créer un compte UNIX foo :

# adduser --disabled-login --gecos 'GitLab instance foo' foo

Note : Assurez-vous d’avoir DIR_MODE=0750 dans /etc/adduser.conf pour créer le home en 750.

PostgreSQL

GitLab recommande PostgreSQL. On utilise donc la version 9.4 de Debian Jessie :

# apt install postgresql postgresql-client libpq-dev postgresql-contrib

Création de l’utilisateur PostgreSQL :

# sudo -u postgres createuser foo -d -P -R

Note : On donne les droits CREATEDB car GitLab doit faire un DROP DATABASE puis CREATE DATABASE lors de l’installation…

Note : Pensez à conserver le mot de passe pour le mettre par la suite pour GitLab CE.

Création de l’extension pg_trgm :

# sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"

Note : C’est à faire seulement la première fois.

Création de la base pour GitLab :

# sudo -u postgres createdb -O foo -E UNICODE foo

Tester la connexion et si l’extension pg_trgm est bien activée :

# sudo -u foo -H psql --password -d foo

psql> SELECT true AS enabled FROM pg_available_extensions
      WHERE name = 'pg_trgm' AND installed_version IS NOT NULL;

enabled
---------
 t
(1 row)

Redis

On utilise une instance Redis dédiée à chaque instance GitLab :

# apt install redis-server
# systemctl stop redis-server   
# systemctl disable redis-server

Créer et activer le template d’unité systemd /etc/systemd/system/redis@.service :

[Unit]
Description=Advanced key-value store instance %i
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/%i.conf
ExecStartPost=/bin/chgrp %i /var/run/redis/%i.sock
ExecStop=/usr/bin/redis-cli shutdown
Restart=always
User=redis
Group=%i

[Install]
WantedBy=multi-user.target

Puis :

# systemctl daemon-reload

Configuration spéciale pour l’instance :

# cat /etc/redis/foo.conf

daemonize yes
pidfile /var/run/redis/foo.pid
port 0
unixsocket /var/run/redis/foo.sock
unixsocketperm 770
timeout 0
loglevel notice
logfile /var/log/redis/foo.log
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename foo.rdb
dir /var/lib/redis

# chmod 644 /etc/redis/foo.conf

# systemctl enable redis@foo
# systemctl start redis@foo

GitLab CE

# sudo -iu foo
$ umask 002
$ git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 9-1-stable gitlab
$ cd gitlab
$ cp config/gitlab.yml.example config/gitlab.yml
$ sed -i 's@/home/git@/home/foo@g' config/gitlab.yml

Éditer config/gitlab.yml :

host: foo.gitlab.example.com
port: 443
https: true
user: foo
email_from: gitlab@example.com
email_display_name: GitLab foo
email_reply_to: gitlab@example.com

Mettre une clé secrète pour le chiffrement en base.

$ cp config/secrets.yml.example config/secrets.yml
$  sed -i "s@# db_key_base:@db_key_base: YOURSECRETKEY@" config/secrets.yml
$ chmod 600 config/secrets.yml

Note : Il est conseillé de générer YOURSECRETKEY ainsi : apg -m30 -n1.
Note : Il est conseillé de sauvegarder le fichier secrets.yml. Voir la section sauvegarde.

Mettre le mot de passe PostgreSQL :

$ cp config/database.yml.postgresql config/database.yml
$  sed -i -e 's/database: gitlabhq_production/database: foo/' \
  -e 's/# username: git/username: foo/' \
  -e 's/# password:/password: PASSWORD/' config/database.yml
$ chmod o-rwx config/database.yml

Note : Conservez l’espace devant le sed pour ne pas enregistrer le mot de passe dans l’historique BASH.

Ajuster les droits de certains répertoires :

$ chmod 750 ~
$ chmod -R u+rwX,go-w log/
$ chmod -R u+rwX {tmp/,tmp/pids/,builds,shared/artifacts/}
$ chmod -R u+rwX,g+rwX tmp/sockets/
$ install -d -m 700 public/uploads/

Unicorn

Configuration de base d’Unicorn :

$ cp config/unicorn.rb.example config/unicorn.rb
$ sed -i \
  -e 's@/home/git@/home/foo@g' \
  -e 's/listen "127.0.0.1:8080", :tcp_nopush => true/#listen "127.0.0.1:8080", :tcp_nopush => true/' \
  config/unicorn.rb

Rack attack

Initialisation de la configuration de Rack::Attack (qui permet du filtrage / rate-limiting) :

$ cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb

Git

Configuration :

$ git config --global core.autocrlf input
$ git config --global gc.auto 0
$ git config --global repack.writeBitmaps true

Resque

Configuration :

$ cp config/resque.yml.example config/resque.yml
$ sed -i 's/redis.sock/foo.sock/' config/resque.yml

Gems

Important: Votre partition /home ne doit pas être montée avec l’option noexec.

On installe les Gems requise :

$ bundle install -j$(nproc) --deployment --without development test mysql aws kerberos

GitLab Shell

Installation :

$ bundle exec rake gitlab:shell:install REDIS_URL=unix:/var/run/redis/foo.sock RAILS_ENV=production SKIP_STORAGE_VALIDATION=true
$ chmod -R ug+rwX,o-rwx ~/repositories/
$ chmod -R ug-s ~/repositories/
$ chmod g+s ~/repositories/

gitlab-workhorse

Installation :

$ bundle exec rake "gitlab:workhorse:install[/home/foo/gitlab-workhorse]" RAILS_ENV=production

Base de données

On crée la base de données avec l’identifiant (une adresse email) et un mot de passe pour l’utilisateur root sur l’interface web de GitLab :

$ cd ~/gitlab
$  bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword GITLAB_ROOT_EMAIL=admingitlab@example.com

Note : Conservez l’espace devant le bundle pour ne pas enregistrer le mot de passe dans l’historique BASH.

Script d’init

Attention, GitLab ne supporte pas officiellement systemd !

On doit donc encore passer pas un script d’init classique :

$ sed -i -e 's/app_user="git"/app_user="foo"/' \
  -e 's/# Provides: .*gitlab/# Provides: gitlab-foo/' \
  lib/support/init.d/gitlab
$ sed -i 's@script_path = "/etc/init.d/gitlab"@script_path = "/etc/init.d/gitlab-foo"@g' lib/tasks/gitlab/check.rake
$ git commit -a -m 'change default user'

# install -m 755 /home/foo/gitlab/lib/support/init.d/gitlab /etc/init.d/gitlab-foo
# systemctl enable gitlab-foo

Logrotate

# install -m 644 /home/foo/gitlab/lib/support/logrotate/gitlab /etc/logrotate.d/gitlab-foo
# sed -i 's@/home/git@/home/foo@g' /etc/logrotate.d/gitlab-foo

Nginx

On utilise Nginx, c’est le seul serveur web supporté officiellement par GitLab :

# apt install nginx
# adduser www-data foo
# chmod -R g+rwX /home/foo/gitlab/tmp/{pids,sockets}
# install -m 644 /home/foo/gitlab/lib/support/nginx/gitlab-ssl /etc/nginx/sites-available/foo
# sed -i -e 's@/home/git@/home/foo@g' \
  -e 's/YOUR_SERVER_FQDN/foo.gitlab.example.com/g' \
  -e 's@/var/log/nginx/gitlab@/var/log/nginx/foo@g' \
  -e 's/upstream gitlab-workhorse/upstream gitlab-foo-workhorse/' \
  -e 's@http://gitlab-workhorse@http://gitlab-foo-workhorse@' \
  /etc/nginx/sites-available/foo
# ln -s /etc/nginx/sites-available/foo /etc/nginx/sites-enabled/
# systemctl restart nginx

Note : La partie SSL/TLS n’est pas évoquée. À vous de faire le nécessaire avec un certificat Let’s Encrypt par exemple. N’oubliez donc pas de modifier les directives ssl_ dans le vhost.
Note : apt install nginx est à faire seulement la première fois.

Finalisation de l’installation

Vérification de l’état de l’installation :

# sudo -iu foo
$ cd gitlab
$ bundle exec rake gitlab:env:info RAILS_ENV=production

Compilation des assets :

$ yarn install --production --pure-lockfile
$ bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production

Démarrage de l’instance :

# /etc/init.d/gitlab-foo start

Vérifier le statut :

# sudo -iu foo
$ cd gitlab
$ bundle exec rake gitlab:check RAILS_ENV=production

Si tout est au vert, c’est bon ! On pourra aller sur l’instance via http://foo.gitlab.example.com

Sauvegarde

On peut réaliser des sauvegardes grâce à la commande bundle exec rake gitlab:backup:create RAILS_ENV=production

On peut ainsi mettre un cron pour l’utilisateur foo :

# Create a full backup of the GitLab repositories and SQL database every day at 4am
0 4 * * * cd ~/gitlab && bundle exec rake gitlab:backup:create RAILS_ENV=production CRON=1

Dans ~/gitlab/config/gitlab.yml on pourra indiquer un temps de rétention. Par exemple pour garder 5j de backups keep_time: 432000

Note : Par défaut, les sauvegardes sont stockées dans ~/gitlab/tmp/backups. Il est évidemment conseillé de les sauvegarder ailleurs et sur une machine distante.

Attention, le fichier secrets.yml contient les clés de chiffrements pour les sessions et les variables. Il n’est pas inclus dans les sauvegardes GitLab. Vous devez le copier au moins une fois dans un endroit sécurisé.

Mises à jour

Le principe des mises à jour est basé sur un git pull et un git checkout.

Mise à jour mineure 9.a.b vers 9.c.d.

Procédure générique. Il est possible de « sauter » plusieurs versions. Par exemple, de 9.0.7 à 9.1.4, etc.

Sauvegarde

# sudo -iu foo
$ cd gitlab
$ bundle exec rake gitlab:backup:create RAILS_ENV=production

Mise à jour de GitLab

$ umask 002
$ git fetch --all
$ git checkout -- Gemfile.lock db/schema.rb
$ git checkout v9.x.y -b v9.x.y
$ sed -i -e s'/app_user="git"/app_user="foo"/' \
  -e 's/# Provides: .*gitlab$/# Provides: gitlab-foo/' \
  lib/support/init.d/gitlab
$ sed -i 's#script_path = "/etc/init.d/gitlab"#script_path = "/etc/init.d/gitlab-foo"#g' lib/tasks/gitlab/check.rake
$ git commit -a -m 'change default user'

Mise à jour de gitlab-shell

$ cd ~/gitlab-shell
$ git fetch
$ git checkout v$(cat ~/gitlab/GITLAB_SHELL_VERSION) -b v$(cat ~/gitlab/GITLAB_SHELL_VERSION

Mise à jour de gitlab-workhorse

$ cd ~/gitlab-workhorse
$ git fetch
$ git checkout v$(cat ~/gitlab/GITLAB_WORKHORSE_VERSION) -b v$(cat ~/gitlab/GITLAB_WORKHORSE_VERSION)
$ make

Mise à jour base de données, Gems et assets

$ cd ~/gitlab
$ bundle install --without development test mysql aws kerberos --deployment
$ bundle clean
$ bundle exec rake db:migrate RAILS_ENV=production
$ bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
$ bundle exec rake cache:clear RAILS_ENV=production
$ git commit -a -m 'upgraded to 9.x.y'

Redémarrer GitLab

# /etc/init.d/gitlab-foo restart

Vérifier le statut

# sudo -iu foo
$ cd gitlab
$ bundle exec rake gitlab:env:info RAILS_ENV=production
$ bundle exec rake gitlab:check RAILS_ENV=production

Si tout est au vert, la migration s’est bien passée !

Mise à jour majeure

En attente d’une version majeure. À priori la 10.

Divers / FAQ

Ensemble de scripts que l’on utilise.

Restaurer un backup vers un autre nom d’instance

Si vous avez un backup de foo, que vous voulez restaurer dans bar, il faudra faire une restauration classique puis via psql :

# sudo -iu postgres
$ pg_dump foo > foo.sql
$ psql bar < foo.sql
# sudo -iu postgres psql bar
REASSIGN OWNED BY "foo" TO "bar";

Downgrader le schéma SQL

Par exemple si on downgrade une version. Il faudra récupérer la bonne version dans db/migrate. Exemple :

$ bundle exec rake db:migrate:redo RAILS_ENV=production VERSION=20161223034646

Corriger l’erreur column timelogs.merge_request_id does not exist

Si vous avez une erreur 500 lors de l’accès à une merge request et l’erreur suivante dans les logs :

==> gitlab/log/production.log <==
Started GET "/foo/bar/merge_requests/1" for 2001:db8::f00 at 2017-06-19 09:48:11 +0200
Processing by Projects::MergeRequestsController#show as HTML
  Parameters: {"namespace_id"=>"foo", "project_id"=>"bar", "id"=>"1"}
Completed 500 Internal Server Error in 214ms (ActiveRecord: 28.3ms)

ActionView::Template::Error (PG::UndefinedColumn: ERROR:  column timelogs.merge_request_id does not exist
LINE 1: ...UM("timelogs"."time_spent") FROM "timelogs" WHERE "timelogs"...

C’est que le schéma SQL n’est pas à jour. Pour corriger le problème on peut jouer la migration DB qui s’occupe de crée la colonne timelogs.merge_request_id.

$ bundle exec rake db:migrate:redo RAILS_ENV=production VERSION=20170124174637

Note: Si vous avez un erreur avec le redo, il faudra probablement éditer le fichier de migration, pour commenter la partie « down ».