# CI/CD 集成

在 CI/CD 中使用 SparkCR 的目标是减少公共镜像仓库拉取失败和限流，同时避免把个人密码写入流水线。

## 推荐做法

- 为每个项目或 runner 单独创建 [Access Token](/tokens)。
- 公共镜像拉取只授予 `pull:public`。
- 需要私有上游镜像时再授予 `pull:private`。
- 需要推送到私有上游时再授予 `push`。
- 把账号邮箱、令牌和镜像仓库入口放入 CI Secret。
- 令牌泄漏或人员变更后，撤销旧令牌并创建新令牌。

## 通用登录步骤

在流水线开始阶段登录：

```bash
echo "$SPARKCR_TOKEN" | docker login "$SPARKCR_REGISTRY" \
  --username "$SPARKCR_USERNAME" \
  --password-stdin
```

建议使用这些 Secret：

- `SPARKCR_REGISTRY`
- `SPARKCR_USERNAME`
- `SPARKCR_TOKEN`

## GitHub Actions

```yaml
name: build

on:
  push:
    branches: [main]
  pull_request:

jobs:
  image:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to SparkCR
        run: |
          echo "${{ secrets.SPARKCR_TOKEN }}" | docker login "${{ secrets.SPARKCR_REGISTRY }}" \
            --username "${{ secrets.SPARKCR_USERNAME }}" \
            --password-stdin

      - name: Pull base image through SparkCR
        run: docker pull "${{ secrets.SPARKCR_REGISTRY }}/docker.io/library/node:22-alpine"

      - name: Build image
        run: docker build --pull -t app:${{ github.sha }} .
```

## GitLab CI

```yaml
stages:
  - build

build-image:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  before_script:
    - echo "$SPARKCR_TOKEN" | docker login "$SPARKCR_REGISTRY" --username "$SPARKCR_USERNAME" --password-stdin
  script:
    - docker pull "$SPARKCR_REGISTRY/docker.io/library/node:22-alpine"
    - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
```

## BuildKit 与 buildx

BuildKit 会复用 Docker credential store。只要同一个 job 内先执行 `docker login`，后续 `docker buildx build` 就能通过 SparkCR 拉取基础镜像。

```bash
echo "$SPARKCR_TOKEN" | docker login "$SPARKCR_REGISTRY" \
  --username "$SPARKCR_USERNAME" \
  --password-stdin

docker buildx create --use
docker buildx build --pull --tag app:ci .
```

## 私有镜像仓库拉取和推送

私有上游需要先在控制台的 [`Private Registries`](/settings/private-registries) 页面创建。CI Token 至少需要：

- 拉取私有镜像：`pull:private`
- 推送私有镜像：`push`

示例：

```bash
echo "$SPARKCR_TOKEN" | docker login "$SPARKCR_REGISTRY" \
  --username "$SPARKCR_USERNAME" \
  --password-stdin

docker pull "$SPARKCR_REGISTRY/acme-harbor/myapp:base"
docker build -t "$SPARKCR_REGISTRY/acme-harbor/myapp:$CI_COMMIT_SHA" .
docker push "$SPARKCR_REGISTRY/acme-harbor/myapp:$CI_COMMIT_SHA"
```

其中 `acme-harbor` 使用私有镜像仓库页面生成的 endpoint 为准。

## Kubernetes Runner

Kubernetes runner 建议同时配置：

- 节点 runtime mirror，让集群内镜像拉取走 SparkCR。
- `imagePullSecret`，让 runner Pod 能认证到 SparkCR。

创建 Secret：

```bash
kubectl create secret docker-registry sparkcr-registry \
  --docker-server="$SPARKCR_REGISTRY" \
  --docker-username="$SPARKCR_USERNAME" \
  --docker-password="$SPARKCR_TOKEN"
```

在 runner 或 job Pod 模板中引用：

```yaml
imagePullSecrets:
  - name: sparkcr-registry
```
