为了托管一些私有的代码,折腾 CI/CD,我用 Docker 搭建一套自己的 Gitlab. Gitlab 社区版功能很强大, 包含且不限于 代码托管、容器镜像库,Gitlab Pages 以及 CI/CD。

搭建服务

我用的是 docker-compose 搭建的,Gitlab 版本为 14.1.1-ce.0, 整个镜像文件有 2.23G,配置文件如下。

version: '3'
services:
 web:
  image: 'gitlab/gitlab-ce:14.1.1-ce.0'
  restart: always
  container_name: gitlab
  hostname: 'gitlab.razeen.me'
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      external_url "https://gitlab.razeen.me"
      letsencrypt['enable'] = false
      nginx['redirect_http_to_https'] = false
      nginx['listen_port'] = 80
      nginx['listen_https'] = false
      gitlab_pages['enable'] = true
      gitlab_pages['inplace_chroot'] = true
      pages_external_url "https://pages.razeen.me"
      pages_nginx['listen_port'] = 80
      pages_nginx['listen_https'] = false
      registry['enabled'] = true
      registry_nginx['listen_port'] = 5050
      registry_nginx['listen_https'] = false
      registry_external_url "https://registry.razeen.me"
      gitlab_rails['gitlab_shell_ssh_port'] = 20022
      gitlab_rails['gitlab_email_from'] = 'git@xxx.xxx'
      gitlab_rails['smtp_enable'] = true
      gitlab_rails['smtp_address'] = "smtp.qq.com"
      gitlab_rails['smtp_port'] = 465
      gitlab_rails['smtp_user_name'] = "xxxx@xxxx.cn"
      gitlab_rails['smtp_password'] = "xxxxxxx"
      gitlab_rails['smtp_authentication'] = "login"
      gitlab_rails['smtp_enable_starttls_auto'] = true
      gitlab_rails['smtp_tls'] = true
      gitlab_rails['smtp_domain'] = "exmail.qq.com"
      grafana['enable'] = false
      prometheus_monitoring['enable'] = false      
  ports:
    - '127.0.0.1:19080:80'
    - '127.0.0.1:19050:5050'
    - '20022:22'
  volumes:
    - './config:/etc/gitlab'
    - './data:/var/opt/gitlab'
    - './logs:/var/log/gitlab'

在配置中,我们只使用了一个环境变量 GITLAB_OMNIBUS_CONFIG 就将我们需要的参数指定好了。其中主要开启了:

  • Gitlab
  • Pages (静态页面)
  • Registry (镜像仓库)
  • SMTP 服务

简要配置介绍如下:

# gitlab 服务的地址
      external_url "https://gitlab.razeen.me"

# 如果你开启了该选项, 可以自动申请并使用 Let\`s Encrypt 的证书,当然还要配合一些其他设置。 我这里由于 `HTTPS` 是我自己管理的就关闭了该选项;
      letsencrypt['enable'] = false

# Gitlab 主服务 Nginx 的配置, 我把 HTTPS 关闭了,全部自己统计管理;
      nginx['redirect_http_to_https'] = false
      nginx['listen_port'] = 80
      nginx['listen_https'] = false

# 有时会结合 CI/CD 部署一些静态页面,就把 Pages 开了。
      gitlab_pages['enable'] = true
      gitlab_pages['inplace_chroot'] = true
      pages_external_url "https://pages.razeen.me"
      pages_nginx['listen_port'] = 80
      pages_nginx['listen_https'] = false
      
# 镜像仓库是必须要有的,一些镜像放到内部,自用起来速度杠杠的。
      registry['enabled'] = true
      registry_nginx['listen_port'] = 5050
      registry_nginx['listen_https'] = false
      registry_external_url "https://registry.razeen.me"
      
# 一些基础的配置,SSH 端口,以及 SMTP 邮件服务(我用的QQ的)。
      gitlab_rails['gitlab_shell_ssh_port'] = 20022
      gitlab_rails['gitlab_email_from'] = 'git@xxx.xxx'
      gitlab_rails['smtp_enable'] = true
      gitlab_rails['smtp_address'] = "smtp.qq.com"
      gitlab_rails['smtp_port'] = 465
      gitlab_rails['smtp_user_name'] = "xxxx@xxxx.cn"
      gitlab_rails['smtp_password'] = "xxxxxxx"
      gitlab_rails['smtp_authentication'] = "login"
      gitlab_rails['smtp_enable_starttls_auto'] = true
      gitlab_rails['smtp_tls'] = true
      gitlab_rails['smtp_domain'] = "exmail.qq.com"
      
# grafana 和 prometheus 我关了,后面自建
      grafana['enable'] = false
      prometheus_monitoring['enable'] = false

      
# 几个关键的端口先映射出来,80是服务端口,5050是镜像仓库,22就是SSH了。
  ports:
    - '127.0.0.1:19080:80'
    - '127.0.0.1:19050:5050'
    - '20022:22'

# 配置、数据、日志 目录也持久化一下
  volumes:
    - './config:/etc/gitlab'
    - './data:/var/opt/gitlab'
    - './logs:/var/log/gitlab'

配置好这些,镜像拉下来后,第一次等个几分钟就启动好了(取决于服务器性能)。。。

通配符证书申请

由于要开启 HTTPS, 证书少不了, 首先想到的是 Let`s Encrypt 的通配符了,结合 Acme 自动化,免费 且 省心。 但 Let`s Encrypt 目前在国内申请老不稳定,我就选用了 ZeroSSL 的通配证书, 两行命令搞定。

# 注册账户
docker run --rm  -it  \
  -v "$(pwd)/acme":/acme.sh  \
  neilpang/acme.sh --register-account  -m me@razeen.me --server zerossl

# 申请 ECC 证书, 我用的是 DNSPod 直接写上 DNS 服务商密钥的两个环境变量即可。
# 其他的还参考 https://github.com/acmesh-official/acme.sh/wiki/dnsapi
docker run --rm  -it  \
  -v "$(pwd)/acme":/acme.sh  \
  --net=host \
  -e "DP_Id=xxxx" \
  -e "DP_Key=xxxx" \
  neilpang/acme.sh  --issue \
    --dns dns_dp \
    -d "razeen.me" \
    -d "*.razeen.me" \
    -d "*.pages.razeen.me" \
    --keylength ec-256 \
    --dnssleep 300 \
    --force

这样证书就申请好了,在$(pwd)/acme目录下可找到对应目录及文件。

自建 Nginx

由于机器上我有一些其他服务要用 Nginx, 我就统一用了同一个 Nginx, 配置如下。

  • Gitlab 服务
server {
  listen 443 ssl http2;

  server_name gitlab.razeen.me;
  server_tokens off; ## Don't show the nginx version number, a security best practice

  ## Increase this if you want to upload large attachments
  ## Or if you want to accept large git objects over http
  client_max_body_size 0;

  ## Strong SSL Security
  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
  ssl_certificate              /etc/nginx/ssl/razeen_wildcard.crt;
  ssl_certificate_key          /etc/nginx/ssl/razeen_wildcard.key;

  ssl_verify_client optional;
  ssl_client_certificate /etc/nginx/ssl/myroot.pem;
  ssl_verify_depth 1;


  # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
  ssl_protocols  TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers off;
  ssl_session_tickets off;
  ssl_session_timeout  1d;

  access_log  /var/log/nginx/access_gitlab.log;
  error_log   /var/log/nginx/error_gitlab.log;


  ## HSTS Config
  ## https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
  add_header Strict-Transport-Security "max-age=63072000";

  # Rails sets a default policy of strict-origin-when-cross-origin, so
  # hide that and just send the one we've configured for nginx
  proxy_hide_header Referrer-Policy;
  add_header Referrer-Policy strict-origin-when-cross-origin;


  if ($http_host = "") {
    set $http_host_with_default "gitlab.razeen.me";
  }

  if ($http_host != "") {
    set $http_host_with_default $http_host;
  }



  ## https://github.com/gitlabhq/gitlabhq/issues/694
  ## Some requests take more than 30 seconds.
  proxy_read_timeout      3600;
  proxy_connect_timeout   300;
  proxy_redirect          off;
  proxy_http_version 1.1;

  proxy_set_header Host $http_host_with_default;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header X-Forwarded-Ssl on;

  proxy_set_header             X-Real-IP         $real_addr;
  proxy_set_header             X-Forwarded-For   $forwarded_for;
  proxy_set_header             X-Forwarded-Proto https;

  location / {
    proxy_cache off;
    proxy_pass  http://127.0.0.1:19080;
  }
}
  • 镜像仓库配置

server {
  listen 443 ssl;
  server_name register.razeen.me;
  server_tokens off; ## Don't show the nginx version number, a security best practice

  client_max_body_size 0;
  chunked_transfer_encoding on;

  ## Strong SSL Security
  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
  ssl_certificate              /etc/nginx/ssl/razeen_wildcard.crt;
  ssl_certificate_key          /etc/nginx/ssl/razeen_wildcard.key;

  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
  ssl_protocols  TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers off;
  ssl_session_tickets off;
  ssl_session_timeout  1d;


  ## HSTS Config
  ## https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
  add_header Strict-Transport-Security "max-age=63072000";

  access_log  /var/log/nginx/access_gitlab_registry.log;
  error_log   /var/log/nginx/error_gitlab_registry.log;

  location / {

    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 https;
    proxy_set_header X-Forwarded-Ssl on;

    proxy_read_timeout                  900;
    proxy_cache off;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_http_version 1.1;

    proxy_pass          http://127.0.0.1:19050;
  }
}
  • Pages 配置
server {
  listen 443 ssl http2;
  server_name  ~^(?<group>.*)\.pages\.razeen\.cn$;
  server_tokens off; ## Don't show the nginx version number, a security best practice

  ## Disable symlink traversal
  disable_symlinks on;

  ## Strong SSL Security
  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
  ssl_certificate              /etc/nginx/ssl/razeen_wildcard.crt;
  ssl_certificate_key          /etc/nginx/ssl/razeen_wildcard.key;


  # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
  ssl_protocols  TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers off;
  ssl_session_tickets off;
  ssl_session_timeout  1d;

  access_log  /var/log/nginx/access_gitlab_pages.log;
  error_log   /var/log/nginx/error_gitlab_pages.log;

  ## HSTS Config
  ## https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
  add_header Strict-Transport-Security "max-age=63072000";



  # Pass everything to pages daemon
  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_set_header             X-Real-IP         $real_addr;
    proxy_set_header             X-Forwarded-For   $forwarded_for;
    proxy_set_header             X-Forwarded-Proto https;

    proxy_cache off;
    proxy_pass          http://127.0.0.1:19080;
  }
}

配置好后,我们就可以愉快的通过 HTTPS 访问了。到这我们 Gitlab 就搭建好了,功能使用我们就可以后面慢慢折腾啦。

最后,看一下我的管理界面(我还拼了个简单的Logo==)。

my-gitlab-admin