# 如何用 Docker 建制 Self-Host 的 GitLab 和 GitLab CI


近期因為公司的需求打算替換 Gerrit，所以用 Docker 建立了公司內部 Host 的 GitLab 和 GitLab Runner。其中這邊要提到 GitLab Runner 是用來幫 GitLab 跑 CI 的外掛，有點像是 Jenkins 的 Slave Node，用來串接 GitLab CI。

這邊主要分成三個部分

1. 架設 GitLab

1. GitLab Runner 串接

1. Auto Backup and Restore

## 架設 GitLab

### Step 1：

```
docker pull gitlab/gitlab-ce
```


### Step 2：

新增 docker-compose.yml 檔案，其中 `{host_ip}`替換成實際的機器 ip 位址。

```
version: "3.6" 
services:
  web:
    image: 'gitlab/gitlab-ce'
    container_name: 'gitlab'
    restart: always
    hostname: {host_ip}
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://{host_ip}:9090'
        gitlab_rails['gitlab_shell_ssh_port'] = 2224
    networks:
      - gitlab-network
    ports:
      - '80:80'
      - '443:443'
      - '9090:9090'
      - '2224:22'
    volumes:
      - '/srv/gitlab/config:/etc/gitlab'
      - '/srv/gitlab/logs:/var/log/gitlab'
      - '/srv/gitlab/data:/var/opt/gitlab'

networks:
  gitlab-network:
    name: gitlab-network
```


### Step 3：

```
docker-compose up --build --abort-on-container-exit
```


第一次啟動時需等待約 5 分鐘。啟動後使用瀏覽器連接 {host_ip}:9090 到 GitLab 去重新設置密碼。預設 username 是 root。

## GitLab Runner 串接

這邊的話 GitLab Runner 需要準備另一台機器，跟 GitLab 分開。不然 GitLab Runner 在 clone 的時候 URL 的解析會有問題。這部分我也不知道怎麼解決，問了官方也沒有回應。可能是因為我的 GitLab Runner 是使用了 dind （docker in docker）的關係吧。其中 GitLab 可以跟多個 GitLab Runner 串接，Runner 都放在同一台機器是沒有問題的，只是 container 和 volume mount 的地方要不同。

### Step 1：

其中 `{runner-name}` 替換成自己要的名字

```
docker pull gitlab/gitlab-runner
docker run -d --name {runner-name} -v /var/run/docker.sock:/var/run/docker.sock -v /srv/{runner-name}/config:/etc/gitlab-runner --rm gitlab/gitlab-runner
```


### Step 2：

Step 1 啟動後，到 GitLab 裡面的 **Admin Area** &gt; **Overview** &gt; **Runners**。可以看到 Runner Registration Token

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1615084525596/N-OlqOBdq.png)

### Step 3：

將 Step 2 取得的 token 替換掉下面指令中的 `{registration-token}` 並執行。`{gitlab-ip}` 替換為 GitLab 伺服器的 IP 位址。`{runner-name}` 替換為在 Step 1 設定的名字。

```
docker exec -it {runner-name} gitlab-runner register -n --url http://{gitlab-ip}:9090 --registration-token {registration-token} --clone-url http://{gitlab-ip}:9090 --executor docker --docker-image "docker:latest" --docker-privileged
```


## Auto Backup and Restore

### Backup

修改 `/srv/gitlab/config/gitlab.rb` 並增加以下的設定，這邊我是設定備份到 AWS 的 S3。其他的備份點，例如 GCP 或是本地端的可以參考官網。

```
gitlab_rails['backup_keep_time'] = 86400

gitlab_rails['backup_upload_connection'] = {
  'provider' => 'AWS',
  'region' => 'us-west-1',
  'aws_access_key_id' => {access key id},
  'aws_secret_access_key' => {secret access key}
}
gitlab_rails['backup_upload_remote_directory'] = 'gitlab'
```


修改完後，需要讓 GitLab 載入新的 config 設定

```
docker exec -t gitlab-master gitlab-ctl reconfigure
```


產生備份檔案，會自動上傳到 AWS 的 S3

```
docker exec -t gitlab-master gitlab-rake gitlab:backup:create
```


### Restore

1. 依照原本的 docker-compose.yml 重新啟動 GitLab

1. 當 GitLab 重啟完畢後，從 S3 下載備份檔案到 `/srv/gitlab/data/backups` 
`aws s3 cp {s3 backup file url} {backup file name}`

1. 最後執行執行來復原設定
`docker exec -it gitlab-master gitlab-rake gitlab:backup:restore`
其中如果有多個備份檔案在 backups 目錄的話，則需要特別指定是哪個備份檔案
`docker exec -it gitlab-master gitlab-rake gitlab:backup:restore BACKUP={prefix backup file name before gitlab_backup.tar}`

### Cron Job

最後為了讓備份可以自動執行，所以就使用了 Linux 預設的 Cron 來處理。設定每週五的午夜執行備份指令

```
$ crontab -e
0 0 * * FRI docker exec -t gitlab-master gitlab-rake gitlab:backup:create
```


