| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- properties([
- parameters([
- [$class: 'ChoiceParameter',
- choiceType: 'PT_SINGLE_SELECT',
- description: '选择要部署 API or UI',
- name: 'modulePrefix',
- randomName: 'choice-parameter-5631314439613978',
- script: [
- $class: 'GroovyScript',
- fallbackScript: [
- classpath: [],
- sandbox: true,
- script:
- 'return[\'Could not get Env\']'
- ],
- script: [
- classpath: [],
- sandbox: true,
- script:
- 'return["java"]'
- ]
- ]
- ],
- [$class: 'CascadeChoiceParameter',
- choiceType: 'PT_SINGLE_SELECT',
- description: '选择要部署的项目',
- name: 'module',
- randomName: 'choice-parameter-5631314456178619',
- referencedParameters: 'modulePrefix',
- script: [
- $class: 'GroovyScript',
- fallbackScript: [
- classpath: [],
- sandbox: true,
- script:
- 'return[\'Could not get Environment from Env Param\']'
- ],
- script: [
- classpath: [],
- sandbox: true,
- script:
- 'return["storlead-mail-api"]'
- ]
- ]
- ]
- ])
- ])
- pipeline {
- options {
- timestamps()
- }
- environment {
- GROUPID = readMavenPom().getGroupId()//com.storlead
- ARTIFACTID = readMavenPom().getArtifactId()//sp-project
- VERSION = readMavenPom().getVersion()//1.0
- }
- // 参数
- parameters {
- choice(
- name: 'profile',
- choices: ['test', 'prod','uat'],
- description: '选择要部署的配置文件'
- )
- }
- agent any
- stages {
- stage('处理参数') {
- steps {
- script {
- echo "处理参数"
- script {
- //服务器配置
- MODULE_PREFIX = "${params.modulePrefix}"
- SERVER_SSH_PORT = 53023
- SERVER_HOST = "node1.storlead.com"
- SWARM_INIT_REPLICAS_NUM = 1
- //服务配置
- API_PORT = 9200
- API_REMOTE_DEBUG_PORT = 9201
- API_NAMESPACE_RESTFUL = "${params.module}"
- //DOCKER配置
- DOCKER_REGISTRY = "reg-aliyun"
- DOCKER_HOST = "registry.cn-shenzhen.aliyuncs.com"
- //Docker私服登陆url https://registry-vpc.cn-shenzhen.aliyuncs.com
- DOCKER_LOGIN_REGISTRY = "https://${DOCKER_HOST}"
- BUILD_PREFIX = "storlead-huawei"
- //镜像完整名称 registry-vpc.cn-shenzhen.aliyuncs.com/storlead/sp-project-management-prod:1.0
- DOCKER_IMG_NAME = "${DOCKER_HOST}/${BUILD_PREFIX}/${params.module}-${params.profile}:${VERSION}"
- //镜像名 storlead/sp-project-management-prod:1.0
- IMG_NAME = "${BUILD_PREFIX}/${params.module}-${params.profile}:${VERSION}"
- PUSH_DOCK_IMG = true
- SERVER_HOST_NAME = "test1"
- echo "为指定 module 设定对应 服务器及端口"
- echo "处理 ${params.module} 项目"
- if (params.modulePrefix == "java") {
- echo "---- storelad-mail-api"
- script {
- if (params.profile == "test") {
- SWARM_INIT_REPLICAS_NUM = 1
- SERVER_HOST = "test1.storlead.com"
- API_PORT = 18060
- API_REMOTE_DEBUG_PORT = 18061
- SERVER_HOST_NAME = "test1"
- } else if (params.profile == "prod") {
- SERVER_HOST = "110.41.82.21"
- API_PORT = 18060
- API_REMOTE_DEBUG_PORT = 18061
- SERVER_HOST_NAME = "node1"
- }
- }
- } else if (params.modulePrefix == "ui") {
- script {
- if (params.profile == "test") {
- SERVER_HOST = "test1.storlead.com"
- } else if (params.profile == "prod") {
- SERVER_HOST = "110.41.82.21"
- }
- }
- }
- echo "处理MODULE_NAMESPACE_RESTFUL"
- // //把 module 名 从 sp-xxx 变成 xxx 也就是 项目 的 namespace
- //if (API_NAMESPACE_RESTFUL == "storlead-mail-api") {
- API_NAMESPACE_RESTFUL = "api"
- //}
- echo "处理镜像推送"
- }
- }
- }
- }
- // stage('Node 编译') {
- //
- // when {
- // environment name: 'modulePrefix', value: 'ui'
- // }
- // agent {
- // docker {
- // // image "registry-vpc.cn-shenzhen.aliyuncs.com/storlead/node:19-alpine"
- // image "node:20-alpine"
- // args '-v /app:/app/:z -v /etc/localtime:/etc/localtime:ro -u root'
- // reuseNode true
- // }
- // }
- // steps {
- // withCredentials([
- // usernamePassword(credentialsId: 'storleadHW', usernameVariable: 'usernameHW', passwordVariable: 'passwordHW'),
- // usernamePassword(credentialsId: 'storlead', usernameVariable: 'username', passwordVariable: 'password')
- // ]) {
- // script {
- // echo "发布 UI 代码"
- //
- // def remote = [:]
- // remote.allowAnyHosts = true
- // remote.name = "${SERVER_HOST}"
- // remote.host = "${SERVER_HOST}"
- // remote.port = 53023
- // remote.user = username
- // remote.password = password
- //
- // if (params.profile == "prod") {
- // remote.port = 22
- // remote.user = "root"
- // remote.user = usernameHW
- // remote.password = passwordHW
- // }
- // if(params.module == 'sp-user-mobile-center') {
- // sh """cd ${params.modulePrefix}/${params.module} && npm install && npm run build:${params.profile}"""
- // } else {
- // sh """cd ${params.modulePrefix}/${params.module} && npm install && npm run ${params.profile}"""
- // }
- //
- // // sh """cd ${params.modulePrefix}/${params.module} && npm run ${params.profile}"""
- //
- // sshCommand remote: remote, command: "mkdir -p /app/sp/ui/app-centre/${params.profile}/${params.module}"
- //
- // sshCommand remote: remote, command: "rm -rf /app/sp/ui/app-centre/${params.profile}/${params.module}/dist/*"
- //
- //
- // echo "/app/sp/ui/sales/${params.profile}/${params.module}/*"
- //
- // sshPut remote: remote, from: "${params.modulePrefix}/${params.module}/dist/", into: "/app/sp/ui/app-centre/${params.profile}/${params.module}/"
- //
- // echo "${params.modulePrefix}/${params.module}/dist/,/app/sp/ui/app-centre/${params.profile}/${params.module}/"
- //
- // sshCommand remote: remote, command: "cp -rf /app/sp/ui/app-centre/${params.profile}/${params.module}/dist/* /app/sp/ui/app-centre/${params.profile}/${params.module}/"
- // }
- // }
- // }
- // }
- stage('Maven 编译') {
- when {
- environment name: 'modulePrefix', value: 'java'
- }
- agent {
- docker {
- // 与 Temurin 17 一致(含 Maven);若本地无此镜像会自动拉取
- image 'maven:3-eclipse-temurin-17'
- //让docker 使用 host 宿主机的 m2仓库 使用root用户来运行 以让指定的~/.m2/config/setting.xml 阿里加速下载maven 依赖生效
- args '-v /app:/app:z -v $HOME/.m2:/root/.m2:z -u root'
- reuseNode true
- }
- }
- steps {
- echo "编译 API 代码"
- sh "mvn clean package -U -am -pl ${params.module} -P${params.profile} -Dmaven.test.skip=true"
- }
- }
- // 项目打包到镜像并推送到镜像仓库
- stage('构建Docker镜像') {
- when {
- environment name: 'modulePrefix', value: 'java'
- }
- steps {
- echo "构建Dcoker镜像-------------------"
- script {
- docker.withRegistry(DOCKER_LOGIN_REGISTRY, DOCKER_REGISTRY) {
- // 使用 Jenkins 节点已有的 eclipse-temurin:17
- BASE_IMAGE = 'eclipse-temurin:17'
- sh "docker pull ${BASE_IMAGE} || true"
- sh """
- echo '
- FROM ${BASE_IMAGE}
- COPY ${params.module}/target/${params.module}.jar app.jar
- EXPOSE ${API_PORT}
- EXPOSE ${API_REMOTE_DEBUG_PORT}
- HEALTHCHECK --interval=1m --timeout=10s CMD curl -f http://localhost:${API_PORT}/${API_NAMESPACE_RESTFUL}/actuator
- ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-Djava.awt.headless=true","-Dspring.profiles.active=${params.profile}", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:${API_REMOTE_DEBUG_PORT}","-jar","/app.jar"]' > Dockerfile
- docker build -t ${DOCKER_IMG_NAME} .
- """
- sh "docker push ${DOCKER_IMG_NAME}"
- }
- }
- }
- }
- stage('启动服务') {
- when {
- environment name: 'modulePrefix', value: 'java'
- }
- steps {
- withCredentials([
- usernamePassword(credentialsId: 'storleadHW', usernameVariable: 'usernameHW', passwordVariable: 'passwordHW'),
- usernamePassword(credentialsId: 'storlead', usernameVariable: 'username', passwordVariable: 'password'),
- usernamePassword(credentialsId: 'reg-aliyun', usernameVariable: 'aliUsername', passwordVariable: 'aliPassword')
- ]) {
- script {
- echo "启动服务"
- echo "${aliPassword}"
- echo "docker login -u ${aliUsername} -p ${aliPassword} ${DOCKER_LOGIN_REGISTRY}"
- def remote = [:]
- remote.name = "${SERVER_HOST}"
- remote.host = "${SERVER_HOST}"
- remote.port = 53023
- remote.user = username
- remote.password = password
- remote.allowAnyHosts = true
- //因为使用 docker swarm 发布 只能在 manage node 执行部署
- if (params.profile == "prod") {
- remote.port = 22
- remote.user = "root"
- remote.user = usernameHW
- remote.password = passwordHW
- }
- if (PUSH_DOCK_IMG) {
- //docker 认证
- sshCommand remote: remote, command: "docker login -u ${aliUsername} -p ${aliPassword} ${DOCKER_LOGIN_REGISTRY}"
- //如果选择推送才使用远程的版本 如果不选择推送到远程则直接运行本机刚打包的镜像版本即可
- sshCommand remote: remote, command: "docker pull ${DOCKER_IMG_NAME}"
- }
- // 勿用 echo '...' 写 yml:约束行里的单引号会截断 shell 字符串,导致 stack yml 损坏
- def stackFile = "${params.module}-${params.profile}-stack.yml"
- def stackYaml = """\
- version: "3.7"
- services:
- ${params.module}-${params.profile}:
- image: ${DOCKER_IMG_NAME}
- deploy:
- replicas: ${SWARM_INIT_REPLICAS_NUM}
- placement:
- constraints:
- - node.hostname == ${SERVER_HOST_NAME}
- resources:
- limits:
- memory: 2G
- reservations:
- memory: 512M
- update_config:
- parallelism: 1
- delay: 1m
- restart_policy:
- condition: on-failure
- max_attempts: 3
- healthcheck:
- test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:${API_PORT}/${API_NAMESPACE_RESTFUL}/actuator || exit 1"]
- interval: 1m
- timeout: 5s
- retries: 3
- start_period: 30s
- environment:
- - TZ=Asia/Shanghai
- - SPRING_PROFILES_ACTIVE=${params.profile}
- - JAVA_OPTS=-Xms512m -Xmx1024m
- volumes:
- - /app:/app
- - /mnt/vdb/storlead:/mnt/vdb/storlead
- ports:
- - "${API_PORT}:${API_PORT}"
- - "${API_REMOTE_DEBUG_PORT}:${API_REMOTE_DEBUG_PORT}"
- networks:
- - ${ARTIFACTID}
- extra_hosts:
- - "www.storlead.com:172.18.194.161"
- - "node1:110.41.82.21"
- - "node2:110.41.174.46"
- - "node3:121.37.226.174"
- - "test1.storlead.com:172.18.194.168"
- - "test2.storlead.com:172.18.194.163"
- networks:
- ${ARTIFACTID}:
- driver: overlay
- external: true
- """
- writeFile file: stackFile, text: stackYaml
- echo "----- stack yml -----"
- sh "cat ${stackFile}"
- // 全部都以swarm 模式启动;external 网络不存在时先创建
- sshCommand remote: remote, command: "mkdir -p /docker/sp"
- sshCommand remote: remote, command: "docker network inspect ${ARTIFACTID} >/dev/null 2>&1 || docker network create -d overlay --attachable ${ARTIFACTID}"
- sshPut remote: remote, from: stackFile, into: "/docker/sp/${stackFile}"
- sshCommand remote: remote, command: "docker stack deploy --resolve-image=always --with-registry-auth -c /docker/sp/${stackFile} ${params.module}-${params.profile}"
- }
- }
- }
- }
- }
- }
|