オンプレGitLabでgit+CI+npmサーバー2024 の履歴(No.7)
更新自前サーバーで GitLab を動かしてプライベートな npm プロジェクトなどを置きたい†
GitLab は、
- GitHub のように使える git 利用開発支援機能
- テストやビルドやデプロイを自動化する CI サーバー機能
- npm パッケージサーバー機能
など、さまざまな機能を兼ね備えるフリーソフト。
自前のサーバーにインストールして動かせる。
GitLab を動かすには 4GB 以上のメモリが必要で、しばらく前だと二の足を踏んでいたのだけれど今なら軽いはず。
Docker を使ってサクッと動かす。(動かせるといいな)
今のところ、
- docker で GitLab を動かす
- ホストの apache2 をプロキシサーバーとして外からの接続を docker との間で中継する
- docker で GitLab Runner を動かす
- GitLab に Runner を登録する(shell モード)
- CI/CD で成果物を .zip としてダウンロード可能にする
ところまで基本を押さえることができました。
- GitLab に Runner を登録する(docker モード)
- GitLab の npm パッケージサーバーへパッケージを Deploy する
はこれからです。
目次†
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 で失敗する。
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 ユーザーを使って普段使いのユーザー(以下では "myname" とする)を作っておく。
自分で変更した root のパスワードを忘れてしまった場合†
root のパスワードを自分で変更して、その後忘れてしまうと困ったことになる。
そんな時は、
にあるように、
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 で実際にジョブを実行するサーバーは GitLab Runner と呼ばれる。
同時に使用する人数と比較すると今使っている物理サーバーには余裕があるので、 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 一覧に正しく追加される。
ERROR: Verifying runner... failed → extra_hosts の設定が必要?†
何らかの事情で Runner の docker 内部から myserver.com で apache2 の動くサーバーへ到達できない場合には(LAN 内で ローカル IP を持っている場合など)、
$ docker compose exec runner \
gitlab-runner register \
--url https://myserver.com/gitlab \
--token glrt-iqghvxb-GLHJG9WsFPT6
Enter the GitLab instance URL (for example, https://gitlab.com/):
[https://myserver.com/gitlab]: <ENTER>
ERROR: Verifying runner... failed runner=yFiGd5DTA status=couldn't execute POST against https://myserver.com/gitlab/api/v4/runners/verify: Post "https://myserver.com/gitlab/api/v4/runners/verify": dial tcp xx.xx.xx.xx:443: connect: connection refused
PANIC: Failed to verify the runner.
のように connection refused というエラーが出て失敗する。
このときは docker-compose.yml 内で runner に
extra_hosts:
- myserver.com:192.168.0.2
のようなのを追加して https://myserver.com/gitlab でサーバーへ到達できるようにしておく必要がある。
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
- Project name: gitlab-ci-hello
- Project url: https://myserver.com/gitlab/myname/gitlab-ci-hello
- Visibility Level: private
- Project Configuration: README のチェックを外す
そして 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 の画面で確認すると、
こちらのようにコミット番号の隣に緑のチェックマークがついて、 ジョブが成功したことを確認できる。
このチェックをクリックして中を見ると、
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
用語の整理:
- パイプラインは複数のステージから構成される
- 個々のステージは並列実行可能な複数のジョブから構成される
- 個々のステージは前のステージのジョブがすべて成功してから次へ進む
node 環境を準備&ビルド&テスト†
例えば、以下の .gitlab_ci.yml と package.json をコミットしてみる。
.gitlab_ci.yml
variables:
NODE_VERSION: 22
NVM_VERSION: v0.40.0
stages:
- build
- test
- package
cache:
paths:
- dist/*
# common setting for each job
default:
before_script:
- ls -d "$HOME/.nvm" || (curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash)
- export NVM_DIR="$HOME/.nvm"
- \[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
- nvm --version
- nvm use ${NODE_VERSION} || nvm install ${NODE_VERSION}
# each job is associated to a stage
build:
stage: build
script:
- echo $CI_PIPELINE_SOURCE
- echo $CI_COMMIT_REF_NAME
- echo $CI_COMMIT_TAG
- echo $CI_COMMIT_BRANCH
- npm run lint
- npm run build
environment: production
test:
stage: test
script:
- npm run test:unit --run
package:
stage: package
only:
- tags
except:
- branches
script:
- ls dist
artifacts:
name: mypackage-${CI_COMMIT_TAG}.tar.gz
paths:
- dist/*
package.json
LANG:console
{
"name": "mypackage",
"version": "0.0.1",
"scripts": {
"lint": "echo 'lint - success!'",
"build": "mkdir -p dist && (echo 'Hello!' > dist/hello.txt) && echo 'build - success!'",
"test:unit": "echo 'test:unit - success!'"
}
}
すると build と test に成功して、
build の結果:
LANG:console
Running with gitlab-runner 17.3.1 (66269445)
on bee01 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...
Reinitialized existing Git repository in /home/gitlab-runner/builds/t2X9wkLjw/0/gitlab/osamu/gitlab-ci-hello/.git/
Checking out 504e92af as detached HEAD (ref is master)...
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:07
$ ls -d "$HOME/.nvm" || (curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash)
ls: cannot access '/home/gitlab-runner/.nvm': No such file or directory
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16555 100 16555 0 0 59336 0 --:--:-- --:--:-- --:--:-- 59336
=> Downloading nvm from git to '/home/gitlab-runner/.nvm'
=> Cloning into '/home/gitlab-runner/.nvm'...
* (HEAD detached at FETCH_HEAD)
master
=> Compressing and cleaning up git repository
=> Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.zshrc, and ~/.profile.
=> Create one of them and run this script again
OR
=> Append the following lines to the correct file yourself:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
=> Installing Node.js version 22
Downloading and installing node v22.8.0...
Downloading https://nodejs.org/dist/v22.8.0/node-v22.8.0-linux-x64.tar.gz...
######################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v22.8.0 (npm v10.8.2)
Creating default alias: default -> 22 (-> v22.8.0 *)
=> Node.js version 22 has been successfully installed
=> Close and reopen your terminal to start using nvm or run the following to use it now:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
$ export NVM_DIR="$HOME/.nvm"
$ \[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
$ nvm --version
0.40.0
$ nvm use ${NODE_VERSION} || nvm install ${NODE_VERSION}
Now using node v22.8.0 (npm v10.8.2)
$ npm run lint
> mypackage@0.0.1 lint
> echo 'lint - success!'
lint - success!
$ npm run build
> mypackage@0.0.1 build
> mkdir -p dist && (echo 'Hello!' > dist/hello.txt) && echo 'build - success!'
build - success!
Cleaning up project directory and file based variables 00:00
Job succeeded
test の結果:
LANG:console
Running with gitlab-runner 17.3.1 (66269445)
on bee01 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:01
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /home/gitlab-runner/builds/t2X9wkLjw/0/gitlab/osamu/gitlab-ci-hello/.git/
Checking out ae25c69e as detached HEAD (ref is master)...
Removing dist/
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:00
$ ls -d "$HOME/.nvm" || (curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash)
/home/gitlab-runner/.nvm
$ export NVM_DIR="$HOME/.nvm"
$ \[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
$ nvm --version
0.40.0
$ nvm use ${NODE_VERSION} || nvm install ${NODE_VERSION}
Now using node v22.8.0 (npm v10.8.2)
$ npm run test:unit --run
> mypackage@0.0.1 test:unit
> echo 'test:unit - success!'
test:unit - success!
Cleaning up project directory and file based variables 00:00
Job succeeded
となる。
ちゃんと初回に node がインストールされて、2回目はそれが再利用されている。
ちゃんと test をするときは report を作成するといいらしい
https://docs.gitlab.com/17.3/ee/ci/testing/unit_test_reports.html
パッケージング†
まず、上で
cache:
paths:
- dist/*
をしておかないと build で作成したファイルが package に引き継がれないので注意が必要だ。
そして package ステージには
only:
- tags
except:
- branches
がついているので、tag を付けたときで、なおかつそのタグがデフォルトブランチ(ここでは master)についてないとスクリプトは実行されない。
- https://stackoverflow.com/questions/42796018/how-to-run-a-gitlab-ci-yml-job-only-on-a-tagged-branch
- https://stackoverflow.com/questions/69199614/ci-commit-tag-in-if-statemets-of-regular-job
あたりを参照。
試してみよう
GitLab 画面のプロジェクトページの左上 "+" のドロップダウンから New Tag を選んで、
https://myserver.com/gitlab/myname/mypackage/-/tags/new
から 0.0.1 というタグを作成する。
・・・ん? 新しいパイプラインが生成されないような???
https://forum.gitlab.com/t/pipeline-not-executed-after-commit/87173/6
によると GitLab と Runner のバージョンを合わせた方がいいと書かれてる?
GitLab のバージョンは、
$ docker compose exec web gitlab-rake gitlab:env:info
とするか、GitLab 画面左下の Help ボタンを押すことで確認できる。
ここでは 17.3.1 だった。
Runner のバージョンは GitLab の admin メニューから CI/CD - Runners で
https://myserver.com/gitlab/admin/runners
ここから個々の Runner をクリックして show detail すると、、、17.3.1 なので問題なし。
ああ、違った。
ちゃんと動いているけれど、トップ画面の緑色のチェックマークはあくまでコミットに対する CI/CD の結果で、タグに対する CI/CD の結果は Tags のページでタグの横に現れるのか。
個別のタグのページに CI/CD の結果を表示してくれないので混乱した。
https://myserver.com/gitlab/myname/gitlab-ci-hello/-/tags/0.0.1
パイプラインがすべて正しく実行されると、
https://myserver.com/gitlab/myname/gitlab-ci-hello/-/tags
のタグの横に緑のチェックが出て、その右のダウンロードメニューに artifact - package が現れる。
選択すると mypackage-0.0.1.tar.gz を落とせた。
メニュー自体の表示を mypackage-0.0.1.tar.gz にすることはできないのかな???
TODO: リリース時にこのアーティファクトを参照する方法も調べる
GitLab に Runner を登録する(docker モード)†
node は sudo の必要なくインストールできるので shell モードで簡単に動かせたけれど、 例えば playwright を動かそうとすると apt などでネイティブなパッケージをいろいろ入れなければならず、 困ってしまう。
そういう時は
https://qiita.com/yusayoshi/items/6b48bca5b5c0a17cd40e#gitlab-cicd
のように runner を docker モードで動かしてやればいいいいみたい。
これは、docker の中で走っている Runner が、さらに docker を起動して ci スクリプトをその docker の中で実行させるというもの。いわゆる dind (docker-in-docker) という技術らしい。Runner の docker コンテナを作る際に /var/run/docker.sock を受け渡しているおかげでそういうことができるのだとか。
Runner を docker モードで動かすには 上記手順で Runner を GitLab へ追加する際に Executor を shell ではなく docker とする。
すると、デフォルトで使う docker image を聞かれる。
ここでは主に node 上での開発を考えているので playwright が使えるようリンク先にあった
mcr.microsoft.com/playwright:focal
を指定した。
ci スクリプトから image を指定されないときにはこれが使われることになる。 スクリプトで image 指定すれば別の image を使うこともできる。
extra_hosts を設定する†
上で runner に extra_hosts を追加している場合には、
runner/config.toml に、
[[runners]]
[runners.docker]
extra_hosts = ["myserver.com:192.168.0.2"]
の設定をしないと、runner docker 内部で作成される docker コンテナに hosts の設定が引き継がれないことに注意が必要。
試してみる†
これで始めから npm や playwright の使える環境で ci スクリプトを走らせることができるようになったはず。
上のスクリプトの before_script をバージョン確認だけにしてみた。
default:
before_script:
- node --version
- npm --version
すると、
LANG:console $ node --version v20.16.0 $ npm --version 10.8.1
と表示され、残りのスクリプトも正しく実行された。
GitLab の npm パッケージサーバーへパッケージを Deploy する†
GitLab には npm パッケージサーバーの機能があるので、 そこへパッケージを Deploy してみよう。
GitHub のプロジェクトをクローンして GitLab へ登録する†
まず、こちらで作った typescript-vitest-skeleton という GitHub プロジェクトをクローンして、 GitLab へ登録しなおす
GitLab 上で typescript-vitest-skeleton という空のプロジェクトを作成しておいて、
LANG:console $ git clone https://github.com/osamutake/typescript-vitest-skeleton.git Cloning into 'typescript-vitest-skeleton'... $ cd typescript-vitest-skeleton/ $ npm i $ git remote add origin2 https://myserver.com/gitlab/myname/typescript-vitest-skeleton.git $ git push origin2 --all
左のメニューの Deploy - Package Registray からこの GitLab プロジェクトのパッケージレジストリを確認できる。
https://myserver.com/gitlab/myname/typescript-vitest-skeleton/-/packages
当然今は空だ。
ここに上記 npm パッケージを登録したい。
パッケージ名のスコープ†
GitLab プロジェクトのパッケージレジストリへパッケージを登録するには、
https://myserver.com/gitlab/api/v4/projects/(project id)/packages/npm/@(scope_name)/(package_name)
のようなアドレスへパッケージを PUT することになる。
ここで、
- project id : この GitLab サーバーのプロジェクトにつけられた通し番号
- プロジェクトのトップページ https://myserver.com/gitlab/myname/typescript-vitest-skeleton の右上の縦に3つ並んだ点のアイコン(More actions)をクリックして "Copy Project ID: 9" をクリックするとコピーできる
- scope_name : npm ではパッケージ名の前に @ユーザー名 を付けることでスコープ付きにして、他のパッケージと名前が被らないようにしますが、それと似たような識別子
- GitLab で使うときは GitLab サーバーを識別するために使うことになるみたい?
- package_name : 例えば上の typescript-vitest-skeleton
まだよくわかっていないのだけれど、どうやら GitLab の提供する npm パッケージサーバーからパッケージをダウンロードさせたい場合「"@osamu_takeuchi/*" のように @osamu_takeuchi というスコープがついているパッケージは npm ではなく特定の GitLab サーバーを探しに行け」という設定をすることになるみたいなので、パッケージ名を例えば @myserver/typescript-vitest-skeleton というような、分かりやすいスコープ付きにしておくのが良さそう?
LANG:console $ git remote remove origin $ git remote remove origin2 $ git remote add origin https://myserver.com/gitlab/myname/typescript-vitest-skeleton.git $ sed -i.bak s/@osamu_takeuchi/@myserver/ package.json $ git add package.json $ git commit -m "Scope of package is changed" $ git push origin
デプロイ用のトークンを発行して .npmrc を設定する†
パッケージのアップロードには個々のプロジェクトからのアクセス許可が必要なので、
プロジェクトの Settings - Repository - Deploy Tokens - Add token からトークンを発行する。
https://myserver.com/gitlab/myname/typescript-vitest-skeleton/-/settings/repository
GitLab はいろんなところでいろんな用途のトークンを発行できるので、 違うところで違う用途のトークンを発行して設定して、動かないなあ、となることが多い(汗
- Name を npm push とする
- write_package_registry にチェックを入れる
- [Create deploy token] を押す
- 次の画面で gldt-XXXXXXXXXXXXXXXX のようなトークンをコピーする
プロジェクトのフォルダーにこのトークンを指定した .npmrc を作成する。
LANG:console $ echo ".npmrc" >> .gitignore $ cat <<"EOS" >.npmrc //myserver.com/gitlab/api/v4/projects/9/packages/npm/:_authToken=gldt-XXXXXXXXXXXXXXXXX @myserver:registry=https://myserver.com/gitlab/api/v4/projects/9/packages/npm/ EOS
このファイルを GitLab へアップロードしてしまうと誰でもデプロイできるようになってしまうので、 必ず .gitignore に追加しておく必要がある。
手動でデプロイする†
後は普通に npm publish すればいい。
LANG:console $ npm publish npm notice Publishing to https://myserver.com/gitlab/api/v4/projects/9/packages/npm/ with tag latest and default access + @myserver/mypackage@0.0.1
これでパッケージがデプロイされ、Package Registry に
@myserver/mypackage (latest) 0.0.1 npm
のような項目が現れる。
TODO: プロジェクトじゃなくグループ単位のレジストリを使った方が良いのかも?
TODO: ci スクリプトから自動的にデプロイする方法は?
特に Deploy Token をどのように CI スクリプトに渡せばいいのかが想像つかない???
Package Registry のパッケージを npm install する†
https://myserver.com/gitlab/myname/typescript-vitest-skeleton/-/packages
の一覧から先にデプロイした 0.0.1 をクリックすると、
LANG:console $ echo @myserver:registry=https://myserver.com/gitlab/api/v4/packages/npm/ >> .npmrc $ npm i @myserver/mypackage
のようにすればインストールできると書かれていた。
ただし認証が必要になると。
ここでは読み取りのみの権限があればいいので、
トップページのサイドバーの右上アイコンから Edit Profile、サイドバーの User settings - Access Tokens - Add new token を選択。
https://myserver.com/gitlab/-/user_settings/personal_access_tokens
- Token name を例えば npm install とかにして
- read_api だけチェックして
- Expiration date を適当に延ばして [Create personal access token]
- 次のページでトークンをコピーする (glpat-XXXXXXXX みたいなの)
そして、
https://docs.gitlab.com/ee/user/packages/npm_registry/#authenticate-to-the-package-registry
を見ながら、
LANG:console $ npm config set @myserver:registry https://myserver.com/api/v4/packages/npm/ $ npm config set -- //myserver.com/api/v4/packages/npm/:_authToken=glpat-XXXXXXXX $ cat ~/.npmrc @myserver:registry=https://myserver.com/api/v4/packages/npm/ //myserver.com/api/v4/packages/npm/:_authToken=glpat-XXXXXXXX
これらが ~/.npmrc に書き込まれるのでその後は自由に npm i が使えるはず。
試しに、
LANG:console
$ mkdir ~/test_npm_install
$ cd ~/test_npm_install
$ npm init
{
"name": "test_npm_install",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": ""
}
$ npm install @myserver/mypackage
npm error code E404
npm error 404 Not Found - GET https://myserver.com/api/v4/packages/npm/@myserver%2fmypackage
npm error 404
npm error 404 '@myserver/mypackage@*' 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.
ん?そうでもないぞ。
そんなパッケージは見つからないと言われる・・・って URL を指定し間違っていた。
今は gitlab/ というサブフォルダで gitlab を動かしているので GitLab が教えてくれていた通り、
LANG:console $ npm config set @myserver:registry https://myserver.com/gitlab/api/v4/packages/npm/ $ npm config set -- //myserver.com/gitlab:_authToken=glpat-XXXXXXXX
が正しい。
でもそうしたら今度は
LANG:console $ npm install @myserver/mypackage npm error code E404 npm error 404 Not Found - GET https://registry.npmjs.org/@myserver%2fmypackage - Not found npm error 404 npm error 404 '@myserver/mypackage@*' 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.
となってしまった。
URL のパスが api から始まっていないと認識してくれない???
手で試してみると、
https://myserver.com/gitlab/api/v4/packages/npm/@myname%2fmypackage
へアクセスすると
https://registry.npmjs.org/@takenchi%2fmypackage
へのリダイレクトを返してくるようだ。
適当に、絶対存在しないパッケージ名を与えても同じ動作をするので、恐らく自分が持っていないパッケージに対するフォールバック動作がこれみたい。
つまり、プロジェクトへ Deploy したパッケージがここに見つからない??
なんでだろう???
いろいろ試すと、
- https://myserver.com/gitlab/api/v4/packages/npm/@myname%2fmypackage
- https://myserver.com/gitlab/api/v4/packages/npm/@myname/mypackage
- https://myserver.com/gitlab/api/v4/project/9/packages/npm/@myname%2fmypackage
- https://myserver.com/gitlab/api/v4/project/9/packages/npm/@myname/mypackage
- metadata.json が返る → これが正解っぽい
つまり https://myserver.com/gitlab/api/v4/project/9/packages/npm/@myname/mypackage へアップロードしたのだから同じアドレスへ取りに来いと。
至極当然なのだけれど、それぞれ異なるプロジェクトで作って異なるプロジェクトにアップロードしたパッケージについて、それぞれどこにダウンロードしに行くかプロジェクト番号を覚えておかなければならないのは面倒くさすぎる。
たぶんプロジェクトへアップロードしたのが間違いで、初めから https://myserver.com/gitlab/api/v4/packages/npm/ へアップロードすべきだったと思われる?

