#!/usr/bin/env groovy import groovy.json.JsonSlurperClassic //properties(projectProperties) def jsonOption = new JsonSlurperClassic().parseText(params.modulesOption) echo "jsonOption ${jsonOption}" jsonOption.harbor = "harbor.sino-assist.com" jsonOption.deploy_server = "192.168.3.132" jsonOption.profile = "review" jsonOption.nacos_address = "review-nacos1:8848,review-nacos2:8848,review-nacos3:8848" jsonOption.namespace = "review" def branch = params.branch def DOCKER_CREDENTIAL_ID = 'harbor' def REGISTRY_URL = jsonOption.harbor def IMAGE_TAG = params.branch def deploy_modules = jsonOption.deploy_modules def deploy_server = jsonOption.deploy_server def deploy_step = jsonOption.deploy_step // 根据传入的部署模块配置build的内容 def deploy_project_names = "" for (module in deploy_modules) { if (module.o == true) { deploy_project_names += " ${module.module}:jib " } } node { def gradleHome = tool 'gradle' def gradle = "${gradleHome}/bin/gradle" stage('checkout') { git branch: branch, credentialsId: 'gitlab', url: 'https://git.sino-assist.com/server/sa-server.git' } stage('docker-build-push') { if (deploy_step.contains("打包镜像")) { withCredentials([usernamePassword(passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME', credentialsId: "${DOCKER_CREDENTIAL_ID}",)]) { sh "docker login $REGISTRY_URL -u '$DOCKER_USERNAME' -p '$DOCKER_PASSWORD'" } sh "$gradle $deploy_project_names -x test --parallel --build-cache -Pdocker_hub='$REGISTRY_URL' -Pdocker_version=$IMAGE_TAG -Djib.console=plain" } } if (deploy_step.contains("部署服务")) { stage('docker-deploy') { for (final module in deploy_modules) { if (module.o == true) { def modules = module.module.split(":") module.projectName = modules[modules.length - 1] module.imageTag = IMAGE_TAG echo "deploy module ${module.module}" def services = docker_service_param(module, jsonOption) echo "部署服务" for (final def svc in services) { String yml = makeYML(svc) String serverName = svc.get("serviceName") String ymlFile = "/data/swarm/${serverName}.yml" // 添加 SSH 选项: -o StrictHostKeyChecking=no 跳过 host key 检查 String deploy = "sshpass -p 'Sino.2025' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@${deploy_server} \" mkdir -p /data/swarm/ && echo '''${yml}''' > ${ymlFile} && docker stack deploy -c ${ymlFile} ${serverName} --prune --with-registry-auth\"" echo deploy sh deploy } } } } } } def makeYML(params) { return """ version: \\"3.8\\" services: svc: image: ${params.IMAGE} environment: - active_profile=${params.profile} - nacos_address=${params.nacos_address} - nacos_password=gkxl2024#@ - namespace=${params.namespace} - project_name=${params.projectName} - params=${params.params} - nativeIp=${params.nativeIp} - reservationsMemory=${params.reservationsMemory} - limitMemory=${params.limitMemory} - TZ=Asia/Shanghai ports: - '${params.port}:8080' healthcheck: test: \\"curl --fail --silent localhost:8080/actuator/health/ping | grep UP || exit 1\\" interval: 15s timeout: 5s retries: 20 volumes: - ${params.namespace}_logs:/logs logging: driver: json-file options: max-size: "1G" max-file: "3" extra_hosts: - "hostname:127.0.0.1" - "open.property.cic.cn:59.46.218.8" deploy: mode: replicated replicas: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 3 update_config: order: stop-first resources: limits: cpus: \\"${params.limitCpu}\\" memory: ${params.limitMemory} reservations: cpus: \\"${params.reservationsCpu}\\" memory: ${params.reservationsMemory} placement: constraints: - "node.hostname==${params.hostname}" networks: default: name: ${params.namespace} external: true volumes: ${params.namespace}_logs: external: true """ } // 转换内存格式:0.1G -> 102M, 0.5G -> 512M, 1G -> 1G def convertMemory(String mem) { if (mem == null || mem.trim().isEmpty()) { return "512M" } mem = mem.trim().toUpperCase() // 如果是小数G格式,转换为M if (mem.matches(/^\d+\.\d+G$/)) { def value = mem.replace("G", "").toDouble() def mbValue = (value * 1024).intValue() return "${mbValue}M" } return mem } def docker_service_param(module, jsonOption) { def ipHostnameMap = [ '192.168.3.132': 'ZD-BAK-APP2', '192.168.3.133': 'zd-bak-app3', '192.168.3.134': 'ZD-BAK-APP1', ] def projectName = module.projectName def node = module.node def cpu = module.cpu.split("-") def memory = module.memory.split("-") // 转换内存格式,确保 Java 堆参数有效 def reservationsMemory = convertMemory(memory[0]) def limitMemory = convertMemory(memory[1]) def address = module.address.split("\n") def services = [] for (final def add in address) { def addSplit = add.split(":") def ip = addSplit[0] def port = addSplit[1] def hostname = ipHostnameMap.get(ip) def serviceName = """ss${ip.split("\\.")[3]}_${projectName}""" def par = """-Dspring.cloud.inetutils.preferredNetworks=10.18""" services.add([ nacos_address : jsonOption.nacos_address, namespace : jsonOption.namespace, projectName : projectName, IMAGE : "$jsonOption.harbor/sa-server/$projectName:$module.imageTag", profile : jsonOption.profile, node : node, // 副本数量 reservationsCpu : cpu[0], // 保留cpu limitCpu : cpu[1], // 最大cpu reservationsMemory: reservationsMemory, // 保留内存(已转换格式) limitMemory : limitMemory, // 最大内存(已转换格式) serviceName : serviceName, hostname : hostname, port : port, nativeIp : ip, params : par ]) } echo "params ${params}" return services } // vim: ft=groovy