ラベル gitlab の投稿を表示しています。 すべての投稿を表示
ラベル gitlab の投稿を表示しています。 すべての投稿を表示

2026年7月8日水曜日

Ubuntu glab にコマンドをインストールするスクリプト

Ubuntu glab にコマンドをインストールするスクリプト

概要

シェルスクリプトを紹介します

環境

  • Ubuntu 24.04
  • glab 1.106.0

スクリプト

  • vim install_glab_on_ubuntu.sh
set -euo pipefail

sudo apt-get update
sudo apt-get install -y curl tar jq

ARCH_RAW="$(uname -m)"
case "$ARCH_RAW" in
  x86_64) ARCH_SUFFIX="amd64" ;;
  aarch64|arm64) ARCH_SUFFIX="arm64" ;;
  *)
    echo "Unsupported architecture: $ARCH_RAW" >&2
    exit 1
    ;;
esac

API_URL="https://gitlab.com/api/v4/projects/gitlab-org%2Fcli/releases/permalink/latest"
RELEASE_JSON="$(curl -fsSL "$API_URL")"
TAG_NAME="$(echo "$RELEASE_JSON" | jq -r '.tag_name')"

# ここが重要: 現在の命名は glab_<ver>_linux_<arch>.tar.gz
DOWNLOAD_URL="$(echo "$RELEASE_JSON" | jq -r --arg arch "$ARCH_SUFFIX" '
  .assets.links[]
  | select((.name // "") | test("_linux_" + $arch + "\\.tar\\.gz$"))
  | (.direct_asset_url // .url)
' | head -n1)"

if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then
  echo "No matching asset URL found for arch: $ARCH_SUFFIX" >&2
  echo "DEBUG: available asset names:" >&2
  echo "$RELEASE_JSON" | jq -r '.assets.links[].name' >&2
  exit 1
fi

TMP_DIR="/tmp/glab-install"
TARBALL_PATH="$TMP_DIR/glab.tar.gz"

echo "DEBUG: ARCH_RAW=$ARCH_RAW"
echo "DEBUG: ARCH_SUFFIX=$ARCH_SUFFIX"
echo "DEBUG: API_URL=$API_URL"
echo "DEBUG: TAG_NAME=$TAG_NAME"
echo "DEBUG: DOWNLOAD_URL=$DOWNLOAD_URL"
echo "DEBUG: TMP_DIR=$TMP_DIR"
echo "DEBUG: TARBALL_PATH=$TARBALL_PATH"

rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"

curl -fL "$DOWNLOAD_URL" -o "$TARBALL_PATH"
tar -xzf "$TARBALL_PATH" -C "$TMP_DIR"

GLAB_BIN="$(find "$TMP_DIR" -type f -name glab | head -n1)"
if [[ -z "$GLAB_BIN" ]]; then
  echo "glab binary not found in extracted archive" >&2
  exit 1
fi

sudo install -m 0755 "$GLAB_BIN" /usr/local/bin/glab
glab --version

解説

いろいろやっていますが https://gitlab.com/gitlab-org/cli/-/releases ここから tar をダウンロードし PATH 上に配置しているだけです

最後に

あとは glab auth でログインしましょう

export GITLAB_TOKEN='glpat-c-xxx'
glab auth login --hostname gitlab.devops.nifcloud.net --token <<< "$GITLAB_TOKEN"
glab auth status --hostname gitlab.devops.nifcloud.net

2025年11月1日土曜日

Gitlab CI で nikto を動かし DAST 的なことをする

Gitlab CI で nikto を動かし DAST 的なことをする

概要

前回 Gitlab CI のサービスを使って Web アプリを起動しそのアプリにテストする方法を紹介しました
今回は nikto を実行してみます

環境

  • Gitlab 18.2.6
  • Gitlab Runner 18.2.2
  • Python 3.12.11

.gitlab-ci.yml

stages:
  - build   # ビルドステージ
  - test    # テストステージ
  - pentest # ペネトレーションテストステージ

build:
  stage: build
  image:
    name: moby/buildkit:rootless  # BuildKit を使用するための Docker イメージ
    entrypoint: [""]  # デフォルトのエントリーポイントを無効化
  variables:
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox  # BuildKit の設定
  before_script:
    # Docker 認証情報を設定
    - mkdir -p ~/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
  script:
    # BuildKit を使用して Docker イメージをビルドし、GitLab Container Registry にプッシュ
    - |
      buildctl-daemonless.sh build \
        --frontend dockerfile.v0 \
        --local context=. \
        --local dockerfile=. \
        --output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true

app:
  stage: test
  services:
    # ビルドした Docker イメージをサービスとして起動
    - name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      alias: testapp  # サービスに "testapp" というホスト名を割り当て
  script:
    # サービスが起動するまで待機
    - echo "Waiting for the service to be ready..."
    - >
      for i in {1..30}; do
        curl -s http://testapp:5000 && break || sleep 1;  # サービスが応答するまで最大 30 秒間リトライ
      done
    - echo "Service is ready."  # サービスが起動したことを確認

validate:
  stage: test
  image: curlimages/curl:latest  # curl を使用するための軽量イメージ
  services:
    # ビルドした Docker イメージを再度サービスとして起動
    - name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      alias: testapp  # サービスに "testapp" というホスト名を割り当て
  script:
    # サービスに対してレスポンスを検証
    - echo "Running validation tests..."
    - |
      RESPONSE=$(curl -s http://testapp:5000)  # サービスにリクエストを送信しレスポンスを取得
      if [ "$RESPONSE" = "Hello, World!" ]; then
        echo "Validation passed!"  # レスポンスが期待通りの場合
      else
        echo "Validation failed: Expected 'Hello, World!' but got '$RESPONSE'"  # レスポンスが期待と異なる場合
        exit 1  # ジョブを失敗させる
      fi

pentest:
  stage: pentest
  image:
    name: ghcr.io/sullo/nikto:latest
    entrypoint: [""]
  services:
    - name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      alias: testapp
  script:
    - echo "Running Nikto penetration test..."
    - mkdir -p reports  # レポートを保存するディレクトリを作成
    - nikto.pl -h http://testapp:5000 -F htm -o reports/report.html
    - echo "Nikto scan completed. Report saved to reports/report.html."
  artifacts:
    paths:
      - reports/report.html  # レポートをアーティファクトとして保存
    expire_in: 1 week  # レポートの保存期間を 1 週間に設定

最後に

Gitlab Ultimate に登録していない場合に DAST が使えないので自分で .gitlab-ci.yml にペネトレーションテスト的なことを記載する必要があります
またレポートも自分で保存する必要があるので artifact を使って保存するようにしましょう

2025年10月31日金曜日

Gitlab CI で service を使って Web アプリを起動し簡単なテストを行う

Gitlab CI で service を使って Web アプリを起動し簡単なテストを行う

概要

イメージをビルドしビルドしたイメージからアプリを起動しそのアプリに対してテストするみたいな流れを GItlab CI でやってみます

今回 Web アプリは Python を使っていますが好きな言語のアプリで OK です

環境

  • Gitlab 18.2.6
  • Gitlab Runner 18.2.2
  • Python 3.12.11

Pipfile

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"

[dev-packages]

[requires]
python_version = "3.12"

app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, World!"

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

Dockerfile

FROM python:3.12.11-slim-bookworm

# 作業ディレクトリを設定
WORKDIR /app

# 必要なファイルをコンテナにコピー
COPY Pipfile Pipfile
COPY Pipfile.lock Pipfile.lock
COPY app.py app.py

# 必要なPythonパッケージをインストール
RUN pip install pipenv
RUN pipenv install

# アプリケーションを起動
CMD ["pipenv", "run", "python", "app.py"]

.gitlab-ci.yml

stages:
  - build  # ビルドステージ
  - test   # テストステージ

build:
  stage: build
  image:
    name: moby/buildkit:rootless  # BuildKit を使用するための Docker イメージ
    entrypoint: [""]  # デフォルトのエントリーポイントを無効化
  variables:
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox  # BuildKit の設定
  before_script:
    # Docker 認証情報を設定
    - mkdir -p ~/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
  script:
    # BuildKit を使用して Docker イメージをビルドし、GitLab Container Registry にプッシュ
    - |
      buildctl-daemonless.sh build \
        --frontend dockerfile.v0 \
        --local context=. \
        --local dockerfile=. \
        --output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true

app:
  stage: test
  services:
    # ビルドした Docker イメージをサービスとして起動
    - name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      alias: testapp  # サービスに "testapp" というホスト名を割り当て
  script:
    # サービスが起動するまで待機
    - echo "Waiting for the service to be ready..."
    - >
      for i in {1..30}; do
        curl -s http://testapp:5000 && break || sleep 1;  # サービスが応答するまで最大 30 秒間リトライ
      done
    - echo "Service is ready."  # サービスが起動したことを確認

validate:
  stage: test
  image: curlimages/curl:latest  # curl を使用するための軽量イメージ
  services:
    # ビルドした Docker イメージを再度サービスとして起動
    - name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      alias: testapp  # サービスに "testapp" というホスト名を割り当て
  script:
    # サービスに対してレスポンスを検証
    - echo "Running validation tests..."
    - |
      RESPONSE=$(curl -s http://testapp:5000)  # サービスにリクエストを送信しレスポンスを取得
      if [ "$RESPONSE" = "Hello, World!" ]; then
        echo "Validation passed!"  # レスポンスが期待通りの場合
      else
        echo "Validation failed: Expected 'Hello, World!' but got '$RESPONSE'"  # レスポンスが期待と異なる場合
        exit 1  # ジョブを失敗させる
      fi

最後に

Gitlab には Ultimate ライセンスを使っていると DAST を使えるのですがそうじゃないライセンスだと使えません
そんな場合に自分で DAST 的なことをする必要があるので今回のような流れで実装できます

次回は nikto を組み合わせてセキュリティテストしてみます

2025年10月20日月曜日

GitlabCI で buildkit を使って docker イメージをビルドする

GitlabCI で buildkit を使って docker イメージをビルドする

概要

buildkit 単体で動かそうとするとデーモンが必要だったり runc が必要だったりするのですが GitlabCI で公式のイメージを使用すると簡単に使えたのでメモしておきます

環境

  • buildkit
  • Gitlab 18.2.6
  • Gitlab Runner 18.2.2

.gitlab-ci.yml

.gitlab-ci.yml と同じディレクトリに Dockerfile があれば以下でそのまま使えます
他に環境変数などの設定が必要な場合は variables などで設定してください

stages:
  - test

build:
  stage: test
  image:
    name: moby/buildkit:rootless
    entrypoint: [""]
  variables:
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
  before_script:
    - mkdir -p ~/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
  script:
    - |
      buildctl-daemonless.sh build \
        --frontend dockerfile.v0 \
        --local context=. \
        --local dockerfile=. \
        --output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true

最後に

kaniko からの代替としては一番近い感じはします
以下にもありますが公式にも kaniko からの移行ドキュメントがあります

参考サイト

2025年10月18日土曜日

GitlabCI と werf を組み合わせてイメージのビルドとプッシュをしてみる

GitlabCI と werf を組み合わせてイメージのビルドとプッシュをしてみる

概要

前回 werf に入門してみました
今回は GitlabCI と連携して werf を使ってみます
なお Gitlab Runner は docker executor なので werf の公式イメージを使ってビルドアンドプッシュを行います

環境

  • werf 2-stable
  • Gitlab 18.2.6
  • Gitlab Runner 18.2.2

Gitlab Runner 側設定

以下どちらかを有効にする必要があります

  • 特権モード有効にする
  • seccompとapparmorを無効にする

前者であれば以下のように設定します

[[runners]]
  name = "<name of the Runner you registered>"
  [runners.docker]
    privileged = true
    volumes = [
      "werf-cache:/home/build/.werf",
      "buildah-cache:/home/build/.local/share/containers"
    ]

後者であれば以下のように設定します

[[runners]]
  name = "<name of the Runner you registered>"
  [runners.docker]
    security_opt = ["seccomp:unconfined", "apparmor:unconfined"]
    volumes = [
      "werf-cache:/home/build/.werf",
      "buildah-cache:/home/build/.local/share/containers"
    ]

.gitlab-ci.yml

Gitlab のコンテナレジストリはオンにしておきましょう
以下は werf を使って build and push する最低限の設定になります

  • vim .gitlab-ci.yml
stages:
  - test

werf_build_and_push:
  stage: test
  image:
    name: "registry.werf.io/werf/werf:2-stable"
    pull_policy: always
  before_script:
    - cat $(werf ci-env gitlab --as-file)
    - source $(werf ci-env gitlab --as-file)
  script:
    - werf build --repo ${CI_REGISTRY_IMAGE} --add-custom-tag latest

実際にパイプラインを走らせるとコンテナレジストリにイメージがあることが確認できます
どうやら werf は指定のイメージだけではなくメタデータなどを管理するイメージもコンテナレジストリ上で管理するようです

ポイント

werf を Gitlab で使って便利な点は source $(werf ci-env gitlab --as-file) の部分です
レジストリの認証情報やリポジトリの基本設定を自動で読み込んでくれます
例えば CI_REGISTRY_IMAGE は werf 用の変数 WERF_REPO を使っても OK です

その他コマンド

  • werf converge
    • ビルドアンドプッシュと k8s 環境へのデプロイもしてくれます
  • werf cleanup --repo container-registry/username/reponame --without-kube
    • 使用されていないイメージを自動で削除してくれます
    • 基本は --without-kube なしで使用し k8s 環境で使用されていないイメージを自動で削除しコンテナレジストリのディスク容量を解放するのが目的です
  • werf purge --repo container-registry/username/reponame
    • cleanup に似ていますがこれはイメージが使用されていようがいまいが強制的にコンテナレジストリ上のイメージを削除します

その他各種コマンドは https://werf.io/docs/v2/reference/cli/overview.html を参照してください

最後に

GitlabCI と werf を組み合わせてイメージのビルドアンドプッシュをしてみました
kaniko 代替としてはこれで十分な気もします
そもそも werf は k8s 環境に特化したツールなのでデプロイまで含めてやりたい場合などは werf 一択かなと思います

参考サイト

2025年10月17日金曜日

werf 超入門

werf 超入門

概要

kaniko がメンテされなくなり代わりのイメージビルドツールに werf というツールがあったので試してみました

環境

  • Ubuntu 24.04
  • werf 2.45.1

インストール

  • curl -sSL https://werf.io/install.sh | bash -s -- --version 2 --channel stable

.bashrc などに設定が記載されるのでターミナルを開きなおせば werf コマンドが使えるようになります

$ werf version
v2.45.1

werf.yaml の作成

  • vim werf.yaml
project: lab
configVersion: 1
---
image: test
context: .
dockerfile: Dockerfile

Dockerfile はプロジェクトの直下にあるものとします

werf.yaml の追加

werf.yaml はコミットされていないと認識されないので先にコミットします
リモート側に push まではしなくて OK です

  • git add .
  • git commit -m “Add werf.yaml”

ビルド

  • werf build

以下のように実行されます

Version: v2.45.1
WARNING: unable to parse ssh key /home/devops/.ssh/id_dsa: error parsing private key /home/devops/.ssh/id_dsa: ssh: unhandled key type
Using werf config render file: /tmp/werf-config-render-2657037271

┌ ???   (1/1) image test
│ ┌ Building stage test/dockerfile
│ │ test/dockerfile  #0 building with "default" instance using docker driver
│ │ test/dockerfile
│ │ test/dockerfile  #1 [internal] load remote build context
│ │ test/dockerfile  #1 DONE 0.1s
│ │ test/dockerfile
│ │ test/dockerfile  #2 copy /context /
│ │ test/dockerfile  #2 DONE 0.0s
│ │ test/dockerfile
│ │ test/dockerfile  #3 [internal] load metadata for docker.io/library/python:3.12.11-slim-bookworm
│ │ test/dockerfile  #3 ...
│ │ test/dockerfile
│ │ test/dockerfile  #4 [auth] library/python:pull token for registry-1.docker.io
│ │ test/dockerfile  #4 DONE 0.0s
│ │ test/dockerfile
│ │ test/dockerfile  #3 [internal] load metadata for docker.io/library/python:3.12.11-slim-bookworm
│ │ test/dockerfile  #3 DONE 2.7s
│ │ test/dockerfile
│ │ test/dockerfile  #5 [1/2] FROM docker.io/library/python:3.12.11-slim-bookworm@sha256:519591d6871b7bc437060736b9f7456b8731f1499a57e22e6c285135ae657bf7
│ │ test/dockerfile  #5 resolve docker.io/library/python:3.12.11-slim-bookworm@sha256:519591d6871b7bc437060736b9f7456b8731f1499a57e22e6c285135ae657bf7 done
│ │ test/dockerfile  #5 sha256:519591d6871b7bc437060736b9f7456b8731f1499a57e22e6c285135ae657bf7 9.13kB / 9.13kB done
│ │ test/dockerfile  #5 sha256:c00fc7b44d844b6da22861ec24af43968a5200eac4ec607b4725d585165d6b49 1.75kB / 1.75kB done
│ │ test/dockerfile  #5 sha256:688a685f6a1fa9250d7c6cee916889cbca364e4b027520110e0fce80c64a13e0 5.60kB / 5.60kB done
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 0B / 28.23MB 0.1s
│ │ test/dockerfile  #5 sha256:229c2e83adbca32a7582f378ce5a103e5c327ffd945d3f451fe66d1886693f34 0B / 3.52MB 0.1s
│ │ test/dockerfile  #5 sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e 0B / 13.66MB 0.1s
│ │ test/dockerfile  #5 sha256:229c2e83adbca32a7582f378ce5a103e5c327ffd945d3f451fe66d1886693f34 3.52MB / 3.52MB 0.6s done
│ │ test/dockerfile  #5 sha256:5ac70eb707d38d47fc69ca91acd4de7256ef894f5f446a9c344a1f4ad7628114 0B / 250B 0.6s
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 2.10MB / 28.23MB 0.9s
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 11.53MB / 28.23MB 1.1s
│ │ test/dockerfile  #5 sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e 4.19MB / 13.66MB 1.1s
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 14.68MB / 28.23MB 1.2s
│ │ test/dockerfile  #5 sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e 7.50MB / 13.66MB 1.2s
│ │ test/dockerfile  #5 sha256:5ac70eb707d38d47fc69ca91acd4de7256ef894f5f446a9c344a1f4ad7628114 250B / 250B 1.1s done
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 16.78MB / 28.23MB 1.4s
│ │ test/dockerfile  #5 sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e 13.66MB / 13.66MB 1.3s done
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 23.07MB / 28.23MB 1.5s
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 28.23MB / 28.23MB 1.6s
│ │ test/dockerfile  #5 extracting sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375
│ │ test/dockerfile  #5 sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 28.23MB / 28.23MB 1.6s done
│ │ test/dockerfile  #5 extracting sha256:5c32499ab806884c5725c705c2bf528662d034ed99de13d3205309e0d9ef0375 1.6s done
│ │ test/dockerfile  #5 extracting sha256:229c2e83adbca32a7582f378ce5a103e5c327ffd945d3f451fe66d1886693f34
│ │ test/dockerfile  #5 extracting sha256:229c2e83adbca32a7582f378ce5a103e5c327ffd945d3f451fe66d1886693f34 0.2s done
│ │ test/dockerfile  #5 extracting sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e
│ │ test/dockerfile  #5 extracting sha256:d296ae3a1b166ec8b25480749804c463ffde8dd56bd4a0d938c764b93565254e 0.8s done
│ │ test/dockerfile  #5 extracting sha256:5ac70eb707d38d47fc69ca91acd4de7256ef894f5f446a9c344a1f4ad7628114 done
│ │ test/dockerfile  #5 DONE 4.6s
│ │ test/dockerfile
│ │ test/dockerfile  #6 [2/2] RUN python -V
│ │ test/dockerfile  #6 0.496 Python 3.12.11
│ │ test/dockerfile  #6 DONE 0.8s
│ │ test/dockerfile
│ │ test/dockerfile  #7 exporting to image
│ │ test/dockerfile  #7 exporting layers 0.0s done
│ │ test/dockerfile  #7 writing image sha256:9b378fddd07c7546217a3ec2dba912453034e050f7a642d2052aa472fe085408 done
│ │ test/dockerfile  #7 naming to docker.io/library/9107100b-cef7-4f0a-9a66-49d3dbfe2bed done
│ │ test/dockerfile  #7 DONE 0.1s
│ │ ┌ Store stage into :local
│ │ └ Store stage into :local (0.01 seconds)
│ ├ Info
│ │      name: lab:594be819ed90f0081179a4a268c6045413df7b83b21e1a225badccdd-1760658483401
│ │        id: 9b378fddd07c
│ │   created: 2025-10-17 08:48:03.293806991 +0900 JST
│ │      size: 118.5 MiB
│ └ Building stage test/dockerfile (8.66 seconds)
└ ???   (1/1) image test (9.05 seconds)

Running time 9.30 seconds

以下のようなイメージができれば OK です

docker images
REPOSITORY            TAG                                                                      IMAGE ID       CREATED              SIZE
lab                   594be819ed90f0081179a4a268c6045413df7b83b21e1a225badccdd-1760658483401   9b378fddd07c   About a minute ago   124MB

プッシュする

ビルドしたイメージをプッシュするには --repo オプションを使います
例えば gitlab であれば以下のようにします

  • werf build --repo container-registry.your-gitlab-address/username-or-groupname/repo-name

コンテナレジストリのアドレス/ユーザ名orグループ名/gitlabのリポジトリ名 で指定します
実行すると以下のように gitlab に push されていることが確認できます

Version: v2.45.1
WARNING: unable to parse ssh key /home/devops/.ssh/id_dsa: error parsing private key /home/devops/.ssh/id_dsa: ssh: unhandled key type
Using werf config render file: /tmp/werf-config-render-2317128975

┌ ???   (1/1) image test
│ ┌ Copy suitable stage from secondary :local
│ │ Use previously built image for test/dockerfile
│ │      name: container-registry.your-gitlab-address/username-or-groupname/repo-name:594be819ed90f0081179a4a268c6045413df7b83b21e1a225badccdd-1760658483401
│ │        id: 9b378fddd07c
│ │   created: 2025-10-17 08:48:03 +0900 JST
│ │      size: 44.2 MiB
│ └ Copy suitable stage from secondary :local (18.60 seconds)
└ ???   (1/1) image test (19.27 seconds)

Running time 28.24 seconds

docker images を見ると先ほどビルドしたイメージに gitlab にプッシュするためのタグが作成されてそれがプッシュされていることが確認できます

コンテナレジストリにログインしていない場合は

以下のようなエラーになります

Error: unable to init storage manager: error get synchronization: unable to init http synchronization: unable to get client id for the http synchronization server: unable to get repo container-registry.your-gitlab-address/username-or-groupname/repo-name tags: unable to fetch tags for repo "container-registry.your-gitlab-address/username-or-groupname/repo-name": reading tags for "container-registry.your-gitlab-address/username-or-groupname/repo-name": GET https://xxx/jwt/auth?scope=repository%3Ausername-or-group%2Frepo-name%3Apull&service=container_registry: DENIED: access forbidden

素直に docker login すれば OK です

  • docker login container-registry.your-gitlab-address

タグを設定するには

werf はデフォルトだと UUID のようなランダムな文字列をタグとして付与します
latest やバージョンなど独自のタグを付与して push したい場合には以下のようにします

  • werf build --repo container-registry.your-gitlab-address/username-or-groupname/repo-name --add-custom-tag latest --add-custom-tag hoge

--add-custom-tag を使います
--add-custom-tag は複数指定できます
以下のように複数のタグが push されていることが確認できます

Version: v2.45.1
WARNING: unable to parse ssh key /home/devops/.ssh/id_dsa: error parsing private key /home/devops/.ssh/id_dsa: ssh: unhandled key type
Using werf config render file: /tmp/werf-config-render-4112436980

┌ ???   (1/1) image test
│ ┌ Copy suitable stage from secondary :local
│ │ Use previously built image for test/dockerfile
│ │      name: container-registry.your-gitlab-address/username-or-groupname/repo-name:594be819ed90f0081179a4a268c6045413df7b83b21e1a225badccdd-1760658483401
│ │        id: 9b378fddd07c
│ │   created: 2025-10-17 08:48:03 +0900 JST
│ │      size: 44.2 MiB
│ └ Copy suitable stage from secondary :local (2.14 seconds)
└ ???   (1/1) image test (2.90 seconds)

┌ Adding custom tags
│ ┌ tag latest
│ │   name: container-registry.your-gitlab-address/username-or-groupname/repo-name:latest
│ └ tag latest (3.27 seconds)
│
│ ┌ tag hoge
│ │   name: container-registry.your-gitlab-address/username-or-groupname/repo-name:hoge
│ └ tag hoge (3.23 seconds)
└ Adding custom tags (6.51 seconds)

Running time 17.49 seconds

最後に

kaniko の代用として werf を使ってみました
kaniko のようにビルド -> プッシュを一回のコマンドでできるは良い点です
次回は GitlabCI で werf を使ってみます

参考サイト

2025年10月14日火曜日

Gitlab で renovate を使うときの基本設定

Gitlab で renovate を使うときの基本設定

概要

renovate-runner は使わずまずはローカルから実行する際の最低限の設定について紹介します

環境

  • Ubuntu 24.04.3
  • nodejs 22.14.0
  • renovate 41.144.1

renovate.json

このファイルは renovate を実行するターゲットのリポジトリ配下に配置します

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended"
  ],
  "automergeStrategy": "squash",
  "ignorePaths": [
    "**/archive/**"
  ]
}

renovate コマンド

GITHUB_COM_TOKEN=ghp_xxx LOG_LEVEL=info renovate --platform=gitlab --endpoint=https://your-gitlab-com-url/api/v4 --username=oauth2 --token=glpat-xxx your/repo

トラブルシューティング

curl 'https://index.docker.io/v2/library/pthon/tags/list?n=10000'
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"library/pthon","Action":"pull"}]}]}

リポジトリ名が間違っている場合に認証エラーになるようです

最後に

renovate を動かす場合には必ずターゲットのリポジトリに renovate.json を配置しましょう
配置しないでも動かすことはできますが Gitlab の場合などは MR などが作成されないので注意しましょう

2025年9月18日木曜日

Gitlab で LDAP のログインテストをスクリプトから行う

Gitlab で LDAP のログインテストをスクリプトから行う

概要

過去に CLI を使った方法を紹介しました
CLI の場合 Gitlab インスタンスに ssh が必要なのと接続チェックしか行えないので実際のログインまでのテストはできません

今回は実際にログインするテストを ssh なしで実装してみました
UI と同じリクエストを Python スクリプトから送信すれば OK です

環境

  • Gitlab 18.1.6
  • Python 3.12.11
    • requests 2.32.5
    • beautifulsoup4 4.13.5

サンプルコード

import requests
from bs4 import BeautifulSoup

# GitLab の URL
GITLAB_URL = "https://your-gitlab-fqdn"

# LDAP ユーザーの資格情報
USERNAME = "hawk"
PASSWORD = "xxxxxxxx"
LDAP_NAME = "ldapserver01"


def test_ldap_login():
    # セッションを作成
    session = requests.Session()

    # ログインページにアクセスして CSRF トークンを取得
    login_page = session.get(f"{GITLAB_URL}/users/sign_in")
    if login_page.status_code != 200:
        print("ログインページへのアクセスに失敗しました。")
        return

    # CSRF トークンを取得
    soup = BeautifulSoup(login_page.text, "html.parser")
    element = soup.find("input", {"name": "authenticity_token"})
    if element is None:
        print("authenticity_tokenが見つかりませんでした。")
        return
    csrf_token = element["value"]  # type: ignore

    # ログインデータを準備
    login_data = {
        "username": USERNAME,
        "password": PASSWORD,
        "authenticity_token": csrf_token,
    }

    # ログインリクエストを送信
    response = session.post(
        f"{GITLAB_URL}/users/auth/{LDAP_NAME}/callback",
        data=login_data,
    )

    # レスポンスを確認
    if response.status_code == 200 and "Invalid Login or password" not in response.text:
        if "Welcome to GitLab" in response.text:
            print("LDAP ログインテストが成功しました。")
        else:
            print("LDAP ログインテストに失敗しました。")
            print("レスポンスに 'Welcome to GitLab' が含まれていません。")
    else:
        print("LDAP ログインテストに失敗しました。")
        print("ステータスコード:", response.status_code)
        print("レスポンス:", response.text)


if __name__ == "__main__":
    test_ldap_login()

少し解説

LDAP_NAME の部分は gitlab.rb に設定した ldap_name を設定してください
クロスサイト対策として CSRF トークンが必要になるのでそれをページから取得しリクエストに含める必要があります

Gitlab の API はなく直接 UI ページにアクセスして UI のフォームと同じリクエストを送信している感じです

最後に

これで LDAP のログインテストも ssh せずにテストできます

2025年9月17日水曜日

nifcloud の Gitlab インスタンスにリモートアクセスVPNゲートウェイ経由でプライベートIPアドレスでアクセスする方法

nifcloud の Gitlab インスタンスにリモートアクセスVPNゲートウェイ経由でプライベートIPアドレスでアクセスする方法

概要

前回EasyRSAを使って nifcloud のリモートアクセスVPNゲートウェイを接続しました
今回は nifcloud 側に Gitlab インスタンスにプライベートIPを割り当て割り当てたプライベートIPを使ってリモートアクセスVPNゲートウェイ経由でアクセスしてみます

環境

  • macOS 15.6.1
    • OpenVPN Connect-3.7.1

Gitlab インスタンスにプライベートIPを割り振る

前回リモートアクセスVPNゲートウェイ用に作成したPVLANを使って Gitlab インスタンスにプライベートIPを割り振ります

Gitlab インスタンスのファイアウォールに macOS からのアクセスを許可する

macOS 側の IP 帯は 192.168.1.0/24 なのでこれを追加します
また VPN 経由の場合 192.168 から 172.16 に変換されてアクセスも来るので PVLAN の 172.16.0.0/16 も許可します

確認用で ICMP を追加していますがこれはなくても OK です

macOS 側の hosts ファイルを編集する

プライベートIPでアクセスできるようにします

  • sudo vim /private/etc/hosts
172.16.0.100    xxx.jp-east-1.gitlab.devops.nifcloud.com

OpenVPN Connect を使って VPN 接続する

前回登録したプロフィールを使って接続します

アクセスできるか確認する

hosts に登録した FQDN でアクセスできるか確認しましょう
問題なくアクセスできれば Gitlab ログインの画面が表示されます

あくせすできない場合は ping を打ってみたり Gitlab 側のファイアウォールの設定などを確認しましょう

FQDN でうまくアクセスできない場合は

macOS の場合 /private/etc/hosts に書いた情報を優先的に使ってくれるのですがキャッシュがあるとそれが更に優先されます

一度キャッシュを削除してから再度アクセスしてみてください

  • sudo dscacheutil -flushcache
  • sudo killall -HUP mDNSResponde

以下でプライベートIPになることを確認しましょう

  • dscacheutil -q host -a name xxx.jp-east-1.gitlab.devops.nifcloud.com
name: xxx.jp-east-1.gitlab.devops.nifcloud.com
ip_address: 172.16.0.100

最後に

nifcloud のリモートアクセスVPNゲートウェイを使って Gitlab インスタンスにプライベート IP でアクセスしてみました

hosts ファイルを編集する必要があるのが面倒ですそればっかりはどうしようもないかなと思います

2025年9月10日水曜日

Gitlab と ldap の接続テストを CLI で行う

Gitlab と ldap の接続テストを CLI で行う

概要

基本的には接続テストのみなので実際に LDAP 内のユーザでログインできるかどうかは UI から試すしかありません

環境

  • Gitlab-ee 18.0.6
  • openldap 2.6.10

CLI

今回は結果を確認するために標準出力と標準エラーを別のファイルにリダイレクトしています

  • docker compose exec gitlab gitlab-rake gitlab:ldap:check > stdout.log 2> stderr.log

  • cat stdout.log

Checking LDAP ...

LDAP: ... Server: ldapmain
LDAP authentication... Success
LDAP users with access to your GitLab server (only showing the first 100 results)
        DN: uid=hawk,dc=example,dc=org   uid: hawk
Server: ldapsecondary
Exception: getaddrinfo: Name or service not known

Checking LDAP ... Finished
  • cat stderr.log

基本的には結果はすべて標準出力に表示されます
gitlab.rb に記載されている LDAP サーバごとにチェックはしてくれますが結果はすべて標準出力になります

最後に

Gitlab に LDAP を設定したあとにうまくログインできない場合にトラシュとして使う感じになりそうです
特定のユーザでログインできるかのチェックも CLI でやりたいですがそれは厳しいようです

2025年9月3日水曜日

omnibus-gitlab でメール接続テストをする方法

omnibus-gitlab でメール接続テストをする方法

概要

CLI でメール送信する方法を紹介します

環境

  • Gitlab-ee 18.0.6
  • docker 28.3.3

コマンド

  • docker compose exec gitlab gitlab-rails console

Notify.test_email('宛先メールアドレス', 'テストメールの件名', 'テスト本文').deliver_now

ワンライナーで

gitlab-rails runner を使います

docker compose exec gitlab gitlab-rails runner "Notify.test_email('宛先メールアドレス', 'テストメールの件名', 'テスト本文').deliver_now"

最後に

メールの設定テストをしたいときに便利です

2025年7月11日金曜日

This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.

This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.

概要

Gitlab は古いデプロイメントは自動で無効化する機能があります
場合によっては切り戻しなどで古いデプロイメントを使いたい場合があるかなと思います
その対処方法を紹介します

環境

  • Gitlab 17.10.7

対処方法

  • Settings
  • CI/CD
  • General pilelines
  • Prevenet outdated deployment jobs

のチェックをオフにします
再度 Pipeline を見るとデプロイできるようになっています

最後に

基本はオンにしておいて緊急時にオフにするのがいいと思います

参考サイト

2025年6月5日木曜日

Gitlab で reCAPTCHA を使ってみる

Gitlab で reCAPTCHA を使ってみる

概要

Gitlab と reCAPTCHA v2 を連携しログイン時にロボット化どうかを判定するチェックを導入してみました
v3 にはまだ対応していないので v2 を使いましょう

環境

  • reCAPTCHA v2
  • Gitlab 17.9.3

reCAPTCHA の登録

Gitlab は reCAPTCHA v3 をまだサポートしていないんどえ v2 のキーを取得しましょう

ここから申し込みます
GCP のプロダクトと紐づける必要があります
ドメインには Gitlab の URL を指定しましょう

サイトキーとシークレットキーが発行されるのでメモしておきます
また GCP 側のプロジェクトにも紐づいているのでそちらでも reCAPTCHA の情報を確認できます

Gitlab 側の設定

  • Admin ユーザでログイン
  • 左下の Admin ボタンをクリック
  • 左メニュー Settings -> Reporting
  • Spam and Anti-bot Protection
    • Enable reCAPTCHA -> ON
    • Enable reCAPTCHA for login. -> ON
    • reCAPTCHA site key -> 先ほど取得したサイトキーを入力
    • reCAPTCHA private key -> 先ほど取得したシークレットキーを入力
  • Save Change

動作確認

Gitlab にアクセスしてログインページで reCAPTCHA が表示されることを確認します
表示されない場合は以下を試してください

  • ブラウザのシークレットモードでアクセスする
  • パスワードを何回か間違えて表示されることを確認
  • ブラウザのキャッシュをクリアする
  • 異なる IP の環境からアクセスする

一度信頼されている環境だと reCAPTCHA は表示されないので注意してください GCP 上の reCAPTCHA でも保護がカウントされていることが確認できます

gitlab.rb の編集

これはいらないかもです
一応入れておくと安心です
Omnibus Gitlab であれば docker-compose.yml などに記載しましょう

  • vim /etc/gitlab/gitlab.rb
nginx['proxy_set_headers'] = { 'X-GitLab-Show-Login-Captcha' => '1' }

ロックアウトされた場合は

DB に直接触れたり Admin 権限のあるアクトークンがあるのであれば API から reCAPTCHA を一時的に無効にすることも可能です

curl --request PUT --header \
"PRIVATE-TOKEN: <PersonalAccessToken>" \
"https://gitlab.example.com/api/v4/application/settings?recaptcha_private_key=<SecretKey>&recaptcha_site_key=<SiteKey>"

最後に

Gitlab と reCAPTCHA を連携してみました
テストする場合はロックアウトされる可能性もあるのでログイン状態を保持したブラウザを用意しておくことをおすすめします

参考サイト

2025年4月3日木曜日

Gitlab で renovate を試す

Gitlab で renovate を試す

概要

gitlab のリポジトリに対して renovate を実行してみました
CLI で直接実行する方法と CI を使う方法を紹介します

環境

  • Gitlab 17.8

CLI

  • LOG_LEVEL=debug renovate --platform=gitlab --endpoint=https://your-gitlab-endpoint/api/v4 --username=oauth2 --token=glpat-xxx user/repo

CI

renovate/renovate-runnerを自身の Gitlab にミラーして使います
fork なりミラーしたリポジトリ名を yaml に記載します
Gitlab.com であれば以下のままで OK です

スキャン対象のリポジトリを RENOVATE_EXTRA_FLAGS に追加することで管理するようです

stages:
  - test

include:
  - project: 'renovate/renovate-runner'
    file: '/templates/renovate.gitlab-ci.yml'

renovate:
  stage: test
  variables:
    RENOVATE_EXTRA_FLAGS: "--platform=gitlab --endpoint=https://your-gitlab-endpoint/api/v4 --username=oauth2 user/repo"
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
    - if: '$CI_PIPELINE_SOURCE == "push"'

CI 変数

RENOVATE_TOKEN は必須なので CI の変数に設定しましょう
設定する値は Gitlab の Personal Access Token で OK です

GITHUB_COM_TOKEN はあったほうがいいです
Github アカウントがある場合は Github の Personal Access Token を取得して設定しましょう

最後に

基本は CI を使って定期的に MR を作る感じになるかなと思います
ただ更新対象が自動で決まるのとデフォルトだと2MRしか作成してくれないのでそこは変数による調整が必要かもです

また当然ですがバージョンを固定しているケースは renovate でもバージョンを上げられないのでそこは手動によるバージョン管理になります

参考サイト

2024年12月12日木曜日

Gitlab CI でデプロイジョブが古くて実行できない場合の対処方法

Gitlab CI でデプロイジョブが古くて実行できない場合の対処方法

概要

再度 force push してあげます

環境

  • Gitlab 17.5.2

エラー詳細

This job requires a manual action

This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.

こんな感じで古いデプロイジョブは実行できなくなっています

対策その1

対象のブランチの HEAD から再度パイプラインを手動で実行してあげれば OK です
ただブランチのパイプラインなどの場合 workflow ルールで手動実行できないケースがあるのでその場合は以下の対策を試してください

対策その2

ブランチであれば一つコミットを打ち消して再度 push すれば OK です

  • git reset HEAD^
  • git add .
  • git commit -m "Re commit"
  • git push -u origin feature/branch_name

これで再度ブランチからパイプラインが作成されるのでそこからデプロイすれば OK です

最後に

古いデプロイジョブでも実行可能にするオプションがあるっぽいのでそれをオンにしても OK ですが間違って最新版以外をデプロイしまう可能性があるので注意しましょう

2024年12月11日水曜日

Gitlab CI でリトライする方法

Gitlab CI でリトライする方法

概要

retry を使います

環境

  • Gitlab 17.5.2

.gitlab-ci.yml

この場合は2回リトライするので3回目で失敗して終了します

stages:
  - test

failure_test:
  stage: test
  retry:
    max: 2
    when: script_failure
  image:
    name: python:3.12.8-alpine3.21
  script:
    - python error.py

最後に

タイミングにより失敗するジョブなどに使えます

参考サイト

2024年11月18日月曜日

trivy で TooManyRequests が出る場合はリポジトリの参照先を複数指定しよう

trivy で TooManyRequests が出る場合はリポジトリの参照先を複数指定しよう

概要

--db-repository オプションと --java-db-repository オプションを使います
環境変数でも指定可能です
今回は Gitlab CI で使う方法を紹介します

環境

  • Gitlab 17.3.3
  • trivy 0.57.0

.gitlab-ci.yml

stages:
  - test

trivy-scan:
  stage: test
  image:
    name: aquasec/trivy:latest
    entrypoint: ['']
  variables:
    TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db,aquasec/trivy-db,ghcr.io/aquasecurity/trivy-db
    TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db,aquasec/trivy-java-db,ghcr.io/aquasecurity/trivy-java-db
  script:
    - trivy --version
    - trivy clean --all
    - trivy image --download-db-only

最後に

リポジトリ先はカンマ区切りで指定できるので自分でミラーを作成して指定しても OK です

参考サイト

2024年9月14日土曜日

omnibus-gitlab で管理している Prometheus のバージョンを Python から取得する方法

omnibus-gitlab で管理している Prometheus のバージョンを Python から取得する方法

概要

前回はシェルスクリプト+ gitlab ci で取得しましたが今回は Python で取得します

GitPython というライブラリを使います

環境

  • macOS 14.6.1
  • Python 3.11.10
    • GitPython 3.1.43

サンプルコード

import re
from dataclasses import dataclass

import git


# Prometheus など各種バージョンを管理するデータクラス
@dataclass
class GitlabAlertVersion:
    prometheus_version: str = ""
    alertmanager_version: str = ""
    node_exporter_version: str = ""

    # バージョン情報をファイルに保存します
    def save_to_files(self):
        with open("prometheus_version.txt", "w") as f:
            f.write(self.prometheus_version)
        with open("alertmanager_version.txt", "w") as f:
            f.write(self.alertmanager_version)
        with open("node_exporter_version.txt", "w") as f:
            f.write(self.node_exporter_version)


# omnibus-gitlab のリポジトリをクローンしてバージョンを取得するクラス
class GitlabAlertVersionFetcher:
    def __init__(self, tag="17.1.6+ee.0"):
        self.tag = tag
        self.repo_name = "omnibus-gitlab"
        self.url = f"https://gitlab.com/gitlab-org/{self.repo_name}.git"
        self.file_names = ["prometheus", "alertmanager", "node-exporter"]

    # url に記載のリポジトリを取得
    # 今回は tag を指定しシャロークローンで取得
    def _clone(self) -> git.Repo:
        return git.Repo.clone_from(
            self.url,
            f"./{self.repo_name}",
            branch=self.tag,
            depth="1",
        )

    # 指定のファイルを git grep する
    def _grep(self, file, repo: git.Repo) -> str:
        lines = repo.git.grep(
            "Gitlab::Version.new", "--", f"config/software/{file}.rb"
        ).split("\n")
        pattern = r"\d+\.\d+\.\d+"
        for line in lines:
            match = re.search(pattern, line)
            if match:
                return match.group(0)
        else:
            raise ValueError()

    # 実行メイン関数
    # file_names に定義された各種コンポーネントのバージョンを取得
    def run(self) -> GitlabAlertVersion:
        gitlab_alert_version = GitlabAlertVersion()
        repo = self._clone()
        for file in self.file_names:
            setattr(
                gitlab_alert_version,
                f"{file.replace('-', '_')}_version",
                self._grep(file, repo),
            )
        return gitlab_alert_version


if __name__ == "__main__":
    fetcher = GitlabAlertVersionFetcher()
    version: GitlabAlertVersion = fetcher.run()
    print(version)
    version.save_to_files()

最後に

GitPython を使うと git コマンドを Python 内で使うことができます

参考サイト

2024年9月13日金曜日

Gitlab CI でセマンティクスバージョンを比較する

Gitlab CI でセマンティクスバージョンを比較する

概要

過去に前のバージョンを保存する方法を紹介しました
今回は取得したバージョン同士を比較するジョブを追加します

環境

  • Gitlab.com 17.4.0-pre
    * Runner (docker-mahcine executor ruby:3.1)

.gitlab-ci.yml

compare ジョブを追加しています
sort した結果現在のバージョンと違うバージョンが返ってきたらバージョンアップと判断しています

stages:
  - save_versions
  - fetch_versions
  - check_versions
  - compare_versions

save:
  stage: save_versions
  script:
    - |
      # バージョンファイルがすでにある場合は前回のバージョンファイルに移動する
      mkdir -p $CI_PROJECT_DIR/build/cache
      mkdir -p $CI_PROJECT_DIR/build/artifacts
      # ファイルが何もないと各種ディレクトリが破棄されるのでファイル作成
      touch $CI_PROJECT_DIR/build/cache/keep.txt
      touch $CI_PROJECT_DIR/build/artifacts/keep.txt
      if [ -f $CI_PROJECT_DIR/build/cache/prometheus.txt ]; then
        mv $CI_PROJECT_DIR/build/cache/prometheus.txt $CI_PROJECT_DIR/build/artifacts/pre_prometheus.txt
        echo "Prometheus pre version:"
        cat $CI_PROJECT_DIR/build/artifacts/pre_prometheus.txt
      fi
      if [ -f $CI_PROJECT_DIR/build/cache/alertmanager.txt ]; then
        mv $CI_PROJECT_DIR/build/cache/alertmanager.txt $CI_PROJECT_DIR/build/artifacts/pre_alertmanager.txt
        echo "Alertmanager pre version:"
        cat $CI_PROJECT_DIR/build/artifacts/pre_alertmanager.txt
      fi
      if [ -f $CI_PROJECT_DIR/build/cache/node_exporter.txt ]; then
        mv $CI_PROJECT_DIR/build/cache/node_exporter.txt $CI_PROJECT_DIR/build/artifacts/pre_node_exporter.txt
        echo "Node Exporter pre version:"
        cat $CI_PROJECT_DIR/build/artifacts/pre_node_exporter.txt
      fi
  # 前回のパイプラインを参照するために cache を使う
  cache:
    paths:
      - $CI_PROJECT_DIR/build/cache/*.txt
  # ジョブ間で結果を共有するために artifacts を使う
  artifacts:
    paths:
      - $CI_PROJECT_DIR/build/artifacts/*.txt


# 任意のタグに基づいてバージョン情報を取得するジョブ
fetch:
  stage: fetch_versions
  script:
    - echo "Checking versions for the specified tag -> $TARGET_TAG"
    # GitLabソースコードをクローン
    - git clone https://gitlab.com/gitlab-org/omnibus-gitlab.git
    - cd omnibus-gitlab
    # ユーザーが指定したタグにチェックアウト
    - git checkout $TARGET_TAG
    # prometheusのバージョンを取得
    - grep 'Gitlab::Version.new' config/software/prometheus.rb | sed -n "s/.*'\(.*\)'.*/\1/p" > $CI_PROJECT_DIR/build/artifacts/prometheus.txt
    # Alertmanagerのバージョンを取得
    - grep 'Gitlab::Version.new' config/software/alertmanager.rb | sed -n "s/.*'\(.*\)'.*/\1/p" > $CI_PROJECT_DIR/build/artifacts/alertmanager.txt
    # Node Exporterのバージョンを取得
    - grep 'Gitlab::Version.new' config/software/node-exporter.rb | sed -n "s/.*'\(.*\)'.*/\1/p" > $CI_PROJECT_DIR/build/artifacts/node_exporter.txt
  # 前回のジョブの結果を使用するために artifacts を使う
  artifacts:
    paths:
      - $CI_PROJECT_DIR/build/artifacts/*.txt
  # ジョブの実行にはTARGET_TAG変数が必須
  rules:
    - if: '$TARGET_TAG != null'

check:
  stage: check_versions
  script:
    - echo "Prometheus version:"
    - cat $CI_PROJECT_DIR/build/artifacts/prometheus.txt
    - echo "Alertmanager version:"
    - cat $CI_PROJECT_DIR/build/artifacts/alertmanager.txt
    - echo "Node Exporter version:"
    - cat $CI_PROJECT_DIR/build/artifacts/node_exporter.txt
    # 結果をキャッシュに保存する
    - cp $CI_PROJECT_DIR/build/artifacts/prometheus.txt $CI_PROJECT_DIR/build/cache/prometheus.txt
    - cp $CI_PROJECT_DIR/build/artifacts/alertmanager.txt $CI_PROJECT_DIR/build/cache/alertmanager.txt
    - cp $CI_PROJECT_DIR/build/artifacts/node_exporter.txt $CI_PROJECT_DIR/build/cache/node_exporter.txt
    - ls $CI_PROJECT_DIR/build/cache
    - ls $CI_PROJECT_DIR/build/artifacts
  # 次回のパイプラインに結果を残すために cache を使う
  cache:
    paths:
      - $CI_PROJECT_DIR/build/cache/*.txt
  # 前回のジョブの結果を使用するために artifacts を使う
  artifacts:
    paths:
      - $CI_PROJECT_DIR/build/artifacts/*.txt

compare:
  stage: compare_versions
  script:
    - |
      # 前の Prometheus のバージョン情報を取得
      if [ -f $CI_PROJECT_DIR/build/artifacts/pre_prometheus.txt ]; then
        PREV_VERSION=$(cat $CI_PROJECT_DIR/build/artifacts/pre_prometheus.txt)
        # PREV_VERSION="0.0.0" # for test
      else
        exit 1
      fi
      # 現在の Prometheus のバージョン情報を取得
      if [ -f $CI_PROJECT_DIR/build/artifacts/prometheus.txt ]; then
        CURRENT_VERSION=$(cat $CI_PROJECT_DIR/build/artifacts/prometheus.txt)
      else
        exit 1;
      fi
      # バージョン比較のための関数
      version_gt() {
        [ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" != "$1" ]
      }
      # バージョンを比較
      if version_gt "$CURRENT_VERSION" "$PREV_VERSION"; then
        echo "Version has increased from $PREV_VERSION to $CURRENT_VERSION"
      else
        echo "Version is unchanged."
        exit 0
      fi
  # 前回のジョブの結果を使用するために artifacts を使う
  artifacts:
    paths:
      - $CI_PROJECT_DIR/build/artifacts/*.txt

最後に

今回はシェルスクリプトで実現していますが正しく比較したいのであれば Python などを使う方法を検討してください