Deploying GitLab Community Edition

At my university's CS department, we are trying to set up an internal GitLab CE instance for CI/CD of our projects. Based on our infrastructure, I decided to manage a Traefik instance and deploy GitLab Omnibus on Docker.

Nginx

To have Traefik reverse-proxy the nginx instance, simply disable HTTPS and route the traffic to container port 80:

nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['real_ip_trusted_addresses'] = [ '172.19.0.2/32' ] # Traefik's internal addresss
nginx['real_ip_header'] = 'X-Real-Ip' # X-Real-Ip is set by Traefik
nginx['real_ip_recursive'] = 'on'

container labels:

traefik.http.services.gitlab.loadbalancer.server.port: "80"
traefik.http.routers.gitlab.service: "gitlab"
traefik.http.routers.gitlab.entrypoints: "web"
traefik.http.routers.gitlab.rule: "Host(`gitlab.example.com`)"
traefik.http.routers.gitlab.tls.certResolver: "http"

Grafana

GitLab Omnibus has a built-in Grafana instance that authenticates user using GitLab OAuth. I ran into the issue where Grafana was not able to complete the OAuth process. Let's say the machine's public facing address is 1.2.3.4 and Traefik container IP address is 172.16.0.2. I looked into the logs and found this in /var/log/gitlab/grafana/current:

2021-04-19_18:15:05.40382 t=2021-04-19T18:15:05+0000 lvl=eror msg=login.OAuthLogin(NewTransportWithCode) logger=context userId=0 orgId=0 uname= error="Post \"https://gitlab.example.com/oauth/token\": dial tcp 1.2.3.4:443: connect: connection timed out"

Apparently the GitLab container is not able to connect to gitlab.example.com via 1.2.3.4. Double checking on a shell session inside the container confirms the case:

root@server:/srv/gitlab-ce# docker exec -it gitlab-ce_web_1 bash
root@96c275d00c01:/# curl -v gitlab.example.com
*   Trying 1.2.3.4:80...
(hangs)

It turns out ufw was blocking the traffic from all Docker network interfaces to the host machine (INPUT chain). I decided to disable ufw once and for all.

It is worth to mention that in GitLab's official documentation on running with Docker Compose, they suggest specifying hostname option for the GitLab container. Actually, the option should not be used, because that would resolve gitlab.example.com to 127.0.0.1 inside the container.

At the beginning, you need access to the Grafana admin account to grant administrative permissions to other accounts (i.e. your Grafana account). To do that, first enable the login form, specify a secure password and log in.

grafana['disable_login_form'] = false
grafana['admin_password'] = 'foobar'

After you've done the administrative actions, do not forget to turn it back off:

grafana['disable_login_form'] = true

GitLab Pages

In some of our CI pipelines, there are static websites built by Vue.js that we wish to be directly accessable in Jobs Artifacts, and that is handled by GitLab Pages daemon. To make it work with Traefik, disable pages_nginx and have Traefik route the requests to the Pages daemon directly:

pages_external_url "http://gitlab-pages.example.com"
pages_nginx['enable'] = false
gitlab_pages['external_http'] = ['0.0.0.0:8081']

Traefik labels:

traefik.http.services.gitlab-pages.loadbalancer.server.port: "8081"
traefik.http.routers.gitlab-pages.service: "gitlab-pages"
traefik.http.routers.gitlab-pages.entrypoints: "web"
traefik.http.routers.gitlab-pages.rule: "Host(`example.com`) || Host(`gitlab-pages.example.com`) || HostRegexp(`{subdomain:[a-z]+}.gitlab-pages.example.com`)"
traefik.http.routers.gitlab-pages.tls.certResolver: "http"

Don't forget to expose port 8081 to make it reachable by Traefik.

In addition, our project visibility is set to internal. According to the docs, we needed to enable Access Control for GitLab Pages in gitlab.rb:

gitlab_pages['access_control'] = true

While the GitLab instance runs as a container, we also needed inplace_chroot:

gitlab_pages['inplace_chroot'] = true

It turned out that these two has conflicts to each other, which is explained in this official documentation.

The workaround was pretty much a hack. While the GitLab instance is for internal-only, I decided to go for the hack. Get a shell to the container, and run:

mkdir -p /var/opt/gitlab/gitlab-rails/shared/pages/etc/
cp /etc/resolv.conf /var/opt/gitlab/gitlab-rails/shared/pages/etc/
cp -rv /etc/ssl /var/opt/gitlab/gitlab-rails/shared/pages/etc/
gitlab-ctl restart gitlab-pages

After setting this up, I found out that Pages only serves .html, .htm, .txt, and .json. It does not serve .js or some images. So it ended up no use for us.

Git SSH

In our setup, we have Traefik inside of an another Docker network named traefik. In the beginning, when I was trying to publish port 22 for git server, I forgot to add the GitLab container in the default network as well. So don't forget to do that if you're using similar setup.