kubesphere devops系统基于jenkins构建CI/CD工作流,可以方便快捷地构建、发布应用到k8s。本文以jeesite为例,说明devops流水线的构建过程。
创建前的准备
创建凭证:harbor-jeesite(帐户凭证),kubeconfig(kubeconfig),sonar(秘密文本),gitlab-id(帐户凭证)
流水线构建
进入自己的企业空间,点击devops工程,创建“jeesite”。
进入jeesite devops工程,创建jeesite-pipeline流水线,点击“编辑Jenkinsfile”,将下列代码修改后输入。
Jenkinsfile
pipeline {
agent {
node {
label 'maven'
}
}
stages {
stage('git-clone') {
agent none
steps {
sh 'git config --global http.sslverify false'
git(url: 'https://your-gitlab-url/your-group-name/jeesite4', credentialsId: 'gitlab-id', changelog: true, poll: false, branch: 'master')
}
}
stage('maven-test') {
agent none
steps {
container('maven') {
sh 'mvn -version'
}
}
}
stage('maven-deploy') {
agent none
steps {
container('maven') {
sh '''cd web/bin/
sh package.sh
# mvn -Dmaven.test.skip=true -Dfile.encoding=UTF-8 -DsourceEncoding=UTF-8 clean install -U -f web/pom.xml'''
}
}
}
stage('code-check') {
agent none
steps {
container('maven') {
withCredentials([string(credentialsId : 'sonar' ,variable : 'SONAR_TOKEN' ,)]) {
withSonarQubeEnv('sonar') {
sh '''cd web
mvn sonar:sonar -Dsonar.projectKey=jeesite -Dsonar.host.url=your-sonarqube-url -Dsonar.login=$SONAR_TOKEN'''
}
}
timeout(unit: 'HOURS', activity: true, time: 1) {
waitForQualityGate 'true'
}
}
}
}
stage('build & push') {
agent none
steps {
script {
env.COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
env.BUILD_FLAG="${COMMIT_ID}"
}
container('maven') {
sh 'docker build -f Dockerfile -t $REGISTRY/$HARBOR_NAMESPACE/$IMAGE_APP_NAME:$BUILD_FLAG .'
// 'robot$test+jeesite'中的test为HARBOR_NAMESPACE,jeesite为自己创建的机器人帐户名字
sh 'echo $HARBOR_CREDENTIAL_PSW | docker login $REGISTRY -u \'robot$test+jeesite\' --password-stdin'
sh 'docker push $REGISTRY/$HARBOR_NAMESPACE/$IMAGE_APP_NAME:$BUILD_FLAG'
}
}
}
stage('deploy2k8s') {
agent none
steps {
kubernetesDeploy(enableConfigSubstitution: true, deleteResource: false, kubeconfigId: 'kubeconfig', configs: 'deploy/jeesite.yaml')
}
}
}
environment {
IMAGE_APP_NAME = 'jeesite'
REGISTRY = 'your-harbor-domain'
HARBOR_NAMESPACE = 'test'
HARBOR_CREDENTIAL = credentials('harbor-jeesite')
}
}
将jeesite源码clone到自己的gitlab,进入web/src/main/resources/config/application.yml,修改jdbc配置。创建Dockerfile文件以打包镜像,创建deploy/jeesite.yaml文件以部署项目到k8s。
Dockerfile
FROM openjdk:8-jdk-alpine
COPY ./web/target/web.war /usr/local/web.war
RUN mkdir /usr/local/web \
&& unzip -n /usr/local/web.war -d /usr/local/web/ \
&& rm -rf /usr/local/web.war
WORKDIR /usr/local/web/WEB-INF/
ENTRYPOINT ["sh", "./startup.sh"]
jeesite.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jeesite
namespace: jeesite
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: jeesite
template:
metadata:
labels:
app: jeesite
spec:
# volumes:
# - name: volume-config
# configMap:
# name: jeesite-config
# items:
# - key: application.yml
# path: application.yml
# defaultMode: 0644
containers:
- image: $REGISTRY/$HARBOR_NAMESPACE/$IMAGE_APP_NAME:$BUILD_FLAG
name: jeesite
imagePullPolicy: Always
ports:
- containerPort: 80
name: http
- containerPort: 443
name: https
# volumeMounts:
# - name: volume-config
# readOnly: true
# mountPath: /usr/local/web/WEB-INF/classes/config/application.yml
# subPath: application.yml
imagePullSecrets:
- name: harbor-sec
restartPolicy: Always
---
apiVersion: v1
kind: Service # 若无域名,可自行修改为nodeport方式
metadata:
name: jeesite
namespace: jeesite
spec:
ports:
- port: 80
targetPort: 8980
selector:
app: jeesite
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress # 若无域名,则取消ingress
metadata:
name: jeesite
namespace: jeesite
annotations:
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- your-jeesite-domain
secretName: jeesite-crt-secret
rules:
- host: your-jeesite-domain
http:
paths:
- backend:
serviceName: jeesite
servicePort: 80
若harbor项目访问级别为私有,需要在k8s你所要部署jeesite的命名空间中添加密钥,这对应到jeesite.yaml中Deployment的template.imagePullSecrets字段。
若想将application.yml通过configmap挂载,可以将jeesite.yaml中的注释取消,但会产生如下报错:
1 | 10-28 03:52:04.564 ERROR [com.jeesite.common.config.Global ] - Update classpath:config/application.yml shiro.rememberMe.secretKey failure. |
流水线的构建已大致完成,先不要着急运行,jeesite需要初始化数据库。
- 通过kubectl exec命令或在kubesphere中进入mysql容器,在/etc/mysql/my.cnf中添加如下配置:
1 | [mysqld] |
- mysql -uroot -p 进入mysql后,创建用户和授权:
1 | set global read_only=0; |
- 由于执行init-data.sh脚本需要源代码以及配置maven和java环境,因此本步骤在云ide code-server中完成。git clone下项目源码后,修改web/src/main/resources/config/application.yml中的jdbc配置,然后cd到jeesite4/web/bin目录下执行sh init-date.sh
数据库初始化完毕后,若上述所有配置得当,则可以运行流水线了。若流水线运行成功,且jeesite容器正常运行,则可以通过域名(或nodeport)对其进行访问。访问成功页面如下。
使用Webhook触发流水线
- jenkins配置
30180端口打开jenkins页面(默认账号密码:admin / P@88w0rd),进入系统管理-插件管理,点击可选插件,搜索并安装下列未装插件:Git Plugin、SSH Plugin、URL Trigger Plugin、Gerrit Trigger、Gitlab Hook Plugin、Gitlab Merge Request Builder、GitLab Plugin。然后重启jenkins(your-host:30180/restart)。待重启完毕,进入jeesite对应的流水线,点击配置-构建触发器,选中Build when a change is pushed to GitLab…,复制红框中的链接。
点击高级-Generate,生成secret token,复制token,然后保存设置。
- gitlab配置
点击扳手图标进入admin area,再点击settings-network,确保outbound requests下两选项为选中状态。
进入jeesite4项目,点击settings-webhooks,在URL和Secret Token中输入上步复制的对应值。若复制过来的URL不是ip形式,则将jenkins.devops.kubesphere.local部分替换为节点ip。添加完成后,点击teset-push events,可模拟一次push events事件。若顺利,页面会出现Hook executed successfully: HTTP 200消息,刷新kubesphere jeesite流水线页面,有新的活动运行。
为测试实际效果,在gitlab中修改web/src/main/resources/config/application.yml,将productName设置为JeeSite,提交修改后,流水线自动运行。待部署完毕,访问jeesite,发现“Demo”已消失。