From f856db9728d2c4ba042ae565465cf2ba4c7d60a2 Mon Sep 17 00:00:00 2001 From: bserie Date: Tue, 17 Apr 2018 16:58:49 +0200 Subject: [PATCH] GitLab 10.x.y. --- HowtoGitlab/10.md | 566 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 566 insertions(+) create mode 100644 HowtoGitlab/10.md diff --git a/HowtoGitlab/10.md b/HowtoGitlab/10.md new file mode 100644 index 00000000..9c1d093f --- /dev/null +++ b/HowtoGitlab/10.md @@ -0,0 +1,566 @@ +--- +categories: web git +title: Howto GitLab +... + +* Documentation : + +[GitLab](https://about.gitlab.com/) 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 **10** sous **Debian 9** (Stretch) 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 des versions de Stretch Backports pourt Git et Go via un « pinning » APT : + +~~~ +Package: * +Pin: release n=stretch-backports +Pin-Priority: 50 + +Package: git git-man golang golang-doc golang-src golang-go nginx nginx-* libnginx-* +Pin: release n=stretch-backports +Pin-Priority: 999 +~~~ + +Pour NodeJS, il faut l'installer [ainsi](https://wiki.evolix.org/HowtoNodeJS). +Il faut aussi installer [Yarn](https://wiki.evolix.org/HowtoYarn). +Ruby sera installé manuellement en version 2.3.6. + +On peut ainsi installer toutes les dépendances pour Gitlab : + +~~~ +# apt install autotools-dev bison build-essential checkinstall chrpath cmake coreutils curl file git golang libbison-dev libcurl4-openssl-dev libffi-dev libgdbm-dev libgmp-dev libicu-dev libjemalloc-dev libncurses5-dev libncursesw5-dev libre2-dev libreadline6-dev libreadline-dev libssl1.0-dev libxml2-dev libxslt-dev libyaml-dev logrotate netbase nodejs openssh-server openssl pkg-config procps python-docutils systemtap-sdt-dev tcl8.6-dev tk8.6-dev yarn zlib1g-dev +~~~ + +## 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](HowtoPostgreSQL). On utilise donc la version 9.6 de Debian Stretch : + +~~~ +# 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](#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 10-4-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](#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/,shared/pages} +$ 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 +$ git config --global receive.advertisePushOptions true +~~~ + +## Resque + +Configuration : + +~~~ +$ cp config/resque.yml.example config/resque.yml +$ sed -i 's/redis.sock/foo.sock/' config/resque.yml +~~~ + +## Ruby + +> **Important**: Votre partition `/home` ne doit pas être montée avec l'option `noexec`. + +Installation manuelle à ne faire qu'une fois ou pour mettre à jour la version de Ruby : + +~~~ +$ cd ~ +$ mkdir -p tmp/ruby +$ cd tmp/ruby +$ curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.6.tar.gz +$ echo '4e6a0f828819e15d274ae58485585fc8b7caace0 ruby-2.3.6.tar.gz' | shasum -c - && tar xzf ruby-2.3.6.tar.gz +$ cd ruby-2.3.6 +$ ./configure --disable-install-rdoc --with-jemalloc +$ make -j$(nproc) +# cd /home/foo/tmp/ruby/ruby-2.3.6 +# make install +# gem install bundler --no-ri --no-rdoc +# chmod -R u=rwX,g=rX,o=rX /usr/local/ +~~~ + +## Gems + +On installe les Gems requise : + +~~~ +# sudo -iu foo +$ cd gitlab +$ 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 +~~~ + +## gitaly + +Installation : + +~~~ +$ bundle exec rake "gitlab:gitaly:install[/home/foo/gitaly]" RAILS_ENV=production +$ chmod 0700 /home/foo/gitlab/tmp/sockets/private +$ chown git /home/foo/gitlab/tmp/sockets/private +$ cd /home/foo/gitaly +$ sed -i -e 's@/home/git@/home/foo@g' config.toml +$ cd - +~~~ + +## 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 traductions : + +~~~ +$ bundle exec rake gettext:compile 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](https://forge.evolix.org/projects/evogitlab/repository) 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 ». \ No newline at end of file