Jenkinsfile 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /**
  2. * alien_py_cloud production deploy (repo root Jenkinsfile)
  3. * Jenkins: 39.106.135.88 | Target: 39.105.153.68 | Script Path: Jenkinsfile
  4. *
  5. * 容器均使用 --restart unless-stopped,ECS/宿主机重启后 Docker 会自动拉起。
  6. */
  7. def DEFAULT_PROD_SSH_TARGET = 'alien_store@39.105.153.68'
  8. def DEFAULT_PROD_SSH_CREDENTIALS_ID = 'e611a045-2fdc-4613-babd-a72d69bf9814'
  9. pipeline {
  10. agent any
  11. options {
  12. buildDiscarder(logRotator(numToKeepStr: '10'))
  13. timestamps()
  14. }
  15. parameters {
  16. string(name: 'PROD_SSH_TARGET', defaultValue: DEFAULT_PROD_SSH_TARGET,
  17. description: 'Production host SSH target')
  18. string(name: 'PROD_SSH_CREDENTIALS_ID', defaultValue: DEFAULT_PROD_SSH_CREDENTIALS_ID,
  19. description: 'Jenkins SSH Username with private key credential ID')
  20. string(name: 'GIT_BRANCH', defaultValue: 'produ',
  21. description: 'alien_py_cloud branch to deploy')
  22. }
  23. environment {
  24. CODE_DIR_REMOTE = '/alien_produ/python/alien_py_cloud'
  25. ENV_FILE_REMOTE = '/alien_produ/python/alien_py_cloud/.env.produ'
  26. LOG_ROOT_REMOTE = '/alien_produ/python/alien_py_cloud/logs'
  27. IMAGE_STORE = 'alien_store:local'
  28. IMAGE_GATEWAY = 'alien_gateway:local'
  29. IMAGE_CONTRACT = 'alien_contract:local'
  30. CONTAINER_NAME_STORE = 'py_esign_produ'
  31. CONTAINER_NAME_GATEWAY = 'py_gateway_produ'
  32. CONTAINER_NAME_CONTRACT = 'py_contract_produ'
  33. PORT_STORE_INTERNAL = '48001'
  34. PORT_GATEWAY_INTERNAL = '43333'
  35. PORT_CONTRACT_INTERNAL = '8002'
  36. PORT_GATEWAY_HOST = '33333'
  37. PORT_CONTRACT_HOST = '8002'
  38. DOCKER_NET = 'alien_net_produ'
  39. }
  40. stages {
  41. stage('Verify SSH') {
  42. steps {
  43. script {
  44. def sshTarget = (params.PROD_SSH_TARGET ?: DEFAULT_PROD_SSH_TARGET).trim()
  45. def credId = (params.PROD_SSH_CREDENTIALS_ID ?: DEFAULT_PROD_SSH_CREDENTIALS_ID).trim()
  46. env.SSH_TARGET = sshTarget
  47. env.SSH_CRED_ID = credId
  48. sshagent(credentials: [credId]) {
  49. sh """
  50. set -e
  51. ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${sshTarget}' \\
  52. 'test -f ${ENV_FILE_REMOTE} && sudo docker info >/dev/null'
  53. echo ">>> SSH OK: ${sshTarget}"
  54. """
  55. }
  56. }
  57. }
  58. }
  59. stage('Git Pull on Production') {
  60. steps {
  61. sshagent(credentials: [env.SSH_CRED_ID]) {
  62. sh """
  63. set -e
  64. ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
  65. set -e
  66. cd '${CODE_DIR_REMOTE}'
  67. if [ ! -d .git ]; then
  68. echo "ERROR: ${CODE_DIR_REMOTE} is not a git repo. Clone manually first."
  69. exit 1
  70. fi
  71. git fetch origin
  72. git checkout '${params.GIT_BRANCH}'
  73. git pull origin '${params.GIT_BRANCH}'
  74. echo ">>> git at \$(git rev-parse --short HEAD) on \$(hostname)"
  75. REMOTE_EOF
  76. """
  77. }
  78. }
  79. }
  80. stage('Build Images on Production') {
  81. steps {
  82. sshagent(credentials: [env.SSH_CRED_ID]) {
  83. sh """
  84. set -e
  85. ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
  86. set -e
  87. cd '${CODE_DIR_REMOTE}'
  88. sudo docker build -f alien_store/Dockerfile -t ${IMAGE_STORE} .
  89. sudo docker build -f alien_gateway/Dockerfile -t ${IMAGE_GATEWAY} .
  90. sudo docker build -f alien_contract/Dockerfile -t ${IMAGE_CONTRACT} .
  91. echo ">>> images built on \$(hostname)"
  92. sudo docker images | grep -E 'alien_store|alien_gateway|alien_contract' | head -10
  93. REMOTE_EOF
  94. """
  95. }
  96. }
  97. }
  98. stage('Deploy on Production') {
  99. steps {
  100. sshagent(credentials: [env.SSH_CRED_ID]) {
  101. sh """
  102. set -e
  103. ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
  104. set -e
  105. sudo docker network create ${DOCKER_NET} 2>/dev/null || true
  106. mkdir -p ${LOG_ROOT_REMOTE}/store ${LOG_ROOT_REMOTE}/gateway ${LOG_ROOT_REMOTE}/contract
  107. sudo docker rm -f ${CONTAINER_NAME_STORE} ${CONTAINER_NAME_GATEWAY} ${CONTAINER_NAME_CONTRACT} 2>/dev/null || true
  108. # legacy / previous container names (same host ports)
  109. sudo docker rm -f esign alien_gateway_py alien_contract_py \\
  110. alien_store_produ alien_gateway_produ alien_contract_produ 2>/dev/null || true
  111. wait_http() {
  112. url="\$1"
  113. label="\$2"
  114. cname="\$3"
  115. for i in \$(seq 1 30); do
  116. if curl -sf "\$url" >/dev/null 2>&1; then
  117. echo ">>> \$label OK: \$url"
  118. return 0
  119. fi
  120. sleep 2
  121. done
  122. echo ">>> \$label FAILED: \$url"
  123. if [ -n "\$cname" ]; then
  124. echo ">>> docker ps -a:"
  125. sudo docker ps -a --filter name="\$cname" || true
  126. echo ">>> docker logs --tail 100 \$cname:"
  127. sudo docker logs --tail 100 "\$cname" 2>&1 || true
  128. fi
  129. return 1
  130. }
  131. # 1) store(下游)
  132. sudo docker run -d --name ${CONTAINER_NAME_STORE} \\
  133. --network ${DOCKER_NET} \\
  134. --env-file ${ENV_FILE_REMOTE} \\
  135. -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
  136. -v ${LOG_ROOT_REMOTE}/store:/app/common/logs/alien_store \\
  137. -e APP_ENV=produ \\
  138. -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
  139. --restart unless-stopped \\
  140. ${IMAGE_STORE}
  141. # 2) contract(下游)
  142. sudo docker run -d --name ${CONTAINER_NAME_CONTRACT} \\
  143. --network ${DOCKER_NET} \\
  144. -p ${PORT_CONTRACT_HOST}:${PORT_CONTRACT_INTERNAL} \\
  145. --env-file ${ENV_FILE_REMOTE} \\
  146. -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
  147. -v ${LOG_ROOT_REMOTE}/contract:/app/common/logs/alien_contract \\
  148. -e APP_ENV=produ \\
  149. -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
  150. --restart unless-stopped \\
  151. ${IMAGE_CONTRACT}
  152. # 3) gateway(依赖 store/contract;对外 33333)
  153. sudo docker run -d --name ${CONTAINER_NAME_GATEWAY} \\
  154. --network ${DOCKER_NET} \\
  155. -p ${PORT_GATEWAY_HOST}:${PORT_GATEWAY_INTERNAL} \\
  156. --env-file ${ENV_FILE_REMOTE} \\
  157. -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
  158. -v ${LOG_ROOT_REMOTE}/gateway:/app/common/logs/alien_gateway \\
  159. -e APP_ENV=produ \\
  160. -e STORE_BASE_URL=http://${CONTAINER_NAME_STORE}:${PORT_STORE_INTERNAL} \\
  161. -e CONTRACT_BASE_URL=http://${CONTAINER_NAME_CONTRACT}:${PORT_CONTRACT_INTERNAL} \\
  162. -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
  163. --restart unless-stopped \\
  164. ${IMAGE_GATEWAY}
  165. wait_http "http://127.0.0.1:${PORT_CONTRACT_HOST}/health" "contract" "${CONTAINER_NAME_CONTRACT}"
  166. wait_http "http://127.0.0.1:${PORT_GATEWAY_HOST}/health" "gateway" "${CONTAINER_NAME_GATEWAY}"
  167. sudo docker ps --filter name=${CONTAINER_NAME_STORE} --filter name=${CONTAINER_NAME_GATEWAY} --filter name=${CONTAINER_NAME_CONTRACT}
  168. REMOTE_EOF
  169. """
  170. }
  171. }
  172. }
  173. }
  174. post {
  175. success {
  176. echo ">>> alien_py_cloud deployed on ${env.SSH_TARGET}"
  177. }
  178. failure {
  179. echo '>>> failed: check SSH, .env.produ, sudo docker, and remote git path'
  180. }
  181. always {
  182. cleanWs()
  183. }
  184. }
  185. }