オンプレGitLabでgit+CI+npmサーバー2024 の履歴(No.5)

更新


プログラミング/svelte

自前サーバーで GitLab を動かしてプライベートな npm プロジェクトなどを置きたい

GitLab は、

  • GitHub のように使える git 利用開発支援機能
  • テストやビルドやデプロイを自動化する CI サーバー機能
  • npm パッケージサーバー機能

など、さまざまな機能を兼ね備えるフリーソフト。

自前のサーバーにインストールして動かせる。

GitLab を動かすには 4GB 以上のメモリが必要で、しばらく前だと二の足を踏んでいたのだけれど今なら軽いはず。

Docker を使ってサクッと動かす。(動かせるといいな)

目次

GitLab サーバーを docker compose で動かす

https://gitlab-docs.creationline.com/ee/install/docker.html#install-gitlab-using-docker-compose

を見ながら docker イメージで動作するよう設定する。

  • ホストサーバーには docker 環境があって、自分が管理者である
    • gitlab は docker 内で動かす
  • ホストサーバーには apache2 が https://myserver.com/ への通信を受け付ける状況になっている
  • https://myserver.com/gitlab/ というアドレスへの通信を docker 内の gitlab サーバーへ繋ぐ

という形で GitLab を動かします。

LANG:console
$ cd ~
$ mkdir gitlab
$ cd gitlab
$ echo GITLAB_HOME=`pwd` > .env
$ cat <<"EOS" > docker-compose.yml
services:
  web:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://myserver.com/gitlab'
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        gitlab_rails['gitlab_shell_ssh_port'] = 2224
    ports:
      - '8980:80'
    volumes:
      - '$GITLAB_HOME/etc:/etc/gitlab'
      - '$GITLAB_HOME/log:/var/log/gitlab'
      - '$GITLAB_HOME/data:/var/opt/gitlab'
    shm_size: '256m'
EOS
$ docker compose up -d
[+] Running 10/10
 ✔ web Pulled                               58.2s 
   ✔ 857cc8cb19c0 Pull complete              2.1s 
   ✔ 28812802a434 Pull complete              2.1s 
   ✔ 54e2e989e54c Pull complete              3.0s 
   ✔ abb7892b26dc Pull complete              3.0s 
   ✔ e9d667f5a8c1 Pull complete              3.0s 
   ✔ a8891519352d Pull complete              3.1s 
   ✔ 8b624a00a604 Pull complete              3.1s 
   ✔ 0cf3370d74b6 Pull complete              3.1s 
   ✔ 3253094bd895 Pull complete             55.9s 
[+] Running 2/2
 ✔ Network gitlab_default  Created           0.0s 
 ✔ Container gitlab-web-1  Started           0.7s 

これで docker 内で GitLab サーバーが立ち上がる。

全体としての注意

上記のようにして動かすと、etc/ フォルダに etc/gitlab.rb というのができて、 これを書き換えれば設定を変えられる。

設定項目についてはこちらに説明がある。
https://gitlab-docs.creationline.com/omnibus/settings/configuration.html

また、ファイルの冒頭には以下の注意書きがある。

## GitLab configuration settings
##! This file is generated during initial installation and **is not** modified
##! during upgrades.
##! Check out the latest version of this file to know about the different
##! settings that can be configured, when they were introduced and why:
##! https://gitlab.com/gitlab-org/omnibus-gitlab/blame/master/files/gitlab-config-template/gitlab.rb.template
 
##! Locally, the complete template corresponding to the installed version can be found at:
##! /opt/gitlab/etc/gitlab.rb.template
 
##! You can run `gitlab-ctl diff-config` to compare the contents of the current gitlab.rb with
##! the gitlab.rb.template from the currently running version.
 
##! You can run `gitlab-ctl show-config` to display the configuration that will be generated by
##! running `gitlab-ctl reconfigure`
 
##! In general, the values specified here should reflect what the default value of the attribute will be.
##! There are instances where this behavior is not possible or desired. For example, when providing passwords,
##! or connecting to third party services.
##! In those instances, we endeavour to provide an example configuration.
 
## GitLab URL
##! URL on which GitLab will be reachable.
##! For more details on configuring external_url see:
##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab
##!
##! Note: During installation/upgrades, the value of the environment variable
##! EXTERNAL_URL will be used to populate/replace this value.
##! On AWS EC2 instances, we also attempt to fetch the public hostname/IP
##! address from AWS. For more details, see:
##! https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
# external_url 'GENERATED_EXTERNAL_URL'
 
## Roles for multi-instance GitLab
##! The default is to have no roles enabled, which results in GitLab running as an all-in-one instance.
##! Options:
##!   redis_sentinel_role redis_master_role redis_replica_role geo_primary_role geo_secondary_role
##!   postgres_role consul_role application_role monitoring_role
##! For more details on each role, see:
##! https://docs.gitlab.com/omnibus/roles/index.html#roles
##!
# roles ['redis_sentinel_role', 'redis_master_role']
 
## Legend
##! The following notations at the beginning of each line may be used to
##! differentiate between components of this file and to easily select them using
##! a regex.
##! ## Titles, subtitles etc
##! ##! More information - Description, Docs, Links, Issues etc.
##! Configuration settings have a single # followed by a single space at the
##! beginning; Remove them to enable the setting.
 
##! **Configuration settings below are optional.**

一方、例えば data/nginx/conf/gitlab-http.conf に nginx 関連の設定ファイルが見つかるのだけれど、 こちらの設定ファイルはサーバーを立ち上げ直すと gitlab.rb の内容を元に自動的に生成されるものなので、 手で書きかえてはいけない。

ちゃんと冒頭に

# This file is managed by gitlab-ctl. Manual changes will be
# erased! To change the contents below, edit /etc/gitlab/gitlab.rb
# and run `sudo gitlab-ctl reconfigure`.

などと書かれている。

etc/gitlab.rb を書き換えてしまうと設定情報が docker-compose.yml と gitlab.rb とに分かれてしまうので、どちらか一方にまとめた方がいいのかもしれない。

単純な見やすさからすると docker-compose.yml に書く方が良さそうなのだけれど、 gitlab-ctl diff-config を使うなら gitlab.rb でもいいのかもしれない。

docker コンテナの外から確認するなら:

LANG:console
$ docker compose exec web gitlab-ctl diff-config

ポートの指定

外からの接続を受ける apache2 と同じマシンに置くのであれば docker-compose.yml の

     ports:
       - '8980:80'

のところは

     ports:
       - '127.0.0.1:8980:80'

として、外からの接続が直接 docker へ行かないようにする。

docker でポートを開けると ufw などのファイアウォールで許可してなくても 外向きにポートが開いてしまうので十分注意する。

https を名乗りつつ http で待ち受ける

gitlab の設定で

      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://myserver.com/gitlab'
        nginx['listen_port'] = 80
        nginx['listen_https'] = false

としている理由は以下の通り。

この docker イメージは external_url の設定を見て、内部の nginx で 80 番で http を待つか、443 番で https を待つかを決めている。

「どちらか片方しか有効にならない」というのが重要な点。

今実現したい構成では、外部から見た gitlab サーバーのアドレスは https://myserver.com/gitlab で https 接続になるのだけれど、その暗号化通信は間に入る apache2 が受け持つので docker 内の nginx への接続は http になる。

external_url を https としてしまうと gitlab docker は nginx を 443 番で https を待つように設定してしまい 80 番の http では繋がらなくなってしまう。

そこで 80 番で http を待つように設定しているのがこの部分だ。

サーバーに繋ぎに行って「接続をリセットされました」みたいになるときは、

LANG:console
$ sudo less data/nginx/conf/gitlab-http.conf

として gitlab 関連の nginx の設定を確かめるといい。

(これに気付くのにかなり時間がかかりました・・・)

GITLAB_OMNIBUS_CONFIG で指定可能なその他の設定

GITLAB_OMNIBUS_CONFIG では

LANG:console
$ sudo less etc/gitlab.rb 

として表示される設定項目に値を指定できるので、 「こんなことできないのかな」と思ったときにはじっくり読むといい。

apache2 をプロキシサーバーとして接続を中継させる

ホストマシンの /etc/apache2/sites-enabled/default-ssl.conf に

<IfModule mod_proxy.c>
    ProxyRequests Off
    <Proxy *>
        Require all granted
    </Proxy>

    AllowEncodedSlashes NoDecode
    <Location /gitlab>
        Order deny,allow
        Allow from all
    </Location>
    RequestHeader set X_FORWARDED_PROTO 'https'
    ProxyPass /gitlab http://localhost:8980/gitlab
    ProxyPassReverse /gitlab http://localhost:8980/gitlab
</IfModule>

と設定して、

LANG:console
$ sudo a2enmod proxy
$ sudo service apache2 reload

とすることで apache2 がプロキシサーバーとして振る舞い、 https://myserver.com/gitlab 以下へのアクセスを http://localhost:8929/gitlab へ転送してくれる。

ここで重要なのが AllowEncodedSlashes NoDecode だ。

これをしておかないと、後々 GitLab を npm パッケージサーバーとして使おうとした際に、パッケージリポジトリへの PUT が 404 で失敗する。

https://stackoverflow.com/questions/20496963/avoid-nginx-decoding-query-parameters-on-proxy-pass-equivalent-to-allowencodeds

LANG: console
$ npm publish    # 他の設定が終わってからの話
...
npm error code E404
npm error 404 Not Found - PUT https://myserver.com/gitlab/api/v4/projects/1/packages/npm/@myscope%2fmypackage
npm error 404
npm error 404  '@myscope/mypackage@0.0.1' is not in this registry.
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.

のように、npm publish で認証は通過しているのに、そして、アップロードしようとしているのに 404 で落ちるていたらこの設定を見直すといい。

メールを送れるように設定する

GITLAB_OMNIBUS_CONFIG に

gitlab_rails['gitlab_email_from'] = 'gitlab@myserver.com'
gitlab_rails['gitlab_email_display_name'] = 'GitLab'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.server"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "smtp user"
gitlab_rails['smtp_password'] = "smtp password"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = false
gitlab_rails['smtp_pool'] = false

あたりを追加する。

設定の仕方はこちらを参照:
https://gitlab-docs.creationline.com/omnibus/settings/smtp.html

root でログインする

初期設定で root という管理者ユーザーが登録されているので、 ウェブサーバーから https://myserver.com/gitlab へアクセスして root でログインする。

管理者 root の初期パスワードは gitlab の docker-compose.yml を作ったフォルダの下の etc フォルダを調べるとわかる。

LANG:console
$ sudo cat etc/initial_root_password 

自分で変更した root のパスワードを忘れてしまった場合

https://blog.k-bushi.com/post/tech/environment/construct-gitlab-runner-docker/#gitlab%E3%81%B8%E3%81%AE%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3

にあるように、

LANG:console
$ docker compose exec web gitlab-rake "gitlab:password:reset"
Enter username: root
Enter password: 
Confirm password: 
Password successfully updated for user with username root.

とすればパスワードを設定しなおせるらしい。

GitLab Runner も docker で動かす

同時に使用する人数と比較するとこのサーバーには余裕があるので、 CI サーバーも同じホストで動かしてしまう。

先の docker-compose.yml に以下を追加する。

  runner:
    image: 'gitlab/gitlab-runner:latest'
    restart: unless-stopped
    volumes:
      - '$GITLAB_HOME/runner:/etc/gitlab-runner'
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - '8093:8093'

そして、

LANG:console
$ sudo docker compose up -d

runner を GitLab に追加する

GitLab 画面で新しい Runner インスタンスを作成

https://myserver.com/gitlab/admin/runners

から右上の [New Instance Runner] を押す。

ここでは特別な設定をしないごく一般的な shell の動くサーバーを建てるので、

x Run untagged jobs のチェックを付けて [Create runner]

docker で動かした Runner と対応付ける

次の画面の Step 1 となっているところで

$ gitlab-runner register
   --url https://myserver.com/gitlab
   --token glrt-iqghvxb-GLHJG9WsFPT6

のようなところをコピーする。

ちょっと手直しをして次の形にして Runnner を起動した docker-compose.yml のあるフォルダで実行。

$ docker compose exec runner \
   gitlab-runner register \
       --url https://myserver.com/gitlab \
       --token glrt-iqghvxb-GLHJG9WsFPT6

コマンドを起動するといくつか質問に答えることになる。

  • GitLab instance URL には指定した https://myserver.com/gitlab が入っているのでそのまま ENTER
  • Enter a name for the runner にはこの Runner を識別する名前を付ける
  • Enter an executor には shell を指定

これで Runner 一覧に正しく追加される。

CI 動作を試してみる

LANG: console
$ mkdir ~/gitlab-ci-hello
$ cd ~/gitlab-ci-hello
$ cat <<"EOS" > .gitlab-ci.yml 
build:
  script:
    - echo hello `pwd`
    - ls -la
EOS
$ git init
$ git add .
$ git commit -m "Initial commit"

として .gitlab-ci.yml だけをコミットした git リポジトリを作成する。

GitLab 上でブランクプロジェクトを作ってそこへコミットしてみる。

https://myserver.com/gitlab/projects/new#blank_project

そして Create Project

次のページの Push an existing Git repository の手順で push する。

LANG:console
$ git remote add origin https://myserver.com/gitlab/myname/gitlab-ci-hello.git
$ git push --set-upstream origin --all
Username for 'https://myserver.com': myname
Password for 'https://myname@myserver.com': xxxxxx
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 266 bytes | 266.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://myserver.com/gitlab/myname/gitlab-ci-hello.git
 * [new branch]      master -> master
branch 'master' set up to track 'origin/master'.
$ git push --set-upstream origin --tags
Username for 'https://myserver.com': myname
Password for 'https://myname@myserver.com': xxxxxx
Everything up-to-date

push 時には gitlab サーバーのユーザー名とパスワードを聞かれるので入力する。

GitLab の画面で確認すると、

jobs-success.png

こちらのようにコミット番号の隣に緑のチェックマークがついて、 ジョブが成功したことを確認できる。

このチェックをクリックして中を見ると、

LANG:console
Running with gitlab-runner 17.3.1 (66269445)
  on myrunnner1 t2X9wkLjw, system ID: r_FoHQflE05Zou
Preparing the "shell" executor 00:00
Using Shell (bash) executor...
Preparing environment 00:00
Running on 8163caea6de5...
Getting source from Git repository 00:00
Fetching changes with git depth set to 20...
Initialized empty Git repository in /home/gitlab-runner/builds/t2X9wkLjw/0/gitlab/myname/gitlab-ci-hello/.git/
Created fresh repository.
Checking out cc71a4d9 as detached HEAD (ref is master)...
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:00
$ echo hello `pwd`
hello /home/gitlab-runner/builds/t2X9wkLjw/0/gitlab/myname/gitlab-ci-hello
$ ls -la
total 16
drwxrwxr-x 3 gitlab-runner gitlab-runner 4096 Sep  7 13:03 .
drwxrwxr-x 4 gitlab-runner gitlab-runner 4096 Sep  7 13:03 ..
drwxrwxr-x 6 gitlab-runner gitlab-runner 4096 Sep  7 13:03 .git
-rw-rw-r-- 1 gitlab-runner gitlab-runner   53 Sep  7 13:03 .gitlab-ci.yml
Cleaning up project directory and file based variables 00:00
Job succeeded

のようにして、

LANG:console
$ echo hello `pwd`

LANG:console
$ ls -la

が正しく実行されていることを確認できる。

ワーキングフォルダが /home/gitlab-runner の下にあることからもわかるとおり、 このシェルは gitlab-runner というユーザー権限で実行される。

そのままでは sudo は使えないので、システムに変更を加えるようなコマンドは実行できない。

Runner の Dockerfile はこちらにある:
https://hub.docker.com/r/gitlab/gitlab-runner/dockerfile

中身はものすごく古い ubuntu を元にしている?

なんでこんなに古いんだろう???

CI スクリプトの書き方

概要:
https://gitlab-docs.creationline.com/ee/ci/yaml/gitlab_ci_yaml.html

リファレンス:
https://gitlab-docs.creationline.com/ee/ci/yaml/index.html

用語の整理:

  • パイプラインは複数のステージから構成される
  • 個々のステージは並列実行可能な複数のジョブから構成される
  • 個々のステージは前のステージのジョブがすべて成功してから次へ進む

Counter: 49 (from 2010/06/03), today: 19, yesterday: 30