GitLab - Rustで使う用の.gitlab-ci.yml (Runnerを専有可能な環境向け)
RustなプロジェクトのCIを回す際、ビルドやカバレッジ取得のたびに依存関係がリコンパイルされたり、キャッシュが大きくなったりと色々つらかったので何とかしようと試行錯誤したメモ。
やった事は主に以下二点で、今のところは満足。
一部GitLab Runnerの専有が必要という環境制約あり。
- CIジョブ実行時の
git clean
の対象から./target
を除外する - CIジョブで使用するtarpaulin入りのDockerイメージをあらかじめ作っておく
目次
環境
- GitLab: 14.8.2-ee *1
制約
GitLab Runnerを専有する必要がある
今回のやり方では、Docker executorのvolume上に./target
を保持したままにすることで、volumeそのものをキャッシュ代わりにする。
そのため、共有RunnerのようにCIジョブ実行都度volumeが片付けられてしまう環境では効果がない。
定義ファイル類
配置
イメージをつかむのに必要そうなものだけ書いた。
. |-- .gitlab-ci.yml |-- Cargo.toml |-- Docker | |-- CI | | `-- Dockerfile.rust.ci … CIジョブで使用するimageのビルド用 | `-- Dockerfile.rust … 開発環境用 |-- docker-compose.yml |-- src | `-- main.rs `-- target
.gitlab-ci.yml
パイプラインイメージ
- 各ジョブとも任意のタイミングでGitLabのWebUIから個別に実行できる
- 個別に実行する場合、ビルドとカバレッジ計測は実行時のVariablesとして
CLEAN
を付与することでクリーンビルドできる
.gitlab-ci.yml
variables: CARGO_INCREMENTAL: 0 FF_USE_FASTZIP: "true" # ARTIFACT_COMPRESSION_LEVEL: fast # https://zenn.dev/masakura/articles/1ba1d9ec95cfad # GitLab CI ジョブの高速化 (キャッシュを使わない) GIT_CLEAN_FLAGS: -ffdx -e target/ # CI時に使用するrustのイメージ名 CI_RUST_IMAGE: "$CI_REGISTRY_IMAGE/ci-rust" stages: - build - coverage - rebuild_ci_image image: rust:slim # 通常のフローでは`./target`を掃除できなくなっているので、 # フォールバック手段を用意しておく。 # GitLabのPipeline実行画面で変数`CLEAN`(値は任意)を指定して実行すると、 # ビルド実行前に`./target`を削除できる。 # あと、本体へのマージ時にも一応。 .clean: &clean > [ "${CLEAN:-}" != "" ] || [ "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-}" = $CI_DEFAULT_BRANCH ] && echo ----- CLEAN ------------------------------ && rm -rf ./target && ls -la build: stage: build rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: never - if: $REBUILD_RUST_IMAGE when: never - when: always image: $CI_RUST_IMAGE script: # 始めはビルドやテストなどを個別のジョブに細分化していたが、ジョブごとに # キャッシュの圧縮/展開を繰り返してストレージに優しくない感じだったので # 1ジョブにまとめた。 - ls -la - cargo --version - *clean - > : ----- FORMAT ---------------------------- - cargo fmt --version - time cargo fmt -- --check - > : ----- BUILD ----------------------------- - rustc --version - time cargo build - > : ----- LINT ------------------------------ - cargo clippy --version - time cargo clippy - > : ----- BUILD - TEST ---------------------- - time cargo test --no-run - > : ----- TEST ------------------------------ - time cargo test - ls -la coverage: stage: coverage tags: # coverage用のrunnerに振り分ける。 # buildと一緒のrunnerで処理すると毎回リコンパイルされてしまうので。 - coverage rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" image: $CI_RUST_IMAGE script: - > : ----- TEMP MERGE ---------------------------- # たまに`*** Please tell me who you are.`されるのでダミーを入れておく。 - git config --local user.name "gitlab-runner" - git config --local user.email "gitlab-runner@example.com" - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME # https://ngyuki.hatenablog.com/entry/2020/02/15/205425 # Gitlab CI でマージリクエストのマージ結果でパイプラインを実行する - git checkout "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" - git merge --squash -v - - git diff --stat --staged - ls -la - *clean - > : ----- COVERAGE ------------------------------ - cargo tarpaulin --version - cargo tarpaulin --skip-clean --out Html Xml --output-dir ./coverage - ls -la coverage: '/^\d+.\d+% coverage/' artifacts: paths: # カバレッジレポートをGitLab Pagesで参照できるようにする。 - coverage/tarpaulin-report.html reports: cobertura: # Merge RequestのChangesタブで変更箇所のカバレッジ状況を参照できるようにする。 - coverage/cobertura.xml expose_as: 'coverage report' rebuild_ci_image: stage: rebuild_ci_image rules: - if: $REBUILD_RUST_IMAGE tags: - rebuild_image script: - ls -la - docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY - docker build --pull -t $CI_RUST_IMAGE -f Docker/CI/Dockerfile.rust.ci Docker/CI/ - docker push $CI_RUST_IMAGE
Dockerfile.rust.ci
ビルドやカバレッジ取得で使用するDockerイメージのビルドファイル。
カバレッジ取得はtarpaulinの公式イメージを使うという手もあるのだが、パイプライン内でgit操作したかったり、プロジェクトで使用しているクレートが外部のパッケージに依存していたりするため、個別にDockerイメージを作ることにした。
FROM rust:slim # pkg-config, libssl-dev: # - cargo-tarpaulinのコンパイルに必要 # - プロジェクトで利用しているrequestクレートのコンパイルに必要 # git: # - Merge Requestのパイプライン内で一時的にマージ状態を作るためにgit操作が必要 RUN apt-get update -qq && \ apt-get install -qqy pkg-config libssl-dev git && \ rustup component add rustfmt clippy && \ cargo install cargo-tarpaulin
/etc/gitlab-runner/config.toml
GitLab Runnerをインストールした際に自動生成される定義ファイル。
Docker executorがgit clone
する際にホスト名を名前解決できるように追記しておく。
また、tarpaulinを使用するexecutorには特権が必要になる。
[[runners]] name = "Docker executor for build" executor = "docker" : [runners.docker] volumes = ["/cache"] : + extra_hosts = ["MY_HOST_NAME:192.0.2.1"] + privileged = true # tarpaulinを使用するexecutorのみ
参考リンク
GitLab CI ジョブの高速化 (キャッシュを使わない)
Docker executorのvolumeをキャッシュ代わりにするアイデアの紹介記事。executorが一生懸命
./target
を圧縮・展開してるのを見てう~ん…と思ったり、かと言って./target
配下のキャッシュ対象を選り分けるのも難しそうだし…、などと逡巡していた時にとても助かった。
*1:EEでもライセンスなしの場合はCEと同じ状態になる。
Community EditionとEnterprise Editionの違い | GitLab.JP