Jenkinsfile-alien-py-cloud-produ.groovy 6.2 KB

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