Gitlab

September 14, 2019 Application, DevOps 4 minutes, 52 seconds

Gitlab provides official Docker images. The following config shows the integration in nginx of an out of the box gitlab container with docker-compose.yml.

version "2"
services:
    gitlab:
      image: 'gitlab/gitlab-ce:latest'
      restart: always
      ports:
        - '80:80'
        - '443:443'
        - '22:22'
      volumes:
        - '/srv/gitlab/config:/etc/gitlab'
        - '/srv/gitlab/logs:/var/log/gitlab'
        - '/srv/gitlab/data:/var/opt/gitlab'

In /etc/gitlab/gitlab.rb (from within the container) or in /srv/gitlab/config/gitlab.rb from within the host:

external_url 'https://domain.tld/gitlab/'

nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['proxy_set_headers'] = {
  "X-Forwarded-Proto" => "https",
  "X-Forwarded-Ssl" => "on"
}

After changing the config reconfigure gitlab:

# open a bash in the gitlab container
docker exec -it gitlab bash
# reconfigure gitlab
gitlab-ctl reconfigure

server {
    listen 443 ssl;
    server_name domain.tld;
    index index.html index.htm;
    error_log /var/log/nginx/error.log error;
    location /gitlab {
        client_max_body_size 0;
        gzip off;
        proxy_read_timeout      300;
        proxy_connect_timeout   300;
        proxy_redirect          off;
        proxy_http_version 1.1;
        proxy_set_header    Host                $http_host;
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto   $scheme;
        # TODO
        proxy_pass http://<gitlab>:80;
    }
    ssl_certificate /etc/nginx/cert.pem;
    ssl_certificate_key /etc/nginx/cert.key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;
}

Reload nginx:

# check config syntx
nginx -t
# reload
nginx -s reload

docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

More install options are available

Run in your runner host (here in the docker container)

sudo gitlab-runner register
  • Get your token from /admin/runners of your Gitlab instance
  • Set your executioner (here docker)
  • No tags, allow untagged jobs, no shared runner (without those settings the runner stuck)

add and push .gitlab-ci.yml in your project root

image: maven:latest

verify:
  stage: build
  script:
    - mvn verify

build:
  stage: build
  script:
    - mvn compile

Recommended: wildcard domain and corresponding SSL certificate

  1. Assign a runner to a group of projects in Gitlab runner
  2. Start runner docker run -d --name gitlab-runner-public --restart always -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
  3. Register runner The docker image used can be overwritten in the .gitlab-ci.yml of your pipeline

    1. interactive: docker exec -it gitlab-runner-public bash
      • gitlab-runner register
      • docker as default executioner
      • alpine as default image
    2. or non interactive
      docker run --rm -t -i -v /path/to/config:/etc/gitlab-runner --name gitlab-runner gitlab/gitlab-runner register \
                          --non-interactive \
                          --executor "docker" \
                          --docker-image alpine:3 \
                          --url "https://gitlab.com/" \
                          --registration-token "PROJECT_REGISTRATION_TOKEN" \
                          --description "docker-runner" \
                          --tag-list "docker,aws" \
                          --run-untagged \
                          --locked="false"
  4. Setup Pages (wildcard domain with TLS support) gitlab.rb
            pages_external_url "https://pages.rootknecht.net/"
            gitlab_pages['enable'] = true
            gitlab_pages['inplace_chroot'] = true # in case of gitlab-pages daemon not starting due to bind mount permission error
            pages_nginx['redirect_http_to_https'] = true
            pages_nginx['ssl_certificate'] = "/etc/gitlab/ssl/pages-nginx.crt"
            pages_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/pages-nginx.key"

    Reconfigure and restart

        gitlab-ctl reconfigure
        gitlab-ctl restart gitlab-pages

    Debugging

        # get logs (run in container)
        gitlab-ctl tail gitlab-pages
        # path of your pages (in container)
        ls /var/opt/gitlab/gitlab-rails/shared/pages
        # error log of bundled nginx
        /var/log/gitlab/nginx/gitlab_pages_error.log

Publish static html content with following .gitlab-ci.yml

image: alpine:latest
pages:
  stage: deploy
  script:
  - echo 'Nothing to do...'
  artifacts:
    paths:
    - public # this is the path in your repo to publish
  only:
  - master

In gitlab.rb

gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "<SMTP Host>"
gitlab_rails['smtp_port'] = "587"
gitlab_rails['smtp_user_name'] = "<user>"
gitlab_rails['smtp_password'] = "<password>"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'none' # change if there are valid certificates
gitlab_rails['gitlab_email_from'] = "<MAIL FROM>"
gitlab_rails['gitlab_email_reply_to'] = "<REPLY TO>"

gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = {
'main' => {
  'label' => 'Description',
  'host' =>  '<LDAP-HOST',
  'port' => 389, # 636 for secured connection
  'uid' => 'sAMAccountName',
  'verify_certificates' => true,
  'bind_dn' => '<can be full bind or username>',
  'password' => '<password>',
  'method' => 'plain', # change for enrypted connections
  'base' => '<BASE DN>',
  'active_directory' => true, # true only for Microsoft AD
  'allow_username_or_email_login' => true,
  'user_filter' => '(&(objectCategory=Person)(sAMAccountName=*))'
  }
}

Add virtualisation.docker.enable = true; and optionally extraGroups= [ "docker" ] to a user who needs to control docker to your configuration.nix file.

Add python36Packages.docker_compose to environment.systemPackages

networking.firewall.allowedTCPPorts = [ 80 443 ]

Adjust paths and ports according to your setup

version: '2'

services:
  web:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab'
    ports:
      - '80:80'
      - '443:443'
      - '50222:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'

Run docker-compose up -d to start the service in the backgroud. You should now be able to access gitlab with your machine's IP

Add openssl to environment.systemPackages openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

Alternative: Use lets encrypt

The main configuration file is /srv/gitlab/config/gitlab.rb (adjust your path according to your docker-compose file)

In gitlab.rb put 'external_url "https://gitlab.example.com"'. Gitlab will look after your certificates according to your hostname - here /etc/gitlab/ssl/gitlab.example.com.key and /etc/gitlab/ssl/gitlab.example.com.crt.

Note that this is the path inside of the container and won't be permanent - on your docker host the correct path is /srv/gitlab/config/ssl/

Create the ssl directory and copy your previously generated files cert.pem and cert.key to this folder and rename them. The cert.pem file is the .crt file and the key.pem the .key file.

Now connect to your container with docker exec -it gitlab_web_1 and run gitlab-ctl reconfigure inside your container.

After enabling https gitlab does not listen to http anymore. To redirect incoming http traffic to https put nginx['redirect_http_to_https'] = true in your gitlab.rb file.