KubeSphere DevOps流水线部署

1 篇文章 0 订阅
1 篇文章 0 订阅

一. 安装

1.1 下载yaml

mkdir -p /root/i/yaml/kubesphere && cd /root/i/yaml/kubesphere
wget https://github.com/kubesphere/ks-installer/releases/download/v3.3.0/kubesphere-installer.yaml
wget https://github.com/kubesphere/ks-installer/releases/download/v3.3.0/cluster-configuration.yaml

查看

[root@master kubesphere]# ls
cluster-configuration.yaml  kubesphere-installer.yaml

1.2 设置默认StorageClass

[root@master kubesphere]# kubectl get sc | grep nfs-storage
nfs-storage   nfs-storage   Retain          Immediate           false                  115d
[root@master kubesphere]# kubectl patch storageclass nfs-storage -p  '{ "metadata" : { "annotations" :{"storageclass.kubernetes.io/is-default-class": "true"}}}'
storageclass.storage.k8s.io/nfs-storage patched
[root@master kubesphere]# kubectl get sc | grep nfs-storage
nfs-storage (default)   nfs-storage   Retain          Immediate           false                  115d

如果没有设置,不会安装

1.3 安装

kubectl create ns kubesphere-system
kubectl apply -f kubesphere-installer.yaml

安装成功

[root@master kubesphere]# kubectl get pods -n kubesphere-system
NAME                           READY   STATUS    RESTARTS   AGE
ks-installer-c9655d997-hpqns   1/1     Running   0          72s

1.4 配置

kubectl apply -f cluster-configuration.yaml

检查安装日志

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f

1.5 查看

新建了命名空间

kubesphere-controls-system:
kubesphere-monitoring-federated:联邦集群,多集群
kubesphere-monitoring-system:集群监控
kubesphere-system:

其他资源

[root@master kubesphere]# kubectl get pods -n kubesphere-system
NAME                                     READY   STATUS    RESTARTS   AGE
ks-apiserver-66cd784f8f-jn2k5            1/1     Running   0          11m
ks-console-5c5676fb55-h6krc              1/1     Running   0          11m
ks-controller-manager-6d6b54464d-qrxfs   1/1     Running   0          11m
ks-installer-c9655d997-kz4gb             1/1     Running   0          12m

[root@master kubesphere]# kubectl get svc -n kubesphere-system
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
ks-apiserver            ClusterIP   10.109.250.63   <none>        80/TCP         11m
ks-console              NodePort    10.102.49.78    <none>        80:30880/TCP   11m
ks-controller-manager   ClusterIP   10.101.243.88   <none>        443/TCP        11m

[root@master kubesphere]# kubectl get pods -n kubesphere-monitoring-system
NAME                                               READY   STATUS    RESTARTS   AGE
alertmanager-main-0                                2/2     Running   0          8m58s
alertmanager-main-1                                2/2     Running   0          8m57s
alertmanager-main-2                                2/2     Running   0          8m56s
kube-state-metrics-645c64569c-pkvkj                3/3     Running   0          9m55s
node-exporter-2t6pq                                2/2     Running   0          9m54s
node-exporter-bstgl                                2/2     Running   0          9m54s
node-exporter-mts6g                                2/2     Running   0          9m55s
notification-manager-deployment-7dd45b5b7d-p4bpr   2/2     Running   0          5m15s
notification-manager-deployment-7dd45b5b7d-sp8vw   2/2     Running   0          5m15s
notification-manager-operator-8598775b-vppz6       2/2     Running   0          9m34s
prometheus-k8s-0                                   2/2     Running   0          8m57s
prometheus-k8s-1                                   2/2     Running   0          8m55s
prometheus-operator-57c78bd7fb-jbfxs               2/2     Running   0          9m56s

[root@master kubesphere]# kubectl get pvc -n kubesphere-monitoring-system
NAME                                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
prometheus-k8s-db-prometheus-k8s-0   Bound    pvc-9046cbb5-8c31-4014-9342-6a63fb348fb3   20Gi       RWO            nfs-storage    9m9s
prometheus-k8s-db-prometheus-k8s-1   Bound    pvc-5816cdfc-0976-4312-918c-d4dc361d5ec9   20Gi       RWO            nfs-storage    9m7s

1.6 页面

访问 http://192.168.4.27:30880,默认账号密码admin/P@88w0rd,然后要求修改密码Ww$19930327
image.png

二. 流水线部署

2.1 开启流水线设置

2.1.1 未安装KS前进行设置

在安装KS前,可通过编辑config-sample.yaml文件,设置如下:

devops:
  enabled: true # 将"false"更改为true
2.1.2 已安装过KS通过管理界面进行设置

若之前已安装过KS,则可通过KS管理界面(平台管理->集群管理)左侧菜单定时资源定义(CRD) -> 搜索clusterconfiguration -> 然后编辑其下资源ks-installer,如下图:
image.png
点击进入
image.png
同样设置devops.enabledtrue
image.png
kubectl 中执行以下命令检查安装过程:

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f

Kubesphere Devops详细开启说明可参见:
https://kubesphere.io/zh/docs/pluggable-components/devops/

2.2 查看流水线安装

设置完成后可通过KS管理界面查看系统组件 - DevOps相关资源是否已安装完成,如下图:
image.png

状态都是健康,安装成功

2.3 创建企业空间

工作台 -> 企业空间 -> 创建
image.png

2.4 创建DevOps项目

image.png
image.png

2.5 Devops项目添加凭证

后续在使用流水线时,Jenkins pipeline脚本需要与外部Git仓库Docker仓库K8s集群(可以是外部集群)进行交互,所以需要在其对应的Devops项目中添加凭证(用于访问外部环境的账号密码、密钥等),后续在Jenkins pipeline脚本中会通过凭证名称(ID)进行引用。

测试环境的外部依赖如下:

凭证名称(ID)凭证类型凭证说明
gitee-wanfei用户名和密码Gitee登录账号密码,用于流水线拉取代码
docker-aliyun用户名和密码阿里云容器镜像服务ACR个人版 docker login账号密码,用于Jenkins脚本推送docker镜像
k8s-config-kskubeconfig当前K8s集群的kubeconfig文件(新建时默认填充),用于Jenkins脚本部署K8s应用负载

双击 DevOps 项目名称进入
具体凭证列表如下图:
image.png

2.6 自定义 Jenkins Agent(忽略这一步)

2.6.1 查看agent配置

配置->配置字典->搜索jenkins-casc-config->编辑YAML
image.png
搜索data.jenkins_user.yaml:jenkins.clouds.kubernetes.templates

2.6.2 自定义agent配置(label没有发现)

也可以添加自定义镜像,例如:

- name: "maven-jdk11" # 自定义 Jenkins Agent 的名称。
  label: "maven jdk11" # 自定义 Jenkins Agent 的标签。若要指定多个标签,请用空格来分隔标签。
  inheritFrom: "maven" # 该自定义 Jenkins Agent 所继承的现有容器组模板的名称。
  containers:
  - name: "maven" # 该自定义 Jenkins Agent 所继承的现有容器组模板中指定的容器名称。
    image: "kubespheredev/builder-maven:v3.2.0jdk11" # 此镜像只用于测试。您可以使用自己的镜像。
2.6.3 java8

官方镜像:kubesphere/builder-maven:v3.2.0,但是helm版本是2

2.6.4 java11

官方镜像:kubesphere/builder-maven:v3.2.1-jdk11,但是helm版本是2

Dockerfile可以参考 https://hub.docker.com/layers/builder-maven/kubesphere/builder-maven/v3.2.1-jdk11/images/sha256-0fed85db83a4b215a128ae1155a3f007fa6d03adc37f65acfd9bc2cdb4c5597a?context=explore

2.6.5 maven-pvc(可以不用pvc执行挂载hostPath)

image.png
添加maven-pvc,也可以使用现有的devops-jenkins pvc,存储maven下载的jar,多次部署不用重复下载

2.7 测试流水线Jenkinsfile(可以跳过)

2.7.1 使用自带的label maven
pipeline {
  agent {
    node {
      label 'maven'
    }
  }
  stages {
    stage('Print Maven and JDK version') {
      steps {
        container('maven') {
          sh '''
          mvn -v
          java -version
          '''
        }
      }
    }
  }
}

参考 https://kubesphere.io/zh/docs/v3.3/devops-user-guide/how-to-use/pipelines/choose-jenkins-agent/

2.7.2 使用自定义得label maven && jdk11(报错label发现不了)
pipeline {
  agent {
    node {
      label 'maven && jdk11'
    }
  }
  stages {
    stage('Print Maven and JDK version') {
      steps {
        container('maven') {
          sh '''
          mvn -v
          java -version
          '''
        }
      }
    }
  }
}

参考 https://kubesphere.io/zh/docs/v3.3/devops-user-guide/how-to-use/pipelines/customize-jenkins-agent/

2.7.3 yaml
pipeline {
  agent {
    kubernetes {
      //cloud 'kubernetes'
      label 'mypod'
      yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: maven
    image: kubesphere/builder-maven:v3.2.1-jdk11
    command: ['cat']
    tty: true
"""
    }
  }
  stages {
    stage('Print Maven and JDK version') {
      steps {
        container('maven') {
          sh '''
          mvn -v
          java -version
          '''
        }
      }
    }
  }
}

2.8 测试流水线

2.8.1 项目添加Jekinsfile``2.7.1

image.png

2.8.2 创建流水线

image.png
image.png
输入git仓库地址和凭证
image.png
image.png
image.png
image.png

2.8.3 查看git分支

双击流水线名称进入
image.png

2.8.4 运行

image.png
image.png
运行中
image.png
双击进入
image.png

2.8.5 查看日志

点击右上角 查看日志
image.png

可以看到执行了Jenkinsfile配置的流水线脚本

2.9 项目Jenkinsfile

def label = "slave-${UUID.randomUUID().toString()}"

def helmLint(String chartDir) {
    println "校验 chart 模板"
    sh "helm lint ${chartDir}"
}

def helmDeploy(Map args) {
    if (args.dry_run) {
        println "Debug 应用 ${args.profile} 环境"
        sh "helm upgrade --install --dry-run --debug --install ..."
    } else {
        println "部署应用 到 ${args.profile} 环境"
        sh "helm upgrade --install --set global.pullPolicy=Always --set global.javaOpts='-Xms256m -Xmx1024m -Xss512k -XX:+PrintGC' \
            --set global.imagePullSecrets=${args.imagePullSecrets} --set global.imageHub.server=${args.imageHubServer}\
            --set global.imageHub.project=${args.imageHubProject} --set global.version=${args.imageTag} \
            --set global.profiles=${args.profile} --set global.namespace=${args.namespace} ${args.name} ${args.chartDir}"
        echo "应用 ${args.name} 部署成功. 可以使用 helm status ${args.name} 查看应用状态"
    }
}

podTemplate(label: label,
    containers: [
        containerTemplate(name: 'maven', image: 'kubesphere/builder-maven:v3.2.1-jdk11', command: 'cat', ttyEnabled: true),
        containerTemplate(name: 'helm', image: 'hypnoglow/kubernetes-helm:3.0.2', command: 'cat', ttyEnabled: true)
    ],
    volumes: [
            hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock'),
            hostPathVolume(hostPath: '/var/data/jenkins_maven_cache', mountPath: '/root/.m2'),
            hostPathVolume(mountPath: '/var/data/jenkins_sonar_cache', hostPath: '/root/.sonar/cache')
        ]) {
        node(label) {
        // checkout scm 下载代码
        def myRepo = checkout scm
        def gitCommit = myRepo.GIT_COMMIT
        def gitBranch = myRepo.GIT_BRANCH
        // Docker凭证ID
        def dockerCredentialId = "docker-aliyun"
        def imageHubServer = "registry.cn-shanghai.aliyuncs.com"
        def imageHubProject = "wanfei"
        def imageTag = "1.0.0-dev"
        // K8S配置凭证ID
        def k8sConfigCredentialId = 'k8s-config-ks'

        stage('代码编译打包') {
            container('maven') {
                echo "1. 代码编译打包阶段"
                echo "当前commit: ${gitCommit}, 分支: ${gitBranch}"
                sh """
                ls -la
                mvn clean package -Dmaven.test.skip=true
                """
            }
        }

        stage('构建 Docker 镜像') {
            container('maven') {
                withCredentials([usernamePassword(credentialsId: "${dockerCredentialId}", passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME')]) {
                    echo "2. 构建 Docker 镜像阶段"
                    sh """
                    ls -la
                    echo "$DOCKER_PASSWORD" | docker login "${imageHubServer}" -u "$DOCKER_USERNAME" --password-stdin
                    sh ./script/deploy/buildImage.sh -v "${imageTag}" -s "${imageHubServer}" -p "${imageHubProject}"
                    """
                  }
            }
        }

        stage('运行 Helm') {
            container('helm') {
            echo "3. [INFO] 开始 Helm 部署"
                // 使用对应K8s配置
                withCredentials([
                    kubeconfigFile(
                    credentialsId: "${k8sConfigCredentialId}",
                    variable: 'KUBECONFIG')
                    ]) {
                        helmDeploy(
                            dry_run             : false,
                            imagePullSecrets    : "",
                            imageHubServer      : "${imageHubServer}",
                            imageHubProject     : "${imageHubProject}",
                            imageTag            : "${imageTag}",
                            profile             : "dev",
                            namespace           : "default",
                            name                : "devops-demo",
                            chartDir            : "./script/deploy/chart/"
                        )
                        echo "[INFO] Helm 部署应用成功..."
                }
            }
        }

    }
}

2.10 Jenkins

访问 http://192.168.4.27:30180/ ,账号密码admin / P@88w0rd

参考 https://kubesphere.io/zh/docs/v3.3/faq/devops/install-jenkins-plugins/

三. 集成sonar

3.1 helm安装sonar

helm upgrade --install sonarqube sonarqube \
  --repo https://charts.kubesphere.io/main \
  -n kubesphere-devops-system  \
  --create-namespace \
  --set service.type=NodePort \
  --set service.nodePort=32590
  • repo地址:https://charts.kubesphere.io/main
  • 安装版本:8.9-community

界面访问 http://192.168.4.27:32590/ 账号密码 admin / admin,修改密码为www19930327

3.2 创建 SonarQube 管理员令牌 (Token)

点击右上角字母 A,然后从菜单中选择 My Account 以转到 Profile 页面。
image.png
点击 Security 并输入令牌名称,例如 kubesphere
image.png
点击 Generate 并复制此令牌。
image.png

c0500471a49371f7fa4053f3b9dc50e091fc3d72

将上面生成的token保存到Jenkins凭据中
image.png

3.3 创建 Webhook 服务器

执行以下命令获取 SonarQube Webhook 的地址。(就是Jenkins地址)

export NODE_PORT=$(kubectl get --namespace kubesphere-devops-system -o jsonpath="{.spec.ports[0].nodePort}" services devops-jenkins)
export NODE_IP=$(kubectl get nodes --namespace kubesphere-devops-system -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/sonarqube-webhook/

预期输出结果:

http://192.168.4.27:30180/sonarqube-webhook/

依次点击 AdministrationConfigurationWebhooks 创建一个 Webhook。
image.png
点击 Create
image.png
在弹出的对话框中输入 NameJenkins Console URL(即 SonarQube Webhook 地址)。点击 Create 完成操作。
image.png

3.4 将 SonarQube 配置添加到 ks-installer

执行以下命令编辑 ks-installer。

kubectl edit cc -n kubesphere-system ks-installer

搜寻至 devops。添加字段 sonarqube 并在其下方指定 externalSonarUrl 和 externalSonarToken。

devops:
  enabled: true
  jenkinsJavaOpts_MaxRAM: 2g
  jenkinsJavaOpts_Xms: 512m
  jenkinsJavaOpts_Xmx: 512m
  jenkinsMemoryLim: 2Gi
  jenkinsMemoryReq: 1500Mi
  jenkinsVolumeSize: 8Gi
  sonarqube: # Add this field manually.
    externalSonarUrl: http://192.168.4.27:32590 # The SonarQube IP address.
    externalSonarToken: c0500471a49371f7fa4053f3b9dc50e091fc3d72 # The SonarQube admin token created above.

完成操作后保存此文件。

3.5 将 SonarQube 服务器添加至 Jenkins

3.5.1 配置sonar服务器

登录Jenkins
点击 系统管理 -> 系统配置
搜寻到 SonarQube servers,然后点击 Add SonarQube
image.png

sonar
http://192.168.4.27:32590
sonar-token

点击确定

3.5.2 全局配置SonarQube Scanner

点击 系统管理 -> 全局工具配置
image.png
点击保存

3.6 将 sonarqubeURL 添加到 KubeSphere 控制台

您需要指定 sonarqubeURL,以便可以直接从 KubeSphere 控制台访问 SonarQube。

执行以下命令:

kubectl edit  cm -n kubesphere-system  ks-console-config

搜寻到 data.client.enableKubeConfig,在下方添加 devops 字段并指定 sonarqubeURL。

client:
  enableKubeConfig: true
  devops: # 手动添加该字段。
    sonarqubeURL: http://192.168.4.27:32590 # SonarQube IP 地址。

保存该文件。

3.7 重启服务

kubectl -n kubesphere-devops-system rollout restart deploy devops-apiserver
kubectl -n kubesphere-system rollout restart deploy ks-console

3.8 项目Jenkinsfile

def label = "slave-${UUID.randomUUID().toString()}"

def helmLint(String chartDir) {
    println "校验 chart 模板"
    sh "helm lint ${chartDir}"
}

def helmDeploy(Map args) {
    if (args.dry_run) {
        println "Debug 应用 ${args.profile} 环境"
        sh "helm upgrade --install --dry-run --debug --install ..."
    } else {
        println "部署应用 到 ${args.profile} 环境"
        sh "helm upgrade --install --set global.pullPolicy=Always --set global.javaOpts='-Xms256m -Xmx1024m -Xss512k -XX:+PrintGC' \
            --set global.imagePullSecrets=${args.imagePullSecrets} --set global.imageHub.server=${args.imageHubServer}\
            --set global.imageHub.project=${args.imageHubProject} --set global.version=${args.imageTag} \
            --set global.profiles=${args.profile} --set global.namespace=${args.namespace} ${args.name} ${args.chartDir}"
        echo "应用 ${args.name} 部署成功. 可以使用 helm status ${args.name} 查看应用状态"
    }
}

podTemplate(label: label,
    containers: [
        containerTemplate(name: 'maven', image: 'kubesphere/builder-maven:v3.2.1-jdk11', command: 'cat', ttyEnabled: true),
        containerTemplate(name: 'helm', image: 'hypnoglow/kubernetes-helm:3.0.2', command: 'cat', ttyEnabled: true)
    ],
    volumes: [
            hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock'),
            hostPathVolume(hostPath: '/var/data/jenkins_maven_cache', mountPath: '/root/.m2'),
            hostPathVolume(mountPath: '/var/data/jenkins_sonar_cache', hostPath: '/root/.sonar/cache')
        ]) {
        node(label) {
        // checkout scm 下载代码
        def myRepo = checkout scm
        def gitCommit = myRepo.GIT_COMMIT
        def gitBranch = myRepo.GIT_BRANCH
        // Docker凭证ID
        def dockerCredentialId = "docker-aliyun"
        def imageHubServer = "registry.cn-shanghai.aliyuncs.com"
        def imageHubProject = "wanfei"
        def imageTag = "1.0.0-dev"
        // K8S配置凭证ID
        def k8sConfigCredentialId = 'k8s-config-ks'

        stage('代码编译打包') {
            container('maven') {
                echo "1. 代码编译打包阶段"
                echo "当前commit: ${gitCommit}, 分支: ${gitBranch}"
                sh """
                ls -la
                mvn clean package -Dmaven.test.skip=true
                """
            }
        }

        stage('代码扫描') {
            echo "2. 代码扫描阶段"
            // jenkins配置的 sonar-server name
            withSonarQubeEnv('sonar') {
                def SCANNER_HOME = tool 'sonar-scan'
                sh """
                ${SCANNER_HOME}/bin/sonar-scanner \
                -Dsonar.projectKey=devops-demo1 \
                -Dsonar.projectName=devops-demo1 \
                -Dsonar.projectVersion=1.0 \
                -Dsonar.sourceEncoding=UTF-8 \
                -Dsonar.language=java \
                -Dsonar.sources=src \
                -Dsonar.java.binaries=target/classes
                """
            }
        }

        stage('检查结果分析') {
            echo "3. 检查结果分析阶段"
            timeout(5) {
                // 等待sonarqube结果回调过来
                def qg = waitForQualityGate()
                echo "结果状态: ${qg.status}"
                if (qg.status != 'OK') {
                    error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
                }
            }
        }

        stage('构建 Docker 镜像') {
            container('maven') {
                withCredentials([usernamePassword(credentialsId: "${dockerCredentialId}", passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME')]) {
                    echo "4. 构建 Docker 镜像阶段"
                    sh """
                    ls -la
                    echo "$DOCKER_PASSWORD" | docker login "${imageHubServer}" -u "$DOCKER_USERNAME" --password-stdin
                    sh ./script/deploy/buildImage.sh -v "${imageTag}" -s "${imageHubServer}" -p "${imageHubProject}"
                    """
                  }
            }
        }

        stage('运行 Helm') {
            container('helm') {
            echo "5. [INFO] 开始 Helm 部署"
                // 使用对应K8s配置
                withCredentials([
                    kubeconfigFile(
                    credentialsId: "${k8sConfigCredentialId}",
                    variable: 'KUBECONFIG')
                    ]) {
                        helmDeploy(
                            dry_run             : false,
                            imagePullSecrets    : "",
                            imageHubServer      : "${imageHubServer}",
                            imageHubProject     : "${imageHubProject}",
                            imageTag            : "${imageTag}",
                            profile             : "dev",
                            namespace           : "default",
                            name                : "devops-demo",
                            chartDir            : "./script/deploy/chart/"
                        )
                        echo "[INFO] Helm 部署应用成功..."
                }
            }
        }

    }
}

3.9 测试

image.png
image.png

四. 提交代码自动构建

4.1 查看Webhook 推送 URL

流水线 -> 编辑
image.png
复制URL
image.png

4.2 gitee添加webhook

在这里插入图片描述
添加

因为部署再本地环境,gitee无法访问,所以配置下内网穿透测试

# 原地址
http://192.168.4.27:30880/devops_webhook/git/?url=https://gitee.com/www19930327/devops-demo.git

# 内网穿透后
http://frp-tai.wanfei.wang/devops_webhook/git/?url=https://gitee.com/www19930327/devops-demo.git

image.png
添加成功
在这里插入图片描述

4.3 测试

随便添加一行代码
image.png
触发自动构建
image.png
代码检查通过
image.png
构建成功
image.png

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值