kuboard部署java项目(自动版)

常见问题

  1. 当一个镜像用于两个服务时,通过latest标签,只会更新成功一个,因此修改为指定版本号进行更新。

    分析:1. sh脚本'''三个单引号不支持环境变量,修改为三个双引号"""才支持。

    ​ 2. 相同镜像,两个服务通过重启,怀疑其中一个镜像还没拉取完但是检测到镜像版本已经是最新的了,因为另一个已经在执行了,就直接重启了。

    1
    2
    3
    4
    5
    6
    7
    sh """#!/bin/bash    
    curl -X PUT \
    -H "content-type: application/json" \
    -H "Cookie: KuboardUsername=admin; KuboardAccessKey=4xx" \
    -d '{"kind":"deployments","namespace":"base","name":"dev-system-business","images":{"harbor/business":"harbor/business:${env.gitlabMergeRequestTitle}"}}' \
    "http://172.1.1.44/kuboard-api/cluster/kubernates/kind/CICDApi/admin/resource/updateImageTag"
    """

环境信息:

软件 版本
Kubernetes 1.26.4
Kuboard 3.5.2.4
Jenkins 2.375.1
Harbor 2.0
Gitlab 10.0.0

后端

基础架构:

graph LR
A[gitlab合并] -->|通知| B(Jenkins编译)
B -->|1.push| D[harbor]
B -->|2.执行| E[kuboard重启项目负载]
D -->|完成后| E

详细步骤:

配置gitlab的webhook
  1. 点击项目Settings-->Integrations
  2. 输入URL,勾选jenkins里面的``Build when a change is pushed to GitLab. GitLab webhook URL: 可以拿到地址,eg: URL为http://172.1.1.24:8080/project/xxxdemo`
  3. 输入SecretToken,SecretToken为jenkins项目的Configure-->General-->Secret token-->generate生产的token,eg:035311df1e0bbedf1c1efb0cb5f5a630
  4. 只勾选Trigger触发方式Merge Request events,关闭其他包括SSL
  5. 点击Add webhook
配置Jenkins的configure
  1. 点击jenkins项目的configure-->General-->Build Triggers

  2. 勾选Build when a change is pushed to GitLab. GitLab webhook URL: http://172.1.1.24:8080/project/xxxdemo

    子集勾选:Accepted Merge Request Events

    Approved Merge Requests(EE-only)

    点击Advanced...

    其他不变,点击Generate生成Secret token

  3. 在Pipeline Script一栏,输入script脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    pipeline {
    agent any
    tools {
    jdk 'jdk8'
    dockerTool 'docker'
    }
    environment {
    GITLAB_API_URL = 'http://172.1.1.2:9999/api/v4'
    GITLAB_PROJECT_ID = '138'
    GITLAB_PRIVATE_TOKEN = 'Ny9ywkxxggjo9CwfuWMz'

    DOCKER_REGISTRY = 'harbor.exxktech.dev'
    DOCKER_REGISTRY_URL = 'http://harbor.exxktech.dev'
    DOCKER_REGISTRY_CREDENTIALS = 'c7da3fce-7e0c-415e-a684-e49e17560120'
    DOCKERFILE_PATH = 'src/main/docker'

    projectVersion = ''
    projectName = ''
    projectVersion1 = ''
    projectName1 = ''

    }
    stages {
    stage('Checkout') {
    steps {
    git branch: 'release',
    credentialsId: '123456',
    url: 'http://172.1.1.2:9999/exxk_backend_project/exxk_center.git'
    }
    }

    stage('maven build') {
    steps {
    script {
    sh 'mvn -Dmaven.test.failure.ignore=true clean install'
    }
    }
    }

    stage('multi build') {
    parallel {
    //项目一
    stage('exxk_center_manager') {
    stages {
    stage('docker build') {
    steps {
    dir('exxk_center_manager') {
    script {
    projectVersion = sh(script: 'mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim()
    projectName = sh(script: 'mvn -f pom.xml help:evaluate -Dexpression=project.artifactId -q -DforceStdout', returnStdout: true).trim()
    // 执行Maven构建
    sh 'mvn -Dmaven.test.failure.ignore=true clean package dockerfile:build'
    }
    }
    }
    }
    stage('Docker tags') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName}:${projectVersion}")
    dockerImage.tag("${env.gitlabMergeRequestTitle}")
    }
    }
    }
    stage('Push Docker Image') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName}:${env.gitlabMergeRequestTitle}")
    withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
    dockerImage.push()
    }
    }
    }
    }
    stage('Docker latest tags') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName}:${projectVersion}")
    dockerImage.tag("latest")
    }
    }
    }
    stage('Push latest Image') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName}:latest")
    withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
    dockerImage.push()
    }
    }
    }
    }
    }
    post {
    success {
    script {
    sh '''#!/bin/bash
    curl -X PUT \
    -H "Content-Type: application/yaml" \
    -H "Cookie: KuboardUsername=admin; KuboardAccessKey=4ip7hrrs6ias.2npbn4kc546tdxb8ew58nsdyz37j7cby" \
    -d '{"kind":"deployments","namespace":"arts-center","name":"exxk-center-manager"}' \
    "http://172.1.1.44/kuboard-api/cluster/kubernates/kind/CICDApi/admin/resource/restartWorkload"
    '''
    }
    }
    }
    }
    //项目二
    stage('exxk_center_application') {
    stages {
    stage('docker build') {
    steps {
    dir('exxk_center_application') {
    script {
    projectVersion1 = sh(script: 'mvn -f pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout', returnStdout: true).trim()
    projectName1 = sh(script: 'mvn -f pom.xml help:evaluate -Dexpression=project.artifactId -q -DforceStdout', returnStdout: true).trim()
    // 执行Maven构建
    sh 'mvn -Dmaven.test.failure.ignore=true clean package dockerfile:build'
    }
    }
    }
    }
    stage('Docker tags') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName1}:${projectVersion1}")
    dockerImage.tag("${env.gitlabMergeRequestTitle}")
    }
    }
    }
    stage('Push Docker Image') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName1}:${env.gitlabMergeRequestTitle}")
    withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
    dockerImage.push()
    }
    }
    }
    }
    stage('Docker latest tags') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName1}:${projectVersion1}")
    dockerImage.tag("latest")
    }
    }
    }
    stage('Push latest Image') {
    steps {
    // 使用Docker插件构建和推送镜像
    script {
    def dockerImage = docker.image("${DOCKER_REGISTRY}/exxk_center/${projectName1}:latest")
    withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
    dockerImage.push()
    }
    }
    }
    }
    }
    post {
    success {
    script {
    sh '''#!/bin/bash
    curl -X PUT \
    -H "Content-Type: application/yaml" \
    -H "Cookie: KuboardUsername=admin; KuboardAccessKey=4ip7hrrs6ias.xxxbn4kc546tdxb8ew58nsdyz37j7cby" \
    -d '{"kind":"deployments","namespace":"arts-center","name":"exxk-center-application"}' \
    "http://172.1.1.44/kuboard-api/cluster/kubernates/kind/CICDApi/admin/resource/restartWorkload"
    '''
    }
    }
    }
    }
    }
    }
    }
    }

    java项目配置

    文件结构

    1
    2
    3
    4
    5
    6
    7
    |-parent
    |-demo1
    |-src\main\docker\Dockerfile
    |-pom.xml
    |-demo2
    |-src\main\docker\Dockerfile
    |-pom.xml

    Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    FROM harbor.exxktech.dev/base/java8:1.0.0

    ARG JAR_FILE
    ADD target/${JAR_FILE}.jar app.jar


    ENV JAVA_OPTS -Xms128m -Xmx256m
    ENV BOOT_PARAMS ""

    EXPOSE 8080

    ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS $JAVA_OPTS_AGENT -Djava.security.egd=file:/dev/./urandom -jar app.jar $BOOT_PARAMS" ]

    pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.4.13</version>
    <executions>
    <execution>
    <id>default</id>
    <phase>none</phase>
    </execution>
    <execution>
    <id>after-deploy</id>
    <phase>deploy</phase>
    <goals>
    <goal>build</goal>
    </goals>
    </execution>
    </executions>
    <configuration>
    <repository>harbor.exxktech.dev/exxk_center/${project.name}</repository>
    <tag>${project.version}</tag>
    <buildArgs>
    <JAR_FILE>${project.build.finalName}</JAR_FILE>
    </buildArgs>
    <dockerfile>src/main/docker/Dockerfile</dockerfile>
    </configuration>
    </plugin>

微前端

架构

graph LR
A[gitlab前端项目1合并] -->|通知| B(Jenkins编译)
c[gitlab前端项目2合并] -->|通知| B(Jenkins编译)
B -->|1.push| D[harbor]
B -->|2.执行| E[kuboard重启项目负载]
D -->|完成后| E

配置

jenkins

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
pipeline {
agent any
tools {
dockerTool 'docker'
}
environment {
GITLAB_API_URL = 'http://172.1.1.25:9999/api/v4'
GITLAB_PROJECT_ID = '115'
GITLAB_PRIVATE_TOKEN = 'Ny9ywk6zggjo9CwfuWMz'

DOCKER_REGISTRY = 'harbor.exxktech.dev'
DOCKER_REGISTRY_URL= 'http://harbor.exxktech.dev'
DOCKER_REGISTRY_CREDENTIALS = 'c7da3fce-7e2c-415e-a684-e49e17560120'

NGINX_IMAGE = "nginx:latest"
IMAGE_NAME = 'harbor.exxktech.dev/art/web-art-center-main'
NGINX_CONFIG = 'default.conf'
}
stages {
stage('GitLab Checkout') {
steps {
dir('main') {
checkout([$class: 'GitSCM', branches: [[name: '*/release']], userRemoteConfigs: [[url: 'http://172.1.1.25:9999/exxk_frontend_project/performing-arts-center-system.git',credentialsId: 'e7a93679-a7f5-411f-823f-c3c5f467549b']]])
}
dir('sub') {
checkout([$class: 'GitSCM', branches: [[name: '*/release']], userRemoteConfigs: [[url: 'http://172.1.1.25:9999/exxk_frontend_project/performing-arts-center-business.git',credentialsId: 'e7a93679-a7f5-411f-823f-c3c5f467549b']]])
}
}
}
stage('Build') {
steps {
sh 'mkdir -p main_dist'
sh 'mkdir -p sub_dist'
// 构建前端项目,需要根据项目结构和使用的构建工具进行修改
sh 'cd main && yarn install && yarn build'
sh 'cd sub && yarn install && yarn build'
}
}

stage('Copy to Workspace') {
steps {
script {
// Copy dist contents to workspace's out directory
sh 'cp -r main/dist/* main_dist/'
sh 'cp -r sub/child/business/* sub_dist/'
sh 'cp main/Dockerfile .'
sh 'cp main/default.conf .'
}
}
}


stage('Build Image') {
steps {
script {
def dockerImage = docker.build("${IMAGE_NAME}:${env.gitlabMergeRequestTitle}")
withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
dockerImage.push()
}
}
}
}

stage('Docker latest tags') {
steps {
// 使用Docker插件构建和推送镜像
script {
def dockerImage = docker.image("${IMAGE_NAME}:${env.gitlabMergeRequestTitle}")
dockerImage.tag("latest")
}
}
}
stage('Push latest Image') {
steps {
// 使用Docker插件构建和推送镜像
script {
def dockerImage = docker.image("${IMAGE_NAME}:latest")
withDockerRegistry(credentialsId: "${DOCKER_REGISTRY_CREDENTIALS}", toolName: 'docker', url: "${DOCKER_REGISTRY_URL}") {
dockerImage.push()
}
}
}

}

}
post {
success {
script {
sh '''#!/bin/bash
curl -X PUT \
-H "Content-Type: application/yaml" \
-H "Cookie: KuboardUsername=admin; KuboardAccessKey=4ip7hrrs6ias.2npbn4kc546tdxb8ew58nsdyz37j7cby" \
-d '{"kind":"deployments","namespace":"arts-center","name":"web-art-center"}' \
"http://172.1.1.44/kuboard-api/cluster/kubernates/kind/CICDApi/admin/resource/restartWorkload"
'''
}
}
}
}

Dockerfile

1
2
3
4
5
6
7
8
9
FROM nginx


RUN rm /etc/nginx/conf.d/default.conf

ADD default.conf /etc/nginx/conf.d/

COPY main_dist/ /usr/share/nginx/html/
COPY sub_dist/ /usr/share/nginx/html/child/busniess/

nginx default.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 后端接口代理地址
upstream api_server {
server deduction-center-manager:8555;
}
server {
listen 80;
server_name localhost;
underscores_in_headers on;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}

location /child/busniess {
root html;
index index.html index.htm;
#try_files $uri $uri/ /child/busniess/index.html;
}

location /manager/api/ {
rewrite ~/manager/api/(.*)$ /$1 break;
proxy_pass http://api_server/manager/api/;
proxy_set_header Host $host;
proxy_pass_request_headers on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 300;
proxy_send_timeout 300;
}


error_page 500 502 503 504 /50x.html;

location = /50x.html {
root html;
}
}