GitLab CI/CD
CI/CDツール
GitLab CI/CD
概要
GitLab CI/CDは、GitLabに統合されたCI/CDシステムです。強力なパイプライン機能、Auto DevOps、Kubernetes統合、セキュリティスキャンが特徴で、包括的なDevOpsプラットフォームを提供します。
詳細
GitLab CI/CD(ギットラブ シーアイ・シーディー)は、GitLab社が提供する統合型CI/CD(継続的インテグレーション・継続的デリバリー)プラットフォームです。2011年のGitLab発足以来進化を続け、現在では単なるコード管理を超えた包括的なDevOpsソリューションを提供しています。リポジトリ内の.gitlab-ci.ymlファイルでパイプラインを定義し、ビルド、テスト、デプロイを自動化します。GitLab Runnerによる多様な実行環境サポート(Docker、Kubernetes、VM)、マトリックスビルド、並列実行により高速で柔軟なCI/CDを実現します。2024年にはCI/CDカタログが正式リリースされ、再利用可能なコンポーネントを通じて効率的なパイプライン構築が可能になりました。Auto DevOps機能により設定なしでCI/CDパイプラインを自動生成し、SAST、DAST、dependency scanningなどの包括的なセキュリティスキャンを統合しています。GitLab独自のカンバンボード、Issue管理、Merge Request、Container Registry、Package Registryとの緊密な統合により、開発からデプロイまでのワンストップソリューションを提供します。
メリット・デメリット
メリット
- オールインワンプラットフォーム: Git、CI/CD、セキュリティ、監視を統合
- Auto DevOps: ゼロ設定でCI/CDパイプラインを自動生成
- 強力なセキュリティ機能: SAST、DAST、dependency scanning内蔵
- 柔軟な実行環境: Docker、Kubernetes、VM、セルフホストランナー対応
- CI/CDカタログ: 再利用可能なコンポーネントでパイプライン効率化
- 包括的な統合: Issue、MR、Container Registryとの緊密連携
- GitOps対応: Kubernetes環境でのGitOpsワークフローサポート
- 無料利用枠: GitLab.comで毎月400分の無料CI/CD実行時間
デメリット
- 学習コスト: YAML記法と複雑な機能セットの理解が必要
- 実行時間制限: GitLab.comではジョブあたり最大8時間の制限
- 料金: セルフホストでも大規模利用時は有料機能が必要
- リソース消費: 機能豊富な分、システムリソースを多く消費
- デバッグの複雑さ: パイプライン失敗時の原因特定が困難
- ベンダーロックイン: GitLab固有機能への依存リスク
- パフォーマンス: 大規模プロジェクトでのUIレスポンス低下
主要リンク
- GitLab CI/CD公式サイト
- GitLab CI/CD公式ドキュメント
- GitLab Runners
- GitLab CI/CDカタログ
- GitLab Auto DevOps
- GitLab Examples
書き方の例
基本的なパイプライン設定
# .gitlab-ci.yml
stages:
- build
- test
- deploy
default:
image: ubuntu:latest
variables:
DOCKER_DRIVER: overlay2
build_job:
stage: build
script:
- echo "Building the application..."
- npm install
- npm run build
artifacts:
paths:
- build/
expire_in: 1 hour
test_job:
stage: test
script:
- echo "Running tests..."
- npm run test
dependencies:
- build_job
deploy_job:
stage: deploy
script:
- echo "Deploying to production..."
- ./deploy.sh
environment:
name: production
url: https://example.com
only:
- main
Node.jsプロジェクトのCI/CD
# .gitlab-ci.yml
image: node:18
stages:
- install
- test
- build
- deploy
cache:
paths:
- node_modules/
- .npm/
variables:
npm_config_cache: "$CI_PROJECT_DIR/.npm"
install_dependencies:
stage: install
script:
- npm ci --cache .npm --prefer-offline
artifacts:
paths:
- node_modules/
expire_in: 30 minutes
lint:
stage: test
script:
- npm run lint
dependencies:
- install_dependencies
unit_tests:
stage: test
script:
- npm run test:unit
coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
paths:
- coverage/
dependencies:
- install_dependencies
build_app:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week
dependencies:
- install_dependencies
only:
- main
- develop
deploy_staging:
stage: deploy
script:
- echo "Deploying to staging..."
- npm run deploy:staging
environment:
name: staging
url: https://staging.example.com
dependencies:
- build_app
only:
- develop
deploy_production:
stage: deploy
script:
- echo "Deploying to production..."
- npm run deploy:production
environment:
name: production
url: https://example.com
dependencies:
- build_app
only:
- main
when: manual
Docker イメージビルドとレジストリプッシュ
# .gitlab-ci.yml
stages:
- build
- test
- push
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_TLS_VERIFY: 1
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
services:
- docker:dind
before_script:
- docker info
build_image:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker save $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA > image.tar
artifacts:
paths:
- image.tar
expire_in: 1 hour
test_image:
stage: test
script:
- docker load < image.tar
- docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA npm test
dependencies:
- build_image
push_image:
stage: push
script:
- docker load < image.tar
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
dependencies:
- build_image
only:
- main
マトリックスビルドとマルチプラットフォーム対応
# .gitlab-ci.yml
stages:
- test
- build
test_matrix:
stage: test
image: node:${NODE_VERSION}
script:
- npm install
- npm test
parallel:
matrix:
- NODE_VERSION: ["16", "18", "20", "22"]
PLATFORM: ["linux", "darwin"]
except:
variables:
- $NODE_VERSION == "16" && $PLATFORM == "darwin"
build_multiarch:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- docker buildx create --use --name multiarch-builder
script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker buildx build
--platform linux/amd64,linux/arm64,linux/arm/v7
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
--tag $CI_REGISTRY_IMAGE:latest
--push .
only:
- tags
条件付きパイプラインとマニュアルデプロイ
# .gitlab-ci.yml
workflow:
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == "schedule"
stages:
- test
- security
- deploy
variables:
ENVIRONMENT: "development"
.base_job: &base_job
before_script:
- echo "Starting job..."
after_script:
- echo "Job completed."
unit_tests:
<<: *base_job
stage: test
script:
- npm run test
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
security_scan:
stage: security
script:
- echo "Running security scans..."
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_PIPELINE_SOURCE == "schedule"
deploy_staging:
<<: *base_job
stage: deploy
script:
- echo "Deploying to staging environment..."
- ./deploy.sh staging
environment:
name: staging/$CI_COMMIT_REF_SLUG
url: https://staging-$CI_COMMIT_REF_SLUG.example.com
on_stop: stop_staging
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: manual
stop_staging:
<<: *base_job
stage: deploy
script:
- echo "Stopping staging environment..."
- ./cleanup.sh staging
environment:
name: staging/$CI_COMMIT_REF_SLUG
action: stop
when: manual
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: manual
deploy_production:
<<: *base_job
stage: deploy
script:
- echo "Deploying to production..."
- ./deploy.sh production
environment:
name: production
url: https://example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
- if: $CI_COMMIT_TAG
when: manual
セキュリティスキャンとコンプライアンス
# .gitlab-ci.yml
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/DAST.gitlab-ci.yml
stages:
- build
- test
- security
- deploy
variables:
SAST_EXCLUDED_PATHS: "tests/, spec/, vendor/"
SECURE_LOG_LEVEL: "debug"
build_app:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
container_scanning:
variables:
CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
dependencies:
- build_app
dast_scan:
stage: security
variables:
DAST_WEBSITE: https://staging.example.com
DAST_AUTH_URL: https://staging.example.com/login
script:
- echo "Running DAST scan..."
artifacts:
reports:
dast: gl-dast-report.json
only:
- schedules
security_report:
stage: security
script:
- echo "Generating security compliance report..."
- ./generate-security-report.sh
artifacts:
reports:
junit: security-report.xml
paths:
- security-report.html
dependencies:
- sast
- dependency_scanning
- container_scanning
Kubernetes デプロイメント
# .gitlab-ci.yml
stages:
- build
- deploy
variables:
KUBE_NAMESPACE: $CI_PROJECT_NAME-$CI_ENVIRONMENT_SLUG
ROLLOUT_RESOURCE_TYPE: deployment
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
.deploy_template: &deploy_template
image: bitnami/kubectl:latest
before_script:
- kubectl config use-context $KUBE_CONTEXT
- kubectl create namespace $KUBE_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
- envsubst < k8s/deployment.yaml | kubectl apply -f -
- envsubst < k8s/service.yaml | kubectl apply -f -
script:
- kubectl rollout status $ROLLOUT_RESOURCE_TYPE/$CI_PROJECT_NAME -n $KUBE_NAMESPACE
- kubectl get all -n $KUBE_NAMESPACE
deploy_staging:
<<: *deploy_template
stage: deploy
variables:
KUBE_CONTEXT: staging-cluster
REPLICAS: "2"
environment:
name: staging
url: https://staging.example.com
kubernetes:
namespace: $KUBE_NAMESPACE
only:
- develop
deploy_production:
<<: *deploy_template
stage: deploy
variables:
KUBE_CONTEXT: production-cluster
REPLICAS: "5"
environment:
name: production
url: https://example.com
kubernetes:
namespace: $KUBE_NAMESPACE
only:
- main
when: manual