kubenetes流水线实施清单

发布于:2024-12-06 ⋅ 阅读:(80) ⋅ 点赞:(0)

整体实施方案概述

  1. 创建命名空间(Namespace):创建一个专用于 CI/CD 的命名空间 cicd
  2. 配置 Secrets
    • Git SSH 密钥(分别为 Maven 和 npm 项目)
    • Docker Registry 凭证(Kaniko)
    • SMTP 凭证(邮件通知)
  3. 创建 PersistentVolumeClaim(PVC):用于存储工作空间数据。
  4. 创建 ServiceAccount 和权限绑定:确保 Tekton Pipelines 有足够的权限。
  5. 创建 Tekton Tasks
    • 初始化环境任务(分别为 Maven 和 npm)
    • 拉取代码任务(分别为 Maven 和 npm)
    • 运行 dockerContext.sh 脚本任务
    • 构建并推送镜像任务(使用 Kaniko)
    • 部署到 Kubernetes 任务
    • 发送邮件通知任务
  6. 创建 Tekton Pipelines
    • Maven 流水线
    • npm 流水线
  7. 创建 dockerContext.sh 脚本
  8. 应用所有 Tekton 资源
  9. 测试与运行
  10. 常见问题排查

详细实施步骤

步骤 1:创建命名空间

如果尚未创建,创建一个专用于 CI/CD 的命名空间 cicd

kubectl create namespace cicd

验证命名空间创建成功:

kubectl get namespaces

步骤 2:配置 Git SSH 密钥

2.1 生成 SSH 密钥
  1. 为 Maven 项目生成 SSH 密钥(如果尚未有):

    ssh-keygen -t rsa -b 4096 -C "maven_email@example.com" -f ~/maven_id_rsa
    
  2. 为 npm 项目生成 SSH 密钥(如果尚未有):

    ssh-keygen -t rsa -b 4096 -C "npm_email@example.com" -f ~/npm_id_rsa
    
  3. 将公钥添加到各自 Git 仓库的部署密钥中,以便允许 CI/CD 系统访问私有仓库。

2.2 创建 Kubernetes Secrets 存储 Git SSH 私钥

保存 Maven Git SSH Secret 为 git-ssh-secret-maven.yaml

apiVersion: v1
kind: Secret
metadata:
  name: git-ssh-key-maven
  namespace: cicd
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: <BASE64_ENCODED_MAVEN_ID_RSA>

保存 npm Git SSH Secret 为 git-ssh-secret-npm.yaml

apiVersion: v1
kind: Secret
metadata:
  name: git-ssh-key-npm
  namespace: cicd
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: <BASE64_ENCODED_NPM_ID_RSA>

生成 Base64 编码的私钥:

# 对 Maven 私钥进行编码
cat ~/maven_id_rsa | base64 -w0

# 对 npm 私钥进行编码
cat ~/npm_id_rsa | base64 -w0

将编码后的字符串替换到 <BASE64_ENCODED_MAVEN_ID_RSA><BASE64_ENCODED_NPM_ID_RSA> 中。

应用 Secrets:

kubectl apply -f git-ssh-secret-maven.yaml
kubectl apply -f git-ssh-secret-npm.yaml

验证 Secrets 创建成功:

kubectl get secrets -n cicd

步骤 3:配置 Docker Registry 认证(使用 Kaniko)

3.1 准备 Docker Registry 凭证

确保您有镜像仓库的服务器地址、用户名、密码和邮箱。

3.2 创建 Docker Registry Secret

保存为 kaniko-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: kaniko-secret
  namespace: cicd
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <BASE64_ENCODED_DOCKER_CONFIG_JSON>

生成 .dockerconfigjson 的方法:

您可以使用以下命令自动生成:

kubectl create secret docker-registry kaniko-secret \
  --namespace=cicd \
  --docker-server=<YOUR_DOCKER_REGISTRY_SERVER> \
  --docker-username=<YOUR_USERNAME> \
  --docker-password=<YOUR_PASSWORD> \
  --docker-email=<YOUR_EMAIL> \
  --dry-run=client -o jsonpath='{.data.\.dockerconfigjson}' | base64 -w0

将输出结果替换到 kaniko-secret.yaml 中的 <BASE64_ENCODED_DOCKER_CONFIG_JSON>

应用 Secret:

kubectl apply -f kaniko-secret.yaml

验证 Secret 创建成功:

kubectl get secrets -n cicd

步骤 4:创建 SMTP Secret

用于邮件通知。

保存为 smtp-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: smtp-secret
  namespace: cicd
type: Opaque
data:
  smtp-server: <BASE64_ENCODED_SMTP_SERVER>
  smtp-port: <BASE64_ENCODED_SMTP_PORT>
  smtp-username: <BASE64_ENCODED_SMTP_USERNAME>
  smtp-password: <BASE64_ENCODED_SMTP_PASSWORD>
  from-email: <BASE64_ENCODED_FROM_EMAIL>
  to-email: <BASE64_ENCODED_TO_EMAIL>

将各字段值进行 Base64 编码:

echo -n 'smtp.gmail.com' | base64 -w0
echo -n '587' | base64 -w0
echo -n 'user@gmail.com' | base64 -w0
echo -n 'password123' | base64 -w0
echo -n 'user@gmail.com' | base64 -w0
echo -n 'admin@example.com' | base64 -w0

示例:

apiVersion: v1
kind: Secret
metadata:
  name: smtp-secret
  namespace: cicd
type: Opaque
data:
  smtp-server: c210cC5nbWFpbC5jb20= # smtp.gmail.com
  smtp-port: NTg3 # 587
  smtp-username: dXNlckBnbWFpbC5jb20= # user@gmail.com
  smtp-password: cGFzc3dvcmQxMjM= # password123
  from-email: dXNlckBnbWFpbC5jb20= # user@gmail.com
  to-email: YWRtaW5AZXhhbXBsZS5jb20= # admin@example.com

应用 Secret:

kubectl apply -f smtp-secret.yaml

验证 Secret 创建成功:

kubectl get secrets -n cicd

步骤 5:创建 PersistentVolumeClaim(PVC)

Tekton 需要持久化存储来存放工作空间数据。

保存为 workspace-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: workspace-pvc
  namespace: cicd
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

应用 PVC:

kubectl apply -f workspace-pvc.yaml

验证 PVC 状态:

kubectl get pvc -n cicd

步骤 6:创建 ServiceAccount 和权限绑定

确保 Tekton Pipelines 有足够的权限访问 Kubernetes API 和相关资源。

保存为 tekton-sa.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-sa
  namespace: cicd

应用 ServiceAccount:

kubectl apply -f tekton-sa.yaml

绑定权限(示例:赋予 edit 权限):

kubectl create rolebinding tekton-sa-edit \
  --clusterrole=edit \
  --serviceaccount=cicd:tekton-sa \
  --namespace=cicd

说明:

  • edit ClusterRole 赋予了在命名空间内编辑资源的权限。根据实际需求,可以调整权限。

步骤 7:创建 Tekton Tasks

我们将为 Maven 和 npm 项目分别创建初始化任务和代码拉取任务。构建、推送镜像、部署和发送邮件的任务可以共用。

7.1 初始化环境任务

7.1.1 初始化 Maven 环境任务 (init-maven.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-maven
  namespace: cicd
spec:
  steps:
    - name: setup-maven
      image: maven:3.8.6-jdk-11
      script: |
        #!/bin/sh
        set -e
        echo "初始化 Maven 环境..."
        mvn --version
        # 在此处添加任何 Maven 相关的初始化步骤,例如下载依赖

7.1.2 初始化 npm 环境任务 (init-npm.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-npm
  namespace: cicd
spec:
  steps:
    - name: setup-npm
      image: node:16
      script: |
        #!/bin/sh
        set -e
        echo "初始化 NPM 环境..."
        node --version
        npm --version
        # 在此处添加任何 NPM 相关的初始化步骤,例如安装全局包

应用初始化任务:

kubectl apply -f init-maven.yaml
kubectl apply -f init-npm.yaml
7.2 拉取代码任务

7.2.1 拉取 Maven 项目代码任务 (clone-repo-maven.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-maven
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-maven-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 Maven 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-maven
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-maven
      secret:
        secretName: git-ssh-key-maven

7.2.2 拉取 npm 项目代码任务 (clone-repo-npm.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-npm
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-npm-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 npm 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-npm
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-npm
      secret:
        secretName: git-ssh-key-npm

应用拉取代码任务:

kubectl apply -f clone-repo-maven.yaml
kubectl apply -f clone-repo-npm.yaml
7.3 运行 dockerContext.sh 任务 (run-docker-context.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: run-docker-context
  namespace: cicd
spec:
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: run-script
      image: bash:latest
      script: |
        #!/bin/sh
        set -e
        cd $(workspaces.source.path)
        if [ -f .manifest/dockerContext.sh ]; then
          echo "运行 dockerContext.sh 脚本..."
          chmod +x .manifest/dockerContext.sh
          ./.manifest/dockerContext.sh || echo "dockerContext.sh 执行失败,跳过..."
        else
          echo "未找到 dockerContext.sh 脚本,跳过..."
        fi

应用任务:

kubectl apply -f run-docker-context.yaml
7.4 构建并推送镜像任务(使用 Kaniko) (build-and-push-kaniko.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-and-push-kaniko
  namespace: cicd
spec:
  params:
    - name: image
      description: Docker 镜像名称
      type: string
    - name: dockerfile
      description: Dockerfile 的路径
      default: ./Dockerfile
      type: string
    - name: context
      description: 构建上下文路径
      default: .
      type: string
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:latest
      command:
        - /kaniko/executor
      args:
        - "--context=$(workspaces.source.path)/$(params.context)"
        - "--dockerfile=$(workspaces.source.path)/$(params.dockerfile)"
        - "--destination=$(params.image)"
        - "--oci-layout-path=/kaniko/oci"
        - "--cache=true"
        - "--cache-repo=$(params.image)"
      env:
        - name: DOCKER_CONFIG
          value: /kaniko/.docker/
      volumeMounts:
        - name: kaniko-secret
          mountPath: /kaniko/.docker/
  volumes:
    - name: kaniko-secret
      secret:
        secretName: kaniko-secret

应用任务:

kubectl apply -f build-and-push-kaniko.yaml
7.5 部署到 Kubernetes 任务 (deploy-to-kubernetes.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: deploy-to-kubernetes
  namespace: cicd
spec:
  params:
    - name: namespace
      description: Kubernetes 命名空间
      type: string
    - name: deployment-name
      description: Kubernetes Deployment 名称
      type: string
    - name: image
      description: 要部署的镜像
      type: string
  steps:
    - name: deploy
      image: bitnami/kubectl
      script: |
        #!/bin/sh
        set -e
        echo "将镜像 $(params.image) 部署到命名空间 $(params.namespace)..."
        kubectl set image deployment/$(params.deployment-name) app=$(params.image) -n $(params.namespace)
    - name: set-status
      image: alpine
      script: |
        #!/bin/sh
        echo "succeeded" > /tekton/results/status
  results:
    - name: status
      description: 部署状态

应用任务:

kubectl apply -f deploy-to-kubernetes.yaml
7.6 发送邮件通知任务 (send-email.yaml)

(已在上文提供,此处重复以方便参考)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: send-email
  namespace: cicd
spec:
  params:
    - name: subject
      type: string
      description: 邮件主题
    - name: body
      type: string
      description: 邮件正文
  steps:
    - name: send-email
      image: curlimages/curl:7.83.1
      script: |
        #!/bin/sh
        set -e

        SMTP_SERVER=$(cat /var/secrets/smtp/smtp-server)
        SMTP_PORT=$(cat /var/secrets/smtp/smtp-port)
        SMTP_USERNAME=$(cat /var/secrets/smtp/smtp-username)
        SMTP_PASSWORD=$(cat /var/secrets/smtp/smtp-password)
        FROM_EMAIL=$(cat /var/secrets/smtp/from-email)
        TO_EMAIL=$(cat /var/secrets/smtp/to-email)

        SUBJECT="$(params.subject)"
        BODY="$(params.body)"

        echo "正在通过 $SMTP_SERVER:$SMTP_PORT 发送邮件到 $TO_EMAIL..."

        echo -e "Subject: $SUBJECT\n\n$BODY" | \
          curl --url "smtp://$SMTP_SERVER:$SMTP_PORT" \
               --ssl-reqd \
               --mail-from "$FROM_EMAIL" \
               --mail-rcpt "$TO_EMAIL" \
               --user "$SMTP_USERNAME:$SMTP_PASSWORD" \
               -T -
  volumes:
    - name: smtp-secrets
      secret:
        secretName: smtp-secret

应用任务:

kubectl apply -f send-email.yaml

步骤 8:创建 Tekton Pipelines

为 Maven 和 npm 项目分别创建独立的流水线。

8.1 Maven 流水线 (maven-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: maven-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-maven
      taskRef:
        name: init-maven
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-maven
      taskRef:
        name: clone-repo-maven
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "Maven 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **Maven 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
      workspaces:
        - name: source
          workspace: source
8.2 npm 流水线 (npm-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: npm-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-npm
      taskRef:
        name: init-npm
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-npm
      taskRef:
        name: clone-repo-npm
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "NPM 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **NPM 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
      workspaces:
        - name: source
          workspace: source

说明:

  • Maven 和 npm 流水线结构类似,但各自引用不同的初始化和代码拉取任务。
  • finally 部分确保无论前面的任务成功还是失败,都会执行 send-email 任务发送通知。

应用流水线:

kubectl apply -f maven-pipeline.yaml
kubectl apply -f npm-pipeline.yaml

验证流水线创建成功:

kubectl get pipelines -n cicd

步骤 9:创建 dockerContext.sh 脚本

dockerContext.sh 是一个用于处理特定上下文操作的脚本。根据您的需求,您可以在此脚本中添加自定义逻辑。以下是一个示例脚本:

创建 dockerContext.sh 文件:

#!/bin/sh
set -e

echo "执行 dockerContext.sh 脚本..."

# 示例操作:生成 Docker 镜像标签
TIMESTAMP=$(date +%Y%m%d%H%M%S)
echo "生成的时间戳标签:$TIMESTAMP"

# 您可以在此处添加更多自定义操作,例如修改配置文件、生成额外文件等。

echo "dockerContext.sh 脚本执行完成。"

说明:

  • 功能:此脚本用于执行构建前的自定义操作,例如生成镜像标签、修改配置文件等。
  • 位置:将此脚本放置在项目的 .manifest/ 目录下,即 .manifest/dockerContext.sh

确保脚本具有执行权限:

chmod +x .manifest/dockerContext.sh

步骤 10:应用所有 Tekton 资源

按照以下顺序依次应用所有 Tekton 任务和流水线配置文件:

kubectl apply -f init-maven.yaml
kubectl apply -f init-npm.yaml
kubectl apply -f clone-repo-maven.yaml
kubectl apply -f clone-repo-npm.yaml
kubectl apply -f run-docker-context.yaml
kubectl apply -f build-and-push-kaniko.yaml
kubectl apply -f deploy-to-kubernetes.yaml
kubectl apply -f send-email.yaml
kubectl apply -f maven-pipeline.yaml
kubectl apply -f npm-pipeline.yaml
kubectl apply -f workspace-pvc.yaml
kubectl apply -f kaniko-secret.yaml
kubectl apply -f smtp-secret.yaml
kubectl apply -f tekton-sa.yaml

验证资源创建成功:

kubectl get tasks,pipelines -n cicd
kubectl get pvc -n cicd
kubectl get secrets -n cicd
kubectl get serviceaccounts -n cicd

步骤 11:测试与运行

11.1 手动触发 Maven 流水线

创建并应用 Maven PipelineRun (maven-pipelinerun.yaml):

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: maven-pipelinerun-$(date +%s)
  namespace: cicd
spec:
  pipelineRef:
    name: maven-pipeline
  params:
    - name: repo-url
      value: https://github.com/example/maven-app.git
    - name: branch
      value: main
    - name: image
      value: docker.io/example/maven-app:latest
    - name: namespace
      value: dev
    - name: deployment-name
      value: maven-app
  workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: workspace-pvc
  serviceAccountName: tekton-sa

应用 PipelineRun:

kubectl apply -f maven-pipelinerun.yaml
11.2 手动触发 npm 流水线

创建并应用 npm PipelineRun (npm-pipelinerun.yaml):

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: npm-pipelinerun-$(date +%s)
  namespace: cicd
spec:
  pipelineRef:
    name: npm-pipeline
  params:
    - name: repo-url
      value: https://github.com/example/npm-app.git
    - name: branch
      value: main
    - name: image
      value: docker.io/example/npm-app:latest
    - name: namespace
      value: dev
    - name: deployment-name
      value: npm-app
  workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: workspace-pvc
  serviceAccountName: tekton-sa

应用 PipelineRun:

kubectl apply -f npm-pipelinerun.yaml

或者,您也可以使用 tkn CLI 触发 Pipeline:

# 触发 Maven 流水线
tkn pipeline start maven-pipeline \
  -p repo-url=https://github.com/example/maven-app.git \
  -p branch=main \
  -p image=docker.io/example/maven-app:latest \
  -p namespace=dev \
  -p deployment-name=maven-app \
  -w name=source,claimName=workspace-pvc \
  --serviceaccount=tekton-sa

# 触发 npm 流水线
tkn pipeline start npm-pipeline \
  -p repo-url=https://github.com/example/npm-app.git \
  -p branch=main \
  -p image=docker.io/example/npm-app:latest \
  -p namespace=dev \
  -p deployment-name=npm-app \
  -w name=source,claimName=workspace-pvc \
  --serviceaccount=tekton-sa
11.3 监控流水线运行状态
# 查看流水线列表
kubectl get pipelines -n cicd

# 查看 PipelineRun 列表
kubectl get pipelineruns -n cicd

# 查看特定 PipelineRun 的日志
tkn pipelinerun logs <pipelinerun-name> -f -n cicd

<pipelinerun-name> 替换为实际的 PipelineRun 名称。

步骤 12:验证邮件通知功能

  1. 触发流水线:按照上述步骤 11.1 或 11.2 触发 Maven 或 npm 流水线。
  2. 检查邮件:确认指定的 to-email 收到相应的通知邮件。
  3. 排查问题
    • 如果邮件未收到,请检查:
      • smtp-secret 是否正确配置,确保所有字段都已正确 Base64 编码。
      • SMTP 服务器是否允许通过 API 或外部应用发送邮件(例如,Gmail 可能需要启用“应用专用密码”)。
      • 查看 send-email 任务的日志,确认 curl 命令是否执行成功。

关键 YAML 文件汇总

1. 初始化环境任务

1.1 Maven 初始化任务 (init-maven.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-maven
  namespace: cicd
spec:
  steps:
    - name: setup-maven
      image: maven:3.8.6-jdk-11
      script: |
        #!/bin/sh
        set -e
        echo "初始化 Maven 环境..."
        mvn --version
        # 在此处添加任何 Maven 相关的初始化步骤,例如下载依赖
1.2 npm 初始化任务 (init-npm.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-npm
  namespace: cicd
spec:
  steps:
    - name: setup-npm
      image: node:16
      script: |
        #!/bin/sh
        set -e
        echo "初始化 NPM 环境..."
        node --version
        npm --version
        # 在此处添加任何 NPM 相关的初始化步骤,例如安装全局包

2. 拉取代码任务

2.1 拉取 Maven 项目代码任务 (clone-repo-maven.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-maven
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-maven-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 Maven 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-maven
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-maven
      secret:
        secretName: git-ssh-key-maven
2.2 拉取 npm 项目代码任务 (clone-repo-npm.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-npm
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-npm-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 npm 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-npm
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-npm
      secret:
        secretName: git-ssh-key-npm

3. 运行 dockerContext.sh 任务 (run-docker-context.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: run-docker-context
  namespace: cicd
spec:
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: run-script
      image: bash:latest
      script: |
        #!/bin/sh
        set -e
        cd $(workspaces.source.path)
        if [ -f .manifest/dockerContext.sh ]; then
          echo "运行 dockerContext.sh 脚本..."
          chmod +x .manifest/dockerContext.sh
          ./.manifest/dockerContext.sh || echo "dockerContext.sh 执行失败,跳过..."
        else
          echo "未找到 dockerContext.sh 脚本,跳过..."
        fi

4. 构建并推送镜像任务(使用 Kaniko) (build-and-push-kaniko.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-and-push-kaniko
  namespace: cicd
spec:
  params:
    - name: image
      description: Docker 镜像名称
      type: string
    - name: dockerfile
      description: Dockerfile 的路径
      default: ./Dockerfile
      type: string
    - name: context
      description: 构建上下文路径
      default: .
      type: string
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:latest
      command:
        - /kaniko/executor
      args:
        - "--context=$(workspaces.source.path)/$(params.context)"
        - "--dockerfile=$(workspaces.source.path)/$(params.dockerfile)"
        - "--destination=$(params.image)"
        - "--oci-layout-path=/kaniko/oci"
        - "--cache=true"
        - "--cache-repo=$(params.image)"
      env:
        - name: DOCKER_CONFIG
          value: /kaniko/.docker/
      volumeMounts:
        - name: kaniko-secret
          mountPath: /kaniko/.docker/
  volumes:
    - name: kaniko-secret
      secret:
        secretName: kaniko-secret

5. 部署到 Kubernetes 任务 (deploy-to-kubernetes.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: deploy-to-kubernetes
  namespace: cicd
spec:
  params:
    - name: namespace
      description: Kubernetes 命名空间
      type: string
    - name: deployment-name
      description: Kubernetes Deployment 名称
      type: string
    - name: image
      description: 要部署的镜像
      type: string
  steps:
    - name: deploy
      image: bitnami/kubectl
      script: |
        #!/bin/sh
        set -e
        echo "将镜像 $(params.image) 部署到命名空间 $(params.namespace)..."
        kubectl set image deployment/$(params.deployment-name) app=$(params.image) -n $(params.namespace)
    - name: set-status
      image: alpine
      script: |
        #!/bin/sh
        echo "succeeded" > /tekton/results/status
  results:
    - name: status
      description: 部署状态

6. 发送邮件通知任务 (send-email.yaml)

(已在上文提供,此处重复以方便参考)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: send-email
  namespace: cicd
spec:
  params:
    - name: subject
      type: string
      description: 邮件主题
    - name: body
      type: string
      description: 邮件正文
  steps:
    - name: send-email
      image: curlimages/curl:7.83.1
      script: |
        #!/bin/sh
        set -e

        SMTP_SERVER=$(cat /var/secrets/smtp/smtp-server)
        SMTP_PORT=$(cat /var/secrets/smtp/smtp-port)
        SMTP_USERNAME=$(cat /var/secrets/smtp/smtp-username)
        SMTP_PASSWORD=$(cat /var/secrets/smtp/smtp-password)
        FROM_EMAIL=$(cat /var/secrets/smtp/from-email)
        TO_EMAIL=$(cat /var/secrets/smtp/to-email)

        SUBJECT="$(params.subject)"
        BODY="$(params.body)"

        echo "正在通过 $SMTP_SERVER:$SMTP_PORT 发送邮件到 $TO_EMAIL..."

        echo -e "Subject: $SUBJECT\n\n$BODY" | \
          curl --url "smtp://$SMTP_SERVER:$SMTP_PORT" \
               --ssl-reqd \
               --mail-from "$FROM_EMAIL" \
               --mail-rcpt "$TO_EMAIL" \
               --user "$SMTP_USERNAME:$SMTP_PASSWORD" \
               -T -
  volumes:
    - name: smtp-secrets
      secret:
        secretName: smtp-secret

应用任务:

kubectl apply -f send-email.yaml

步骤 7:创建 Tekton Pipelines

7.1 Maven 流水线 (maven-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: maven-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-maven
      taskRef:
        name: init-maven
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-maven
      taskRef:
        name: clone-repo-maven
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "Maven 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **Maven 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
  workspaces:
    - name: source
      workspace: source
7.2 npm 流水线 (npm-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: npm-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-npm
      taskRef:
        name: init-npm
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-npm
      taskRef:
        name: clone-repo-npm
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "NPM 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **NPM 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
  workspaces:
    - name: source
      workspace: source

说明:

  • Maven 和 npm 流水线结构类似,但各自引用不同的初始化和代码拉取任务。
  • finally 部分确保无论前面的任务成功还是失败,都会执行 send-email 任务发送通知。

应用流水线:

kubectl apply -f maven-pipeline.yaml
kubectl apply -f npm-pipeline.yaml

步骤 10:创建 dockerContext.sh 脚本

dockerContext.sh 是一个用于处理特定上下文操作的脚本。根据您的需求,您可以在此脚本中添加自定义逻辑。以下是一个示例脚本:

创建 dockerContext.sh 文件:

将以下内容保存为项目中的 .manifest/dockerContext.sh 文件:

#!/bin/sh
set -e

echo "执行 dockerContext.sh 脚本..."

# 示例操作:生成 Docker 镜像标签
TIMESTAMP=$(date +%Y%m%d%H%M%S)
echo "生成的时间戳标签:$TIMESTAMP"

# 您可以在此处添加更多自定义操作,例如修改配置文件、生成额外文件等。

echo "dockerContext.sh 脚本执行完成。"

说明:

  • 功能:此脚本用于执行构建前的自定义操作,例如生成镜像标签、修改配置文件等。
  • 位置:将此脚本放置在项目的 .manifest/ 目录下,即 .manifest/dockerContext.sh

确保脚本具有执行权限:

chmod +x .manifest/dockerContext.sh

步骤 11:应用所有 Tekton 资源

按照以下顺序依次应用所有 Tekton 任务和流水线配置文件:

kubectl apply -f init-maven.yaml
kubectl apply -f init-npm.yaml
kubectl apply -f clone-repo-maven.yaml
kubectl apply -f clone-repo-npm.yaml
kubectl apply -f run-docker-context.yaml
kubectl apply -f build-and-push-kaniko.yaml
kubectl apply -f deploy-to-kubernetes.yaml
kubectl apply -f send-email.yaml
kubectl apply -f maven-pipeline.yaml
kubectl apply -f npm-pipeline.yaml
kubectl apply -f workspace-pvc.yaml
kubectl apply -f kaniko-secret.yaml
kubectl apply -f smtp-secret.yaml
kubectl apply -f tekton-sa.yaml

验证资源创建成功:

kubectl get tasks,pipelines -n cicd
kubectl get pvc -n cicd
kubectl get secrets -n cicd
kubectl get serviceaccounts -n cicd

步骤 12:测试与运行

12.1 手动触发 Maven 流水线

创建并应用 Maven PipelineRun (maven-pipelinerun.yaml):

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: maven-pipelinerun-$(date +%s)
  namespace: cicd
spec:
  pipelineRef:
    name: maven-pipeline
  params:
    - name: repo-url
      value: https://github.com/example/maven-app.git
    - name: branch
      value: main
    - name: image
      value: docker.io/example/maven-app:latest
    - name: namespace
      value: dev
    - name: deployment-name
      value: maven-app
  workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: workspace-pvc
  serviceAccountName: tekton-sa

应用 PipelineRun:

kubectl apply -f maven-pipelinerun.yaml
12.2 手动触发 npm 流水线

创建并应用 npm PipelineRun (npm-pipelinerun.yaml):

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: npm-pipelinerun-$(date +%s)
  namespace: cicd
spec:
  pipelineRef:
    name: npm-pipeline
  params:
    - name: repo-url
      value: https://github.com/example/npm-app.git
    - name: branch
      value: main
    - name: image
      value: docker.io/example/npm-app:latest
    - name: namespace
      value: dev
    - name: deployment-name
      value: npm-app
  workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: workspace-pvc
  serviceAccountName: tekton-sa

应用 PipelineRun:

kubectl apply -f npm-pipelinerun.yaml

或者,您也可以使用 tkn CLI 触发 Pipeline:

# 触发 Maven 流水线
tkn pipeline start maven-pipeline \
  -p repo-url=https://github.com/example/maven-app.git \
  -p branch=main \
  -p image=docker.io/example/maven-app:latest \
  -p namespace=dev \
  -p deployment-name=maven-app \
  -w name=source,claimName=workspace-pvc \
  --serviceaccount=tekton-sa

# 触发 npm 流水线
tkn pipeline start npm-pipeline \
  -p repo-url=https://github.com/example/npm-app.git \
  -p branch=main \
  -p image=docker.io/example/npm-app:latest \
  -p namespace=dev \
  -p deployment-name=npm-app \
  -w name=source,claimName=workspace-pvc \
  --serviceaccount=tekton-sa
12.3 监控流水线运行状态
# 查看流水线列表
kubectl get pipelines -n cicd

# 查看 PipelineRun 列表
kubectl get pipelineruns -n cicd

# 查看特定 PipelineRun 的日志
tkn pipelinerun logs <pipelinerun-name> -f -n cicd

<pipelinerun-name> 替换为实际的 PipelineRun 名称。

步骤 13:验证邮件通知功能

  1. 触发流水线:按照上述步骤 12.1 或 12.2 触发 Maven 或 npm 流水线。
  2. 检查邮件:确认指定的 to-email 收到相应的通知邮件。
  3. 排查问题
    • 如果邮件未收到,请检查:
      • smtp-secret 是否正确配置,确保所有字段都已正确 Base64 编码。
      • SMTP 服务器是否允许通过 API 或外部应用发送邮件(例如,Gmail 可能需要启用“应用专用密码”)。
      • 查看 send-email 任务的日志,确认 curl 命令是否执行成功。

关键 YAML 文件汇总

以下是所有关键 YAML 文件的汇总,供参考:

1. 初始化环境任务

1.1 Maven 初始化任务 (init-maven.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-maven
  namespace: cicd
spec:
  steps:
    - name: setup-maven
      image: maven:3.8.6-jdk-11
      script: |
        #!/bin/sh
        set -e
        echo "初始化 Maven 环境..."
        mvn --version
        # 在此处添加任何 Maven 相关的初始化步骤,例如下载依赖
1.2 npm 初始化任务 (init-npm.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: init-npm
  namespace: cicd
spec:
  steps:
    - name: setup-npm
      image: node:16
      script: |
        #!/bin/sh
        set -e
        echo "初始化 NPM 环境..."
        node --version
        npm --version
        # 在此处添加任何 NPM 相关的初始化步骤,例如安装全局包

2. 拉取代码任务

2.1 拉取 Maven 项目代码任务 (clone-repo-maven.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-maven
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-maven-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 Maven 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-maven
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-maven
      secret:
        secretName: git-ssh-key-maven
2.2 拉取 npm 项目代码任务 (clone-repo-npm.yaml)
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: clone-repo-npm
  namespace: cicd
spec:
  params:
    - name: repo-url
      description: Git 仓库地址
      type: string
    - name: revision
      description: Git 分支或标签
      type: string
  workspaces:
    - name: source
      description: 存放拉取代码的工作空间
  steps:
    - name: clone-npm-repo
      image: alpine/git
      script: |
        #!/bin/sh
        set -e
        echo "从 $(params.repo-url) 克隆 npm 仓库..."
        git clone $(params.repo-url) $(workspaces.source.path)
        cd $(workspaces.source.path)
        git checkout $(params.revision)
      volumeMounts:
        - name: ssh-credentials-npm
          mountPath: /root/.ssh
  volumes:
    - name: ssh-credentials-npm
      secret:
        secretName: git-ssh-key-npm

3. 运行 dockerContext.sh 任务 (run-docker-context.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: run-docker-context
  namespace: cicd
spec:
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: run-script
      image: bash:latest
      script: |
        #!/bin/sh
        set -e
        cd $(workspaces.source.path)
        if [ -f .manifest/dockerContext.sh ]; then
          echo "运行 dockerContext.sh 脚本..."
          chmod +x .manifest/dockerContext.sh
          ./.manifest/dockerContext.sh || echo "dockerContext.sh 执行失败,跳过..."
        else
          echo "未找到 dockerContext.sh 脚本,跳过..."
        fi

4. 构建并推送镜像任务(使用 Kaniko) (build-and-push-kaniko.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-and-push-kaniko
  namespace: cicd
spec:
  params:
    - name: image
      description: Docker 镜像名称
      type: string
    - name: dockerfile
      description: Dockerfile 的路径
      default: ./Dockerfile
      type: string
    - name: context
      description: 构建上下文路径
      default: .
      type: string
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  steps:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:latest
      command:
        - /kaniko/executor
      args:
        - "--context=$(workspaces.source.path)/$(params.context)"
        - "--dockerfile=$(workspaces.source.path)/$(params.dockerfile)"
        - "--destination=$(params.image)"
        - "--oci-layout-path=/kaniko/oci"
        - "--cache=true"
        - "--cache-repo=$(params.image)"
      env:
        - name: DOCKER_CONFIG
          value: /kaniko/.docker/
      volumeMounts:
        - name: kaniko-secret
          mountPath: /kaniko/.docker/
  volumes:
    - name: kaniko-secret
      secret:
        secretName: kaniko-secret

5. 部署到 Kubernetes 任务 (deploy-to-kubernetes.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: deploy-to-kubernetes
  namespace: cicd
spec:
  params:
    - name: namespace
      description: Kubernetes 命名空间
      type: string
    - name: deployment-name
      description: Kubernetes Deployment 名称
      type: string
    - name: image
      description: 要部署的镜像
      type: string
  steps:
    - name: deploy
      image: bitnami/kubectl
      script: |
        #!/bin/sh
        set -e
        echo "将镜像 $(params.image) 部署到命名空间 $(params.namespace)..."
        kubectl set image deployment/$(params.deployment-name) app=$(params.image) -n $(params.namespace)
    - name: set-status
      image: alpine
      script: |
        #!/bin/sh
        echo "succeeded" > /tekton/results/status
  results:
    - name: status
      description: 部署状态

6. 发送邮件通知任务 (send-email.yaml)

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: send-email
  namespace: cicd
spec:
  params:
    - name: subject
      type: string
      description: 邮件主题
    - name: body
      type: string
      description: 邮件正文
  steps:
    - name: send-email
      image: curlimages/curl:7.83.1
      script: |
        #!/bin/sh
        set -e

        SMTP_SERVER=$(cat /var/secrets/smtp/smtp-server)
        SMTP_PORT=$(cat /var/secrets/smtp/smtp-port)
        SMTP_USERNAME=$(cat /var/secrets/smtp/smtp-username)
        SMTP_PASSWORD=$(cat /var/secrets/smtp/smtp-password)
        FROM_EMAIL=$(cat /var/secrets/smtp/from-email)
        TO_EMAIL=$(cat /var/secrets/smtp/to-email)

        SUBJECT="$(params.subject)"
        BODY="$(params.body)"

        echo "正在通过 $SMTP_SERVER:$SMTP_PORT 发送邮件到 $TO_EMAIL..."

        echo -e "Subject: $SUBJECT\n\n$BODY" | \
          curl --url "smtp://$SMTP_SERVER:$SMTP_PORT" \
               --ssl-reqd \
               --mail-from "$FROM_EMAIL" \
               --mail-rcpt "$TO_EMAIL" \
               --user "$SMTP_USERNAME:$SMTP_PASSWORD" \
               -T -
  volumes:
    - name: smtp-secrets
      secret:
        secretName: smtp-secret

应用任务:

kubectl apply -f send-email.yaml

7. Tekton Pipelines

7.1 Maven 流水线 (maven-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: maven-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-maven
      taskRef:
        name: init-maven
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-maven
      taskRef:
        name: clone-repo-maven
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "Maven 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **Maven 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
  workspaces:
    - name: source
      workspace: source
7.2 npm 流水线 (npm-pipeline.yaml)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: npm-pipeline
  namespace: cicd
spec:
  params:
    - name: repo-url
      type: string
      description: Git 仓库地址
    - name: branch
      type: string
      description: Git 分支名称
    - name: image
      type: string
      description: Docker 镜像名称
    - name: namespace
      type: string
      description: Kubernetes 命名空间
    - name: deployment-name
      type: string
      description: Kubernetes Deployment 名称
  workspaces:
    - name: source
      description: 存放代码和构建上下文的工作空间
  tasks:
    - name: init-npm
      taskRef:
        name: init-npm
      runAfter: []
    - name: clone-repo
      runAfter:
        - init-npm
      taskRef:
        name: clone-repo-npm
      params:
        - name: repo-url
          value: $(params.repo-url)
        - name: revision
          value: $(params.branch)
      workspaces:
        - name: source
          workspace: source
    - name: run-docker-context
      runAfter:
        - clone-repo
      taskRef:
        name: run-docker-context
      workspaces:
        - name: source
          workspace: source
    - name: build-and-push
      runAfter:
        - run-docker-context
      taskRef:
        name: build-and-push-kaniko
      params:
        - name: image
          value: $(params.image)
        - name: dockerfile
          value: ./Dockerfile
        - name: context
          value: .
      workspaces:
        - name: source
          workspace: source
    - name: deploy
      runAfter:
        - build-and-push
      taskRef:
        name: deploy-to-kubernetes
      params:
        - name: namespace
          value: $(params.namespace)
        - name: deployment-name
          value: $(params.deployment-name)
        - name: image
          value: $(params.image)
  finally:
    - name: notify
      taskRef:
        name: send-email
      params:
        - name: subject
          value: "NPM 流水线 $(params.deployment-name) - $(tasks.deploy.results.status)"
        - name: body
          value: |
            流水线 **NPM 流水线** 已完成。
            
            - **仓库**: $(params.repo-url)
            - **分支**: $(params.branch)
            - **镜像**: $(params.image)
            - **命名空间**: $(params.namespace)
            - **部署名称**: $(params.deployment-name)
            
            **状态**: $(tasks.deploy.results.status)
  workspaces:
    - name: source
      workspace: source

说明:

  • Maven 和 npm 流水线结构类似,但各自引用不同的初始化和代码拉取任务。
  • finally 部分确保无论前面的任务成功还是失败,都会执行 send-email 任务发送通知。

应用流水线:

kubectl apply -f maven-pipeline.yaml
kubectl apply -f npm-pipeline.yaml

步骤 14:优化与容错

  1. 容错机制
    • run-docker-context 任务中已包含对 dockerContext.sh 脚本不存在或执行失败的处理,确保流水线不会因该脚本的问题中断。
  2. 重试策略
    • 根据需要在 Pipeline 或 Task 中配置重试策略,以应对临时性错误。
    • 示例:在任务定义中添加 retries 字段。
      spec:
        retries: 3
      
  3. 资源限制
    • 为每个 Task 设置资源请求和限制,避免资源争用。
      resources:
        requests:
          memory: "512Mi"
          cpu: "500m"
        limits:
          memory: "1Gi"
          cpu: "1"
      
  4. 日志存储与监控
    • 集成日志收集和监控工具(如 Elasticsearch、Prometheus 和 Grafana),实时监控流水线的执行状态和性能,及时发现并解决问题。

常见问题排查

1. 邮件未发送

  • 检查 SMTP Secret 配置

    • 确保 smtp-secret 中的所有字段(smtp-serversmtp-portsmtp-usernamesmtp-passwordfrom-emailto-email)已正确 Base64 编码并填入 smtp-secret.yaml 中。
  • 验证 SMTP 服务器设置

    • 确保 SMTP 服务器地址和端口正确。
    • 确认 SMTP 服务器允许通过 API 或外部应用发送邮件。
    • 对于 Gmail,可能需要启用“应用专用密码”或调整安全设置。
  • 查看 send-email 任务日志

    • 使用以下命令查看发送邮件任务的详细日志,确认 curl 命令是否执行成功。
    tkn pipelinerun logs <pipelinerun-name> -f -n cicd
    

    <pipelinerun-name> 替换为实际的 PipelineRun 名称。

2. 权限不足

  • 检查 ServiceAccount 权限

    • 确保 tekton-sa ServiceAccount 具有足够的权限访问 Kubernetes API 和相关资源。
  • 验证 RoleBinding 配置

    • 确保 RoleBinding 正确,将 tekton-sa 绑定到适当的 ClusterRole(例如 edit)。
  • 查看 RoleBinding

    kubectl get rolebinding -n cicd
    

3. 持久化存储问题

  • 验证 PVC 状态

    • 确保 workspace-pvc 已正确创建并处于绑定状态。
    kubectl get pvc workspace-pvc -n cicd
    
  • 确认有可用的 PersistentVolume

    • 确保集群中有可用的 PersistentVolume 提供所需的存储。

4. 任务失败

  • 查看失败任务的详细日志

    tkn pipelinerun logs <pipelinerun-name> -f -n cicd
    

    <pipelinerun-name> 替换为实际的 PipelineRun 名称。

  • 根据错误信息调整任务脚本或配置

    • 例如,如果 Maven 任务失败,检查 pom.xml 是否正确,依赖是否可用。