Jenkinsfile 6.2 KB

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