文章目录
一. 安装
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
二. 流水线部署
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,如下图:
点击进入
同样设置devops.enabled为true:
在 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相关资源是否已安装完成,如下图:
状态都是
健康,安装成功
2.3 创建企业空间
工作台 -> 企业空间 -> 创建
2.4 创建DevOps项目


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-ks | kubeconfig | 当前K8s集群的kubeconfig文件(新建时默认填充),用于Jenkins脚本部署K8s应用负载 |
双击 DevOps 项目名称进入
具体凭证列表如下图:
2.6 自定义 Jenkins Agent(忽略这一步)
2.6.1 查看agent配置
配置->配置字典->搜索jenkins-casc-config->编辑YAML
搜索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
2.6.5 maven-pvc(可以不用pvc执行挂载hostPath)

添加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

2.8.2 创建流水线


输入git仓库地址和凭证



2.8.3 查看git分支
双击流水线名称进入
2.8.4 运行


运行中
双击进入
2.8.5 查看日志
点击右上角 查看日志
可以看到执行了
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 页面。
点击 Security 并输入令牌名称,例如 kubesphere。
点击 Generate 并复制此令牌。
c0500471a49371f7fa4053f3b9dc50e091fc3d72
将上面生成的token保存到Jenkins凭据中
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/
依次点击 Administration、Configuration 和 Webhooks 创建一个 Webhook。
点击 Create。
在弹出的对话框中输入 Name 和 Jenkins Console URL(即 SonarQube Webhook 地址)。点击 Create 完成操作。
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。
sonar
http://192.168.4.27:32590
sonar-token
点击确定
3.5.2 全局配置SonarQube Scanner
点击 系统管理 -> 全局工具配置
点击保存
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 测试


四. 提交代码自动构建
4.1 查看Webhook 推送 URL
流水线 -> 编辑
复制URL
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

添加成功
4.3 测试
随便添加一行代码
触发自动构建
代码检查通过
构建成功