GitLab es una herramienta de ciclo de vida de DevOps completa la cual provee un gestor de repositorios Git que incluye Wiki, seguimiento de tickets y características de CI (continuous integration). Se trata de una solución open-source utilizada por grandes compañías alrededor del mundo, aunque sigue un modelo "open-core" en el cual la funcionalidad central es liberada bajo licencia MIT, mientras que ciertas características adicionales se liberan bajo licencias propietarias. El código de GitLab fue desarrollado originalmente en lenguaje Ruby, con algunas de sus partes reescritas en Go.

Este artículo demuestra cómo instalar GitLab desde los fuentes, a pesar de que la documentación oficial aclara inmediatamente que se trata de un proceso extenuante y propenso a errores, con lo cual recomiendan fuertemente la instalación desde paquete. Sin embargo, encarar una instalación manual puede ser de gran utilidad para comprender el funcionamiento completo de GitLab, junto con todas las tecnologías que lo componen y sus interdependencias.



Instalar/verificar dependencias

Verificar versión de sudo:

root@gitlab:~# sudo -V | head -n 1
Sudo versión 1.8.19p1

Verificar versión de git disponible:

root@gitlab:~# git --version
git version 2.20.1

Instalar dependencias faltantes junto con el lenguaje Go:

# apt-get install graphicsmagick golang libre2-dev

Crear un directorio donde almacenar los fuentes de todos los paquetes a instalar:

root@gitlab:~# mkdir -p /usr/local/src/gitlab
root@gitlab:~# cd /usr/local/src/gitlab

Node.js

Instalar Node.js versión 10 siguiendo el tutorial Instalar Node.js 10.x en Debian Stretch.

Instalar Ruby 2.5

Instalar Ruby 2.5.5 con Bundle como gestor de gemas siguiendo el tutorial: Cómo instalar Ruby desde los fuentes en Linux .

Instalar Yarn

Yarn es un gestor de dependencias de Javascript similar a npm. Descargar la última versión disponible desde el sitio oficial, ya que la versión de paquete provista por Debian está desactualizada:

# wget https://yarnpkg.com/latest.tar.gz
root@gitlab:/usr/local/src/gitlab# tar tzvf latest.tar.gz 
-rw-r--r-- root/root      1355 2019-03-15 08:20 yarn-v1.15.2/LICENSE
-rw-r--r-- root/root      3353 2019-03-15 08:20 yarn-v1.15.2/README.md
drwxr-xr-x root/root         0 2019-03-15 08:20 yarn-v1.15.2/bin/
-rwxr-xr-x root/root        42 2019-03-15 08:20 yarn-v1.15.2/bin/yarnpkg
-rwxr-xr-x root/root        34 2019-03-15 08:20 yarn-v1.15.2/bin/yarn.cmd
-rwxr-xr-x root/root      1025 2019-03-15 08:20 yarn-v1.15.2/bin/yarn
-rwxr-xr-x root/root        30 2019-03-15 08:20 yarn-v1.15.2/bin/yarnpkg.cmd
-rwxr-xr-x root/root      1015 2019-03-15 08:20 yarn-v1.15.2/bin/yarn.js
drwxr-xr-x root/root         0 2019-03-15 08:20 yarn-v1.15.2/lib/
-rwxr-xr-x root/root   4893479 2019-03-15 08:20 yarn-v1.15.2/lib/cli.js
-rw-r--r-- root/root      9910 2019-03-15 08:20 yarn-v1.15.2/lib/v8-compile-cache.js
-rw-r--r-- root/root       506 2019-03-15 08:20 yarn-v1.15.2/package.json

Renombrar el paquete según la última versión estable descargada:

root@gitlab:/usr/local/src/gitlab# mv latest.tar.gz yarn-v1.15.2.tar.gz

Instalar Yarn:

# tar xzf yarn-v1.15.2.tar.gz 
# mv yarn-v1.15.2 /usr/local/yarn
# chown -R root:root /usr/local/yarn
# chmod -R 0755 /usr/local/yarn
# chmod g-s /usr/local/yarn 

Por último, ajustar la variable de entorno PATH:

# nano /etc/profile.d/local.sh

Debe quedar así:

RUBYDIR="/usr/local/ruby/bin"
YARNDIR="/usr/local/yarn/bin"
PATH="${PATH}:${RUBYDIR}:${YARNDIR}"
export PATH

Recargar el perfil de Bash:

# source /etc/profile

Verificar las versiones de Ruby y Yarn:

root@gitlab:~# ruby --version
ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux]
root@gitlab:~# yarn --version
1.15.2

Git

Crear un usuario para git:

# useradd -s /bin/bash -m git

Postgres

Compilar PostgreSQL con soporte para "pg_trgm" y crear una instancia para GitLab (initdb).

  1. Compilar e instalar PostgreSQL desde los fuentes
  2. Crear una instancia de PostgreSQL
  3. Crear una base de datos y usuario en un servidor PostgreSQL

Luego de compilar PostgreSQL, compilar "pg_trgm" desde el directorio contrib/:

cd contrib/pg_trgm/
&& make
&& cp pg_trgm.so /usr/local/pgsql/lib
&& cp pg_trgm--*.sql pg_trgm.control /usr/local/pgsql/share/extension
&& cd ../../

Luego ajustar los permisos del plugin:

# chown root:postgres /usr/local/pgsql/share/extension/*

Crear un usuario de Postgres:

root@gitlab:~# su - postgres
postgres@gitlab:~$ createuser -S -D -R -P usr_gitlab

Crear la extensión "pg_trgm":

postgres@gitlab:~$ psql -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
CREATE EXTENSION

Finalmente crear la base de datos para GitLab:

postgres@gitlab:~$ createdb -O usr_gitlab gitlab -E utf-8

Redis

Redis es una estructura de datos en memoria que implementa una base de datos clave-valor. Se utiliza almacenamiento y a veces como caché.

Instalar Redis desde paquete:

root@gitlab:/usr/local/src/gitlab# apt-get install redis-server

Configurar Redis para que escuche peticiones a través del socket Unix en /var/run/redis/redis.sock:

root@gitlab:/usr/local/src/gitlab# nano /etc/redis/redis.conf

Descomentar o agregar las siguientes líneas:

unixsocket /var/run/redis/redis.sock
unixsocketperm 777

Luego reiniciar Redis:

root@gitlab:/usr/local/src/gitlab# service redis-server restart
Stopping redis-server: redis-server.
Starting redis-server: redis-server.

Instalar GitLab

Cambiar al usuario git:

root@gitlab:~# su - git
git@gitlab:~$

La instalación de GitLab desde los fuentes es un tanto extensa y propensa a errores, con lo cual he creado un script Bash para llevarla a cabo:

#!/bin/sh

GITLAB_RELEASE="11-9-stable"
GITLAB_INSTALL_DIR="/usr/local/gitlab"

echo "Clonando GitLab release ${GITLAB_RELEASE}..."

git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b $GITLAB_RELEASE $GITLAB_INSTALL_DIR

# Go to GitLab installation folder
cd $GITLAB_INSTALL_DIR

echo "Editar el archivo de configuración de GitLab..."
sleep 3

# Copy the example GitLab config
cp config/gitlab.yml.example config/gitlab.yml
sed "s|/home/git/gitlab|$GITLAB_INSTALL_DIR|" -i config/gitlab.yml

# Update GitLab config file, follow the directions at top of file
nano config/gitlab.yml

echo "Configurando permisos..."

# Copy the example secrets file
cp config/secrets.yml.example config/secrets.yml
chmod 0600 config/secrets.yml

# Make sure GitLab can write to the log/ and tmp/ directories
chown -R git log/
chown -R git tmp/
chmod -R u+rwX,go-w log/
chmod -R u+rwX tmp/

# Make sure GitLab can write to the tmp/pids/ and tmp/sockets/ directories
chmod -R u+rwX tmp/pids/
chmod -R u+rwX tmp/sockets/

# Create the public/uploads/ directory
mkdir public/uploads/

# Make sure only the GitLab user has access to the public/uploads/ directory
# now that files in public/uploads are served by gitlab-workhorse
chmod 0700 public/uploads

# Change the permissions of the directory where CI job traces are stored
chmod -R u+rwX builds/

# Change the permissions of the directory where CI artifacts are stored
chmod -R u+rwX shared/artifacts/

# Change the permissions of the directory where GitLab Pages are stored
chmod -R ug+rwX shared/pages/

# Copy the example Unicorn config
cp config/unicorn.rb.example config/unicorn.rb

# Find number of cores
echo "Número de nucleos:"
nproc

echo "Configurar Unicorn..."
sleep 3

# Enable cluster mode if you expect to have a high load instance
# Set the number of workers to at least the number of cores
# Ex. change amount of workers to 3 for 2GB RAM server
sed "s|/home/git/gitlab|$GITLAB_INSTALL_DIR|" -i config/unicorn.rb
nano config/unicorn.rb

# Copy the example Rack attack config
cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb

echo "Configurando git..."

# Configure Git global settings for git user
# 'autocrlf' is needed for the web editor
git config --global core.autocrlf input

# Disable 'git gc --auto' because GitLab already runs 'git gc' when needed
git config --global gc.auto 0

# Enable packfile bitmaps
git config --global repack.writeBitmaps true

# Enable push options
git config --global receive.advertisePushOptions true

# Configure Redis connection settings
cp config/resque.yml.example config/resque.yml

echo "Configurar Redis...."
sleep 3

# Change the Redis socket path if you are not using the default Debian / Ubuntu configuration
nano config/resque.yml

# PostgreSQL only:
cp config/database.yml.postgresql config/database.yml

echo "Configurar la base de datos..."
sleep 3

# MySQL and remote PostgreSQL only:
# Update username/password in config/database.yml.
# You only need to adapt the production settings (first part).
# If you followed the database guide then please do as follows:
# Change 'secure password' with the value you have given to $password
# You can keep the double quotes around the password
nano config/database.yml

# PostgreSQL and MySQL:
# Make config/database.yml readable to git only
chmod o-rwx config/database.yml

NOTA: Es necesario que el usuario git tenga permiso de escritura para crear el directorio de instalación de gitlab (variable GITLAB_INSTALL_DIR).

Si se va a instalar en un directorio de sistema, es posible otorgar permisos de escritura temporalmente:<7p>

root@gitlab:~# chmod 777 /usr/local/

Antes de comenzar es necesario seleccionar una rama estable a instalar.

El script de instalación es interactivo, ya que requiere editar manualmente ciertos archivos de configuración.

El primer paso interactivo consiste en editar el archivo de configuración de GitLab. Como mínimo, editar el nombre de host y configuración de correo saliente:

  ## GitLab settings
  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: gitlab.linuxito.com
    email_from: gitlab@linuxito.com 
    email_display_name: GitLab
    email_reply_to: noreply@linuxito.com 

Los archivos de configuración de Unicorn y Redis, para comenzar, pueden dejarse por defecto para ser "tuneados" luego.

Finalmente se configura el acceso a la base de datos Postgres:

production:
  adapter: postgresql
  encoding: unicode
  database: gitlab
  pool: 10
  username: usr_gitlab
  password: 1234
  host: localhost

Gems

Intalar gems:

git@gitlab:~$ cd /usr/local/gitlab/
git@gitlab:/usr/local/gitlab$ bundle install --deployment --without development test mysql aws kerberos

gitlab-shell

Instalar gitlab-shell:

git@gitlab:/usr/local/gitlab$ bundle exec rake gitlab:shell:install RAILS_ENV=production SKIP_STORAGE_VALIDATION=true

gitlab-workhorse

Instalar gitlab-workhorse:

git@gitlab:/usr/local/gitlab$ bundle exec rake "gitlab:workhorse:install[/usr/local/gitlab-workhorse]" RAILS_ENV=production

Gitaly

Instalar Gitaly:

git@gitlab:/usr/local/gitlab$ bundle exec rake "gitlab:gitaly:install[/usr/local/gitaly,/home/git/repositories]" RAILS_ENV=production

Configurar permisos de Gitaly:

root@gitlab:~# chmod 0700 /usr/local/gitlab/tmp/sockets/private/

Configurar Gitaly:

root@gitlab:~# nano /usr/local/gitaly/config.toml

Ajustar adecuadamente todas las rutas:

bin_dir = "/usr/local/gitaly"
socket_path = "/usr/local/gitlab/tmp/sockets/private/gitaly.socket"
[gitaly-ruby]
dir = "/usr/local/gitaly/ruby"
[gitlab-shell]
dir = "/usr/local/gitlab-shell"
[[storage]]
name = "default"
path = "/home/git/repositories"

Iniciar Gitaly:

git@gitlab:/usr/local/gitlab$ cd /usr/local/gitaly/
git@gitlab:/usr/local/gitaly$ ./gitaly config.toml >>/usr/local/gitlab/tmp/gitaly.log 2>&1 &
[1] 5756

Deshabilitar permisos temporales

Deshabilitar el permiso de escritura temporal sobre /usr/local:

root@gitlab:~# chmod 755 /usr/local/

Base de datos

El siguiente paso consiste en instalar las tablas de la base de datos de GitLab.

Iniciar Postgres (el nombre de servicio puede variar):

root@gitlab:~# service postgresql-pg_gitlab start
waiting for server to start.... done
server started

En caso de error o fallo al conectarse a Gitaly, revisar las rutas configuradas en config/gitlab.yml:

git@gitlab:/usr/local/gitlab$ bundle exec rake gitlab:setup RAILS_ENV=production
Failed to connect to Gitaly...
Error: 14:Connect Failed
git@gitlab:/usr/local/gitlab$ nano config/gitlab.yml
  gitaly:
    # Path to the directory containing Gitaly client executables.
    client_path: /home/git/gitaly/bin

Corregir la ruta hacia /usr/local/gitaly, guardar los cambios y reintentar. Asegurarse de que Gitaly esté levantado.

git@gitlab:/usr/local/gitlab$ bundle exec rake gitlab:setup RAILS_ENV=production
This will create the necessary database tables and seed the database.
You will lose any previous data stored in the database.
Do you want to continue (yes/no)?

El rol del usuario configurado debe tener permisos para crear bases de datos y tablas en Postgres:

PG::InsufficientPrivilege: ERROR:  permission denied to create database
git@gitlab:/usr/local/gitlab$ exit
logout
root@gitlab:~# su - postgres
postgres@gitlab:~$ psql
psql (11.2)
Type "help" for help.

postgres=# ALTER ROLE usr_gitlab SUPERUSER;
ALTER ROLE
postgres=# \q
postgres@gitlab:~$ exit
logout
root@gitlab:~# su - git
git@gitlab:~$ cd /usr/local/gitlab

Al finalizar la instalación de la base de datos, es posible comprobar que se crea la cuenta de root de Gitlab sin contraseña:


== Seed from /usr/local/gitlab/db/fixtures/production/002_admin.rb
Administrator account created:

login:    root
password: You'll be prompted to create one on your first visit.

Quitar los privilegios de superusuario al rol del usuario de Postgres para Gitlab:

git@gitlab:/usr/local/gitlab$ exit
logout
root@gitlab:~# su - postgres
postgres@gitlab:~$ psql
psql (11.2)
Type "help" for help.

postgres=# ALTER ROLE usr_gitlab NOSUPERUSER;
ALTER ROLE
postgres=# \q
postgres@gitlab:~$ exit
logout
root@gitlab:~# su - git
git@gitlab:~$ cd /usr/local/gitlab

Script de inicio

Instalar el script de inicio de ejemplo:

root@gitlab:~# cp /usr/local/gitlab/lib/support/init.d/gitlab /etc/init.d/
root@gitlab:~# cp /usr/local/gitlab/lib/support/init.d/gitlab.default.example /etc/default/gitlab

Editar la configuración del script de inicio:

root@gitlab:~# nano /etc/default/gitlab

Ajustar la variable app_root:

app_root="/usr/local/gitlab"

Habilitar el servicio:

root@gitlab:~# update-rc.d gitlab defaults

Configurar logrotate:

root@gitlab:~# cp /usr/local/gitlab/lib/support/logrotate/gitlab /etc/logrotate.d/
root@gitlab:~# nano /etc/logrotate.d/gitlab
# GitLab logrotate settings
# based on: http://stackoverflow.com/a/4883967

/usr/local/gitlab/log/*.log {
    daily 
    missingok
    rotate 90
    compress
    notifempty
    copytruncate
}
 
/usr/local/gitlab-shell/gitlab-shell.log {
    daily 
    missingok
    rotate 90
    compress
    notifempty
    copytruncate
}

Verificar la instalación

El siguiente comando retorna el estado de la instalación de GitLab junto con todas sus dependencias:

git@gitlab:/usr/local/gitlab$ bundle exec rake gitlab:env:info RAILS_ENV=production

System information
System:         Debian 9.8
Current User:   git
Using RVM:      no
Ruby Version:   2.5.5p157
Gem Version:    2.7.6.2
Bundler Version:1.17.3
Rake Version:   12.3.2
Redis Version:  5.0.3
Git Version:    2.20.1
Sidekiq Version:5.2.5
Go Version:     go1.11.5 linux/amd64

GitLab information
Version:        11.9.5
Revision:       f621ab63487
Directory:      /usr/local/gitlab
DB Adapter:     postgresql
URL:            http://gitlab.linuxito.com
HTTP Clone URL: http://gitlab.linuxito.com/some-group/some-project.git
SSH Clone URL:  git@gitlab.linuxito.com:some-group/some-project.git
Using LDAP:     no
Using Omniauth: yes
Omniauth Providers: 

GitLab Shell
Version:        8.7.1
Repository storage paths:
- default:      /home/git/repositories
GitLab Shell path:              /usr/local/gitlab-shell
Git:            /usr/bin/git

Compilar recursos estáticos

Comenzar compilando los archivos gettext:

git@gitlab:/usr/local/gitlab$ bundle exec rake gettext:compile RAILS_ENV=production

Luego compilar los recursos:

git@gitlab:/usr/local/gitlab$ yarn install --production --pure-lockfile
git@gitlab:/usr/local/gitlab$ bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production

Si este paso arroja error de desborde de pila (stack overflow), significa que estamos utilizando una versión de Node.js desactualizada. En el comienzo de este artículo se instala la versión 10 desde los fuentes, no la versión de Debian de paquete.

Iniciar GitLab

En este punto ya es posible iniciar GitLab. Levantar todo ejecutando:

root@gitlab:~# service gitlab start
Starting GitLab Unicorn
Starting GitLab Sidekiq
Starting GitLab Workhorse
Starting Gitaly
.
The GitLab Unicorn web server with pid 19287 is running.
The GitLab Sidekiq job dispatcher with pid 19403 is running.
The GitLab Workhorse with pid 19350 is running.
Gitaly with pid 19344 is running.
GitLab and all its components are up and running.

Nginx

Por último resta instalar y configurar Nginx como proxy HTTP/S.

Compilar e instalar Nginx siguiendo el tutorial: Compilar Nginx desde los fuentes en Debian 9.

Configurar Nginx:

root@gitlab:~# cp /usr/local/gitlab/lib/support/nginx/gitlab /usr/local/etc/nginx/gitlab.conf
root@gitlab:~# cd /usr/local/etc/nginx
root@gitlab:/usr/local/etc/nginx# nano nginx.conf

Agregar el siguiente include dentro de la sección http:

    include gitlab.conf;

Configurar la ruta al socket de Workhorse y al directorio público (/usr/local/gitlab/public).

Luego configurar la sección server:

## Normal HTTP host
server {
  ## Either remove "default_server" from the listen line below,
  ## or delete the /etc/nginx/sites-enabled/default file. This will cause gitlab
  ## to be served if you visit any address that your server responds to, eg.
  ## the ip address of the server (http://x.x.x.x/)n 0.0.0.0:80 default_server;
  listen 0.0.0.0:80;
  server_name gitlab.linuxito.com; ## Replace this with something like gitlab.example.com
  server_tokens off; ## Don't show the nginx version number, a security best practice

Reiniciar Nginx:

Starting nginx: root@gitlab:/usr/local/etc/nginx/sites-enabled# service nginx restart
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Restarting nginx: OK

Desde un navegador, acceder a la raíz del servidor en el puerto 80:

Antes de setear el password de GitLab, configurar el acceso seguro a través de HTTPS según las instrucciones en el artículo Cómo compilar Nginx con soporte para SSL. A su vez, es recomendable forzar HTTPS para mejorar la seguridad.

Referencias


Tal vez pueda interesarte


Compartí este artículo