stages: - test - security - build - deploy variables: IMAGE_NAME: rust-user-api REGISTRY: ${CI_REGISTRY:-docker.io} # 缓存配置 .cargo_cache: &cargo_cache cache: key: ${CI_COMMIT_REF_SLUG} paths: - ~/.cargo/registry/ - ~/.cargo/git/ - target/ test: stage: test image: ubuntu:latest <<: *cargo_cache before_script: - apt-get update -qq && apt-get install -y -qq curl build-essential - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - source ~/.cargo/env - rustup component add rustfmt clippy script: - source ~/.cargo/env - cargo fmt -- --check - cargo clippy -- -D warnings - cargo test --verbose rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == "main" - if: $CI_COMMIT_BRANCH == "master" - if: $CI_COMMIT_TAG security-scan: stage: security image: ubuntu:latest needs: [test] before_script: - apt-get update -qq && apt-get install -y -qq curl build-essential - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - source ~/.cargo/env script: - source ~/.cargo/env - cargo install cargo-audit - cargo audit rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_COMMIT_BRANCH == "master" - if: $CI_COMMIT_TAG build: stage: build image: docker:latest services: - docker:dind needs: [test, security-scan] variables: DOCKER_TLS_CERTDIR: "/certs" before_script: - docker login -u $REGISTRY_USER -p $REGISTRY_PASS $REGISTRY script: - | if [ "$CI_COMMIT_TAG" ]; then TAGS="$REGISTRY/$IMAGE_NAME:latest $REGISTRY/$IMAGE_NAME:$CI_COMMIT_TAG" else TAGS="$REGISTRY/$IMAGE_NAME:latest $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA" fi - docker build -t $REGISTRY/$IMAGE_NAME:latest . - | for tag in $TAGS; do docker tag $REGISTRY/$IMAGE_NAME:latest $tag docker push $tag done - echo "IMAGE_TAG=$REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA" > build.env artifacts: reports: dotenv: build.env rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_COMMIT_BRANCH == "master" - if: $CI_COMMIT_TAG deploy-staging: stage: deploy image: alpine:latest needs: [build] environment: name: staging before_script: - apk add --no-cache curl script: - echo "部署到测试环境..." - echo "镜像: $IMAGE_TAG" # 这里添加实际的部署逻辑 rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_COMMIT_BRANCH == "master" deploy-production: stage: deploy image: alpine:latest needs: [build, deploy-staging] environment: name: production before_script: - apk add --no-cache openssh-client curl - mkdir -p ~/.ssh - echo "$DEPLOY_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts script: - | ssh $DEPLOY_USER@$DEPLOY_HOST << 'EOF' cd /opt/rust-api # 备份当前数据库 if [ -f docker-compose.prod.yml ]; then docker-compose -f docker-compose.prod.yml exec -T rust-user-api \ sqlite3 /app/data/production.db ".backup /app/data/backup-$(date +%Y%m%d-%H%M%S).db" || true fi # 拉取最新镜像 docker pull $IMAGE_TAG # 更新docker-compose文件中的镜像标签 if [ -f docker-compose.prod.yml ]; then sed -i "s|image: .*rust-user-api.*|image: $IMAGE_TAG|" docker-compose.prod.yml docker-compose -f docker-compose.prod.yml up -d else docker-compose down || true docker-compose up -d fi # 等待服务启动 sleep 30 # 健康检查 if curl -f http://localhost:8080/health || curl -f http://localhost/health; then echo "✅ 部署成功!" else echo "❌ 部署失败,开始回滚..." docker-compose down exit 1 fi EOF - echo "🎉 生产环境部署成功!" - echo "版本: $CI_COMMIT_TAG" - echo "镜像: $IMAGE_TAG" rules: - if: $CI_COMMIT_TAG =~ /^v.*/ when: manual