Browse Source

修改docker配置

zq940222 2 months ago
parent
commit
b33a9c03ca
5 changed files with 442 additions and 95 deletions
  1. 188 80
      Jenkinsfile
  2. 100 0
      Jenkinsfile-copy
  3. 35 0
      docker/Dockerfile
  4. 0 15
      gateway/Dockerfile
  5. 119 0
      ssh-publish.sh

+ 188 - 80
Jenkinsfile

@@ -1,100 +1,208 @@
-pipeline {
-    agent any
+// ==================== ↓↓↓↓↓↓ docker ↓↓↓↓↓↓ ====================
+// 镜像仓库地址
+def DOCKER_REGISTRY_URL = "registry.cn-shanghai.aliyuncs.com"
+// 镜像仓库命名空间名称
+def DOCKER_REGISTRY_NAMESPACE = "advich-group"
+// 镜像拉取凭证 => jenkins全局凭证中配置
+def DOCKER_REGISTRY_AUTH = "aliyun_docker_registry"
 
-    tools {
-        maven 'Maven-3.8.5'
-        jdk 'JDK8'
-    }
 
-    parameters {
-        choice(name: 'ENV', choices: ['prod'], description: '部署环境')
-        choice(name: 'SERVICE', choices: ['gateway', 'work', 'oa', 'authorization', 'admin', 'bi', 'crm', 'job', 'examine', 'hrm'], description: '选择要部署的微服务')
+// ==================== ↓↓↓↓↓↓ git ↓↓↓↓↓↓ ====================
+// git凭证 => jenkins全局凭证中配置
+def GIT_AUTH = "git_auth"
+
+
+// ==================== ↓↓↓↓↓↓ project ↓↓↓↓↓↓ ====================
+// 项目-git地址
+def PROJECT_GIT_URL = "https://git.dev.advichcloud.com/wangfan/weichi-crm-server.git"
+// 项目-公共模块名称
+def PROJECT_SERVICE_COMMON_NAME = "core"
+// 项目-基础目录
+def PROJECT_BASE_HOME = "/home/app/weichi-crm-server"
+// 项目-服务日志目录
+def PROJECT_SERVICE_LOG_HOME = "${PROJECT_BASE_HOME}/logs"
+// 项目-jar文件目录
+def PROJECT_JAR_HOME = "${PROJECT_BASE_HOME}/target"
+// 项目-docker部署的历史jar目录
+def PROJECT_DOCKER_HISTORY_JAR_HOME = "${PROJECT_BASE_HOME}/docker-history-jar"
+
+
+node {
+    // jenkins工作空间
+    def JENKINS_WORKSPACE = "${WORKSPACE}"
+    // 取哪一块网卡值
+    def ETH_VALUE = ""
+    // 当前时间
+    def CURRENT_TIME = ""
+    // 获取选择的项目服务名称
+    def PROJECT_SERVICE_NAME_SELECT = "${PROJECT_SERVICE_NAME}".split(",")
+    // 获取选择的服务器名称
+    def PUBLISH_SSH_SERVER_SELECT = "${PUBLISH_SSH_SERVER}".split(",")
+    // git分支tag
+    def GIT_BRANCH_TAG = ""
+    // docker镜像仓库认证命令
+    def DOCKER_REGISTRY_AUTH_CMD = ""
+
+    stage('初始化准备') {
+        echo '****************************** 初始化准备 ******************************'
+        // 网卡值设置 [注:正常liunx取eth0的内网ip,局域网取enp5s0的内网ip]
+        ETH_VALUE = sh(script: "( [[ \"${JAVA_OPTS}\" = *'-Dspring.cloud.nacos.discovery.ip'* ]] && echo enp5s0 || echo eth0 )", returnStdout: true).trim()
+        CURRENT_TIME = sh(script: "echo `date +\"%Y-%m-%d %H:%M:%S\"`", returnStdout: true).trim()
+        script {
+            GIT_BRANCH_TAG = GIT_BRANCH.replaceAll('origin/', '')
+        }
+        echo "当前工作空间:${JENKINS_WORKSPACE}"
+        echo "使用分支:${GIT_BRANCH}"
+        echo "使用分支tag:${GIT_BRANCH_TAG}"
+        echo "使用网卡:${ETH_VALUE}"
+        echo "是否跳过构建,直接运行docker容器(tips:适用于之前已经进行过构建打包的情景):${IS_SKIP_BUILD}"
+        echo "当前时间:${CURRENT_TIME}"
+        sh "mkdir -p ${PROJECT_SERVICE_LOG_HOME}"
+        sh "mkdir -p ${PROJECT_JAR_HOME}"
+        sh "mkdir -p ${PROJECT_DOCKER_HISTORY_JAR_HOME}"
+
+        echo '****************************** 镜像仓库认证 ******************************'
+
+        withCredentials([usernamePassword(credentialsId: "${DOCKER_REGISTRY_AUTH}", passwordVariable: 'password', usernameVariable: 'username')]) {
+            // 登录镜像仓库
+            DOCKER_REGISTRY_AUTH_CMD = "docker login -u ${username} -p ${password} ${DOCKER_REGISTRY_URL}"
+            sh "${DOCKER_REGISTRY_AUTH_CMD}"
+        }
     }
-    environment {
-        DOCKER_REGISTRY = "registry.cn-shanghai.aliyuncs.com"
-        DOCKER_NAMESPACE = "advich-group"
-        DOCKER_REPO = "weichi-crm-${params.SERVICE}"
-        DOCKER_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/${DOCKER_REPO}:latest"
-        PROJECT_SERVICE_COMMON_NAME = "core"
+
+
+    stage('拉取代码') {
+        echo '****************************** 拉取代码 ******************************'
+        checkout([$class: 'GitSCM', branches: [[name: "${GIT_BRANCH}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${GIT_AUTH}", url: "${PROJECT_GIT_URL}"]]])
+        sh "pwd"
     }
 
-    stages {
-        stage('拉取Git代码') {
-            steps {
-                checkout scmGit(branches: [[name: '${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'fb3553e7-6ea6-4f34-92a0-6ba34a71c5b5', url: 'https://git.dev.advichcloud.com/wangfan/weichi-crm-server.git']])
-            }
-        }
 
-        stage('公共工程打包') {
-            steps {
-                script {
-                    echo '****************************** 公共工程打包 ******************************'
-                    sh """
-                        mvn -f ${PROJECT_SERVICE_COMMON_NAME} clean install -Dmaven.test.skip=true
-                    """
-                }
-            }
+    stage('公共工程打包') {
+        if ("${IS_SKIP_BUILD}" == "true") {
+            echo '****************************** 公共工程打包 - 跳过 ******************************'
+        } else {
+            echo '****************************** 公共工程打包 ******************************'
+            sh "mvn -f ${PROJECT_SERVICE_COMMON_NAME} clean install -Dmaven.test.skip=true"
         }
+    }
+
+    stage('微服务打包&删除旧容器和镜像&推送镜像&部署远程服务器') {
+        echo '****************************** 微服务打包&删除旧容器和镜像&推送镜像&部署远程服务器 ******************************'
+
+        for (int i = 0; i < PROJECT_SERVICE_NAME_SELECT.length; i++) {
+
+            // 当前待处理项目
+            def current_app_name = PROJECT_SERVICE_NAME_SELECT[i];
+            def current_app_jar = "${current_app_name}.jar";
+            // 父工程
+            def current_app_parent = ""
+            // 端口号
+            def current_app_port = ""
+
+            echo "当前操作项目: ${current_app_name}"
 
-        stage('微服务工程打包') {
-            steps {
-                script {
-                    echo '****************************** 微服务工程打包 ******************************'
-                    sh "mvn -f ${params.SERVICE} clean install -Dmaven.test.skip=true"
+            script {
+                switch (current_app_name) {
+                    case "admin":
+                        current_app_parent = ""
+                        current_app_port = "60667"
+                        break
+                    case "gateway":
+                        current_app_port = "8443"
+                        current_app_parent = ""
+                        break
                 }
             }
-        }
 
-        stage('Build and Push Docker Image') {
-            steps {
-                script {
-                    withCredentials([usernamePassword(
-                        credentialsId: '6ec7fc8d-859f-43ba-8ebc-337bedec055b',
-                        usernameVariable: 'REGISTRY_USERNAME',
-                        passwordVariable: 'REGISTRY_PASSWORD'
-                    )]) {
-                        sh """
-                            cd ${params.SERVICE}
-                            echo "\${REGISTRY_PASSWORD}" | docker login ${DOCKER_REGISTRY} -u \${REGISTRY_USERNAME} --password-stdin
-                            docker build -t ${DOCKER_IMAGE} .
-                            docker push ${DOCKER_IMAGE}
-                        """
-                    }
-                }
+            echo "当前操作项目: ${current_app_name} 端口:${current_app_port}"
+
+
+            if ("${IS_SKIP_BUILD}" != "true") {
+                sh "mvn -f ${current_app_parent}/${current_app_name} clean install -Dmaven.test.skip=true"
+
+                sh "cp ${current_app_parent}/${current_app_name}/target/${current_app_jar} ${JENKINS_WORKSPACE}/docker"
             }
-        }
 
-        stage('Deploy to Server') {
-            when {
-                expression { return params.ENV == 'prod' }
+            // app镜像
+            def app_docker_image_name = "weichi-crm-${current_app_name}"
+//             def app_docker_image_tag = "${current_app_name}_${GIT_BRANCH_TAG}"
+            def app_docker_image_tag = "latest"
+            def app_docker_image = "${DOCKER_REGISTRY_URL}/${DOCKER_REGISTRY_NAMESPACE}/${app_docker_image_name}:${app_docker_image_tag}"
+
+            echo "app镜像: ${app_docker_image}"
+
+            if ("${IS_SKIP_BUILD}" != "true") {
+                // 删除旧容器
+                sh "docker ps -a | grep ${app_docker_image_name} | grep ${app_docker_image_tag} | awk '{print \$1}' | xargs -I docker stop {} | xargs -I docker rm {}"
+                // 删除旧镜像
+                sh "docker images | grep -E ${app_docker_image_name} | grep ${app_docker_image_tag}| awk '{print \$3}' | uniq | xargs -I {} docker rmi --force {}"
+                // 构建新镜像 -f:指定Dockerfile文件路径
+                sh "cd ${JENKINS_WORKSPACE}/docker && docker build -f Dockerfile --build-arg JAVA_OPTS=\"${JAVA_OPTS}\" --build-arg APP_NAME=${current_app_name} --build-arg APP_PORT=${current_app_port} -t ${app_docker_image} . --no-cache"
+
+
+                echo '****************************** 推送镜像 ******************************'
+
+                // 推送镜像
+                sh "docker push ${app_docker_image}"
+                sh "echo 镜像推送成功:${app_docker_image}"
+
+
+                // 操作完后移除docker目录下的jar文件,防止下次docker将多个jar一起构建导致镜像过大问题
+                sh "mv -f ${JENKINS_WORKSPACE}/docker/*.jar ${PROJECT_DOCKER_HISTORY_JAR_HOME}/"
             }
-            steps {
-                script {
-                    echo '****************************** 部署到服务器 ******************************'
-                    def DOCKER_REGISTRY = "${DOCKER_REGISTRY}"
-                    def DOCKER_NAMESPACE = "${DOCKER_NAMESPACE}"
-                    def DOCKER_REPO = "${DOCKER_REPO}"
-                    sshPublisher(publishers: [sshPublisherDesc(configName:'CRM(阿里云)', transfers: [sshTransfer(cleanRemote: false, excludes: '',
-                    execCommand: """
-                        docker login -u wangfan@1934160439855919 -p Initial0 ${DOCKER_REGISTRY}
-                        docker pull ${DOCKER_IMAGE}
-                        docker rm -f ${DOCKER_REPO} || true
-                        docker run -d --name ${DOCKER_REPO} ${DOCKER_IMAGE}
-                    """,
-                    execTimeout: 120000, flatten: false, makeEmptyDirs: false,
-                    noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
-                    remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
-                    usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose:
-                    false)])
+
+            if ("${PUBLISH_SSH_SERVER_SELECT}" != "[]") {
+                echo '****************************** 项目部署 ******************************'
+                // 遍历所有服务器,分别部署
+                for (int j = 0; j < PUBLISH_SSH_SERVER_SELECT.length; j++) {
+                    // 获取当前服务器名称
+                    def currentServerName = PUBLISH_SSH_SERVER_SELECT[j]
+                    echo '开始发布远程机器'
+                    sshPublisher(publishers: [sshPublisherDesc(
+                            // `Manage Jenkins` -> `Configure System` -> `Publish over SSH` -> `SSH Servers` 中的name值
+                            configName: "${currentServerName}",
+                            transfers: [sshTransfer(cleanRemote: false, excludes: '',
+                                    // ===================== ↓↓↓↓↓↓ 执行命令 ↓↓↓↓↓↓ =====================
+                                    execCommand: """
+
+                                    // 传输部署脚本到远程服务器之后,执行该脚本运行程序
+
+                                    cd ${PROJECT_SERVICE_LOG_HOME}
+
+                                    // 传输脚本参数时请使用双引号包裹单个参数值,避免单个参数中存在空格等特殊符号被解析为多个参数!
+                                    sh ssh-publish.sh \
+                                    "${DOCKER_REGISTRY_AUTH_CMD}" \
+                                    "${PROJECT_SERVICE_LOG_HOME}" \
+                                    "${current_app_name}" \
+                                    "${app_docker_image_name}" \
+                                    "${app_docker_image_tag}" \
+                                    "${app_docker_image}" \
+                                    "${ETH_VALUE}" \
+                                    "${current_app_port}" \
+                                    "${JAVA_OPTS}"
+
+                                """,
+                                    // 超时时间1000ms*60*2=2分钟
+                                    execTimeout: 120000,
+                                    flatten: false, makeEmptyDirs: false, noDefaultExcludes: false,
+                                    patternSeparator: '[, ]+',
+                                    // ===================== ↓↓↓↓↓↓ 传输文件 ↓↓↓↓↓↓ =====================
+                                    // 传输文件
+                                    sourceFiles: 'ssh-publish.sh',
+                                    // 远程服务器目录
+                                    remoteDirectory: "${PROJECT_SERVICE_LOG_HOME}",
+                                    remoteDirectorySDF: false,
+                                    // 传输时移除前缀路径
+                                    removePrefix: '')],
+                            usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                 }
+            } else {
+                echo '****************************** 项目不部署 ******************************'
             }
-        }
 
-        stage('Clean Workspace') {
-            steps {
-                cleanWs()
-            }
         }
 
     }
-}
+
+}

+ 100 - 0
Jenkinsfile-copy

@@ -0,0 +1,100 @@
+pipeline {
+    agent any
+
+    tools {
+        maven 'Maven-3.8.5'
+        jdk 'JDK8'
+    }
+
+    parameters {
+        choice(name: 'ENV', choices: ['prod'], description: '部署环境')
+        choice(name: 'SERVICE', choices: ['gateway', 'work', 'oa', 'authorization', 'admin', 'bi', 'crm', 'job', 'examine', 'hrm'], description: '选择要部署的微服务')
+    }
+    environment {
+        DOCKER_REGISTRY = "registry.cn-shanghai.aliyuncs.com"
+        DOCKER_NAMESPACE = "advich-group"
+        DOCKER_REPO = "weichi-crm-${params.SERVICE}"
+        DOCKER_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/${DOCKER_REPO}:latest"
+        PROJECT_SERVICE_COMMON_NAME = "core"
+    }
+
+    stages {
+        stage('拉取Git代码') {
+            steps {
+                checkout scmGit(branches: [[name: '${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'fb3553e7-6ea6-4f34-92a0-6ba34a71c5b5', url: 'https://git.dev.advichcloud.com/wangfan/weichi-crm-server.git']])
+            }
+        }
+
+        stage('公共工程打包') {
+            steps {
+                script {
+                    echo '****************************** 公共工程打包 ******************************'
+                    sh """
+                        mvn -f ${PROJECT_SERVICE_COMMON_NAME} clean install -Dmaven.test.skip=true
+                    """
+                }
+            }
+        }
+
+        stage('微服务工程打包') {
+            steps {
+                script {
+                    echo '****************************** 微服务工程打包 ******************************'
+                    sh "mvn -f ${params.SERVICE} clean install -Dmaven.test.skip=true"
+                }
+            }
+        }
+
+        stage('Build and Push Docker Image') {
+            steps {
+                script {
+                    withCredentials([usernamePassword(
+                        credentialsId: '6ec7fc8d-859f-43ba-8ebc-337bedec055b',
+                        usernameVariable: 'REGISTRY_USERNAME',
+                        passwordVariable: 'REGISTRY_PASSWORD'
+                    )]) {
+                        sh """
+                            cd ${params.SERVICE}
+                            echo "\${REGISTRY_PASSWORD}" | docker login ${DOCKER_REGISTRY} -u \${REGISTRY_USERNAME} --password-stdin
+                            docker build -t ${DOCKER_IMAGE} .
+                            docker push ${DOCKER_IMAGE}
+                        """
+                    }
+                }
+            }
+        }
+
+        stage('Deploy to Server') {
+            when {
+                expression { return params.ENV == 'prod' }
+            }
+            steps {
+                script {
+                    echo '****************************** 部署到服务器 ******************************'
+                    def DOCKER_REGISTRY = "${DOCKER_REGISTRY}"
+                    def DOCKER_NAMESPACE = "${DOCKER_NAMESPACE}"
+                    def DOCKER_REPO = "${DOCKER_REPO}"
+                    sshPublisher(publishers: [sshPublisherDesc(configName:'CRM(阿里云)', transfers: [sshTransfer(cleanRemote: false, excludes: '',
+                    execCommand: """
+                        docker login -u wangfan@1934160439855919 -p Initial0 ${DOCKER_REGISTRY}
+                        docker pull ${DOCKER_IMAGE}
+                        docker rm -f ${DOCKER_REPO} || true
+                        docker run -d --name ${DOCKER_REPO} ${DOCKER_IMAGE}
+                    """,
+                    execTimeout: 120000, flatten: false, makeEmptyDirs: false,
+                    noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
+                    remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
+                    usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose:
+                    false)])
+                }
+            }
+        }
+
+        stage('Clean Workspace') {
+            steps {
+                cleanWs()
+            }
+        }
+
+    }
+}

+ 35 - 0
docker/Dockerfile

@@ -0,0 +1,35 @@
+# 使用自制jdk
+FROM registry.cn-hangzhou.aliyuncs.com/zhengqing/openjdk:8-jdk-alpine
+
+# 维护者信息
+MAINTAINER Zenas
+
+# 构建镜像时传参数据
+ARG APP_NAME
+ARG APP_PORT
+ARG JAVA_OPTS
+
+# 设置环境变量-运行时也可传参进来耍哈
+ENV APP_NAME ${APP_NAME}
+ENV APP_JAR ${APP_NAME}.jar
+ENV APP_PORT ${APP_PORT}
+ENV JAVA_OPTS ${JAVA_OPTS}
+# -XX:+UseG1GC -Xms64m -Xmx64m -Xmn16m -XX:MetaspaceSize=100m -XX:MaxMetaspaceSize=100m -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -Ddefault.client.encoding=UTF-8 -Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Dspring.profiles.active=xx -Dspring.cloud.nacos.discovery.server-addr=xx -Dspring.cloud.nacos.discovery.username=nacos  -Dspring.cloud.nacos.discovery.password=nacos
+# 远程调试参数: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5001
+
+# copy arthas
+COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
+
+# 添加jar包到容器中
+ADD ${APP_JAR} /home/
+RUN sh -c 'touch /'
+
+VOLUME /tmp
+
+# 对外暴漏的端口号
+# [注:EXPOSE指令只是声明容器运行时提供的服务端口,给读者看有哪些端口,在运行时只会开启程序自身的端口!!]
+EXPOSE ${APP_PORT}
+
+# 让你先休息3秒再开始运动吧🏃🏃🏃
+CMD ["sh", "-c", "echo \"****** 运行命令:java -jar ${JAVA_OPTS} /home/${APP_JAR}\"   &   java -jar ${JAVA_OPTS} /home/${APP_JAR}"]
+

+ 0 - 15
gateway/Dockerfile

@@ -1,15 +0,0 @@
-FROM registry.cn-hangzhou.aliyuncs.com/zhengqing/openjdk:8-jdk-alpine-font
-# 作者
-LABEL authors="Jack"
-
-# 创建目标目录
-ENV JAR_FILE=target/wk_gateway-0.0.1-SNAPSHOT.jar
-
-COPY ${JAR_FILE} weichi-crm-gateway.jar
-
-# 暴露微服务的端口
-EXPOSE 8443
-
-CMD echo "****** Start... " & \
-    echo "****** 运行命令:nohup java -jar weichi-crm-gateway.jar >> ./logs/weichi-crm-gateway.log 2>&1 &" & \
-    java -jar weichi-crm-gateway.jar

+ 119 - 0
ssh-publish.sh

@@ -0,0 +1,119 @@
+#!/bin/bash
+
+####################################
+# @description 远程服务器-部署脚本
+# @params $? => 代表上一个命令执行后的退出状态: 0->成功,1->失败
+# @example => sh ssh-publish.sh 参数值1 参数值2 参数值n ...
+# @author Zenas
+# @date 2025/01/23
+####################################
+
+# 在执行过程中若遇到使用了未定义的变量或命令返回值为非零,将直接报错退出
+set -eu
+
+# 仅测试时期查看脚本传参使用
+echo ${*} >> /home/app/weichi-crm-server/logs/run.log
+
+
+# 检查参数个数
+if [ "${#}" -ne 9 ]; then
+	echo "脚本参数不合法,程序终止!"
+	exit
+fi
+
+
+# 当前时间
+CURRENT_TIME=`date +"%Y-%m-%d %H:%M:%S"`
+
+# 执行脚本时传过来的参数
+DOCKER_REGISTRY_AUTH_CMD=${1}
+PROJECT_SERVICE_LOG_HOME=${2}
+current_app_name=${3}
+app_docker_image_name=${4}
+app_docker_image_tag=${5}
+app_docker_image=${6}
+ETH_VALUE=${7}
+current_app_port=${8}
+JAVA_OPTS=${9}
+
+# 本机内网ip
+INET_IP=`ifconfig ${ETH_VALUE} | grep inet | grep -v inet6 | awk '{print $2}'`
+
+
+# 远程服务器下依次执行如下命令
+
+# ----------------------------------------------------------------------------------------------------------------------
+# 初始化
+function init() {
+  # 镜像仓库认证
+  ${DOCKER_REGISTRY_AUTH_CMD}
+
+  # 创建日志文件
+  mkdir -p ${PROJECT_SERVICE_LOG_HOME}
+  cd ${PROJECT_SERVICE_LOG_HOME}
+  touch ${current_app_name}.log
+}
+init
+
+# ----------------------------------------------------------------------------------------------------------------------
+# 判断当前端口是否被占用,没被占用返回0,反之1
+function Listening {
+   TCPListeningnum=`netstat -an | grep ":$1 " | awk '$1 == "tcp" && $NF == "LISTEN" {print $0}' | wc -l`
+   UDPListeningnum=`netstat -an | grep ":$1 " | awk '$1 == "udp" && $NF == "0.0.0.0:*" {print $0}' | wc -l`
+   (( Listeningnum = TCPListeningnum + UDPListeningnum ))
+   if [ $Listeningnum == 0 ]; then
+       echo "0"
+   else
+       echo "1"
+   fi
+}
+
+# 获取随机端口
+function get_random_port {
+  # 随机端口值
+  random_port=0
+  temp_num=0
+  while [ ${random_port} == 0 ]; do
+     # 指定区间随机数
+     temp_num=`shuf -i ${1}-${2} -n1`
+  #       echo "temp_num=${temp_num}"
+     if [ `Listening ${temp_num}` == 0 ] ; then
+        random_port=${temp_num}
+     fi
+  done
+  echo "${random_port}"
+}
+
+# 获取sentinel随机端口
+SENTINEL_PORT=`get_random_port 30100 30200`
+echo "${CURRENT_TIME} sentinel随机端口号: ${SENTINEL_PORT}" >> ${PROJECT_SERVICE_LOG_HOME}/run.log
+
+# ----------------------------------------------------------------------------------------------------------------------
+# 运行程序
+function run() {
+
+  # 删除旧容器
+  docker ps -a | grep ${app_docker_image_name} | grep ${app_docker_image_tag} | awk '{print $1}' | xargs -i docker stop {} | xargs -i docker rm {}
+
+  # 删除旧镜像
+  docker images | grep -E ${app_docker_image_name} | grep ${app_docker_image_tag}| awk '{print $3}' | uniq | xargs -I {} docker rmi --force {}
+
+  # 拉取新镜像
+  docker pull ${app_docker_image}
+
+  # 运行日志记录
+  echo "****** ${CURRENT_TIME} docker run -d -p ${current_app_port}:${current_app_port} -p ${SENTINEL_PORT}:${SENTINEL_PORT} \
+  -e JAVA_OPTS="${JAVA_OPTS} -Dspring.cloud.nacos.discovery.ip=${INET_IP} \
+  -Dspring.cloud.sentinel.transport.client-ip=${INET_IP} -Dspring.cloud.sentinel.transport.port=${SENTINEL_PORT}" \
+  -v ${PROJECT_SERVICE_LOG_HOME}/${current_app_name}.log:/home/${current_app_name}.log \
+  --name ${current_app_name} ${app_docker_image}" >> ${PROJECT_SERVICE_LOG_HOME}/run.log
+
+  # 运行
+  docker run -d -p ${current_app_port}:${current_app_port} -p ${SENTINEL_PORT}:${SENTINEL_PORT} \
+  -e JAVA_OPTS="${JAVA_OPTS} -Dspring.cloud.nacos.discovery.ip=${INET_IP} \
+  -Dspring.cloud.sentinel.transport.client-ip=${INET_IP} -Dspring.cloud.sentinel.transport.port=${SENTINEL_PORT}" \
+  -v ${PROJECT_SERVICE_LOG_HOME}/${current_app_name}.log:/home/${current_app_name}.log \
+  --name ${current_app_name} ${app_docker_image}
+
+}
+run