| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /**
- * alien_py_cloud production deploy (repo root Jenkinsfile)
- * Jenkins: 39.106.135.88 | Target: 39.105.153.68 | Script Path: Jenkinsfile
- *
- * 容器均使用 --restart unless-stopped,ECS/宿主机重启后 Docker 会自动拉起。
- */
- def DEFAULT_PROD_SSH_TARGET = 'alien_store@39.105.153.68'
- def DEFAULT_PROD_SSH_CREDENTIALS_ID = 'e611a045-2fdc-4613-babd-a72d69bf9814'
- pipeline {
- agent any
- options {
- buildDiscarder(logRotator(numToKeepStr: '10'))
- timestamps()
- }
- parameters {
- string(name: 'PROD_SSH_TARGET', defaultValue: DEFAULT_PROD_SSH_TARGET,
- description: 'Production host SSH target')
- string(name: 'PROD_SSH_CREDENTIALS_ID', defaultValue: DEFAULT_PROD_SSH_CREDENTIALS_ID,
- description: 'Jenkins SSH Username with private key credential ID')
- string(name: 'GIT_BRANCH', defaultValue: 'produ',
- description: 'alien_py_cloud branch to deploy')
- }
- environment {
- CODE_DIR_REMOTE = '/alien_produ/python/alien_py_cloud'
- ENV_FILE_REMOTE = '/alien_produ/python/alien_py_cloud/.env.produ'
- LOG_ROOT_REMOTE = '/alien_produ/python/alien_py_cloud/logs'
- IMAGE_STORE = 'alien_store:local'
- IMAGE_GATEWAY = 'alien_gateway:local'
- IMAGE_CONTRACT = 'alien_contract:local'
- CONTAINER_NAME_STORE = 'py_esign_produ'
- CONTAINER_NAME_GATEWAY = 'py_gateway_produ'
- CONTAINER_NAME_CONTRACT = 'py_contract_produ'
- PORT_STORE_INTERNAL = '48001'
- PORT_GATEWAY_INTERNAL = '43333'
- PORT_CONTRACT_INTERNAL = '8002'
- PORT_GATEWAY_HOST = '33333'
- PORT_CONTRACT_HOST = '8002'
- DOCKER_NET = 'alien_net_produ'
- }
- stages {
- stage('Verify SSH') {
- steps {
- script {
- def sshTarget = (params.PROD_SSH_TARGET ?: DEFAULT_PROD_SSH_TARGET).trim()
- def credId = (params.PROD_SSH_CREDENTIALS_ID ?: DEFAULT_PROD_SSH_CREDENTIALS_ID).trim()
- env.SSH_TARGET = sshTarget
- env.SSH_CRED_ID = credId
- sshagent(credentials: [credId]) {
- sh """
- set -e
- ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${sshTarget}' \\
- 'test -f ${ENV_FILE_REMOTE} && sudo docker info >/dev/null'
- echo ">>> SSH OK: ${sshTarget}"
- """
- }
- }
- }
- }
- stage('Git Pull on Production') {
- steps {
- sshagent(credentials: [env.SSH_CRED_ID]) {
- sh """
- set -e
- ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
- set -e
- cd '${CODE_DIR_REMOTE}'
- if [ ! -d .git ]; then
- echo "ERROR: ${CODE_DIR_REMOTE} is not a git repo. Clone manually first."
- exit 1
- fi
- git fetch origin
- git checkout '${params.GIT_BRANCH}'
- git pull origin '${params.GIT_BRANCH}'
- echo ">>> git at \$(git rev-parse --short HEAD) on \$(hostname)"
- REMOTE_EOF
- """
- }
- }
- }
- stage('Build Images on Production') {
- steps {
- sshagent(credentials: [env.SSH_CRED_ID]) {
- sh """
- set -e
- ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
- set -e
- cd '${CODE_DIR_REMOTE}'
- sudo docker build -f alien_store/Dockerfile -t ${IMAGE_STORE} .
- sudo docker build -f alien_gateway/Dockerfile -t ${IMAGE_GATEWAY} .
- sudo docker build -f alien_contract/Dockerfile -t ${IMAGE_CONTRACT} .
- echo ">>> images built on \$(hostname)"
- sudo docker images | grep -E 'alien_store|alien_gateway|alien_contract' | head -10
- REMOTE_EOF
- """
- }
- }
- }
- stage('Deploy on Production') {
- steps {
- sshagent(credentials: [env.SSH_CRED_ID]) {
- sh """
- set -e
- ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new '${env.SSH_TARGET}' bash -s <<'REMOTE_EOF'
- set -e
- sudo docker network create ${DOCKER_NET} 2>/dev/null || true
- mkdir -p ${LOG_ROOT_REMOTE}/store ${LOG_ROOT_REMOTE}/gateway ${LOG_ROOT_REMOTE}/contract
- sudo docker rm -f ${CONTAINER_NAME_STORE} ${CONTAINER_NAME_GATEWAY} ${CONTAINER_NAME_CONTRACT} 2>/dev/null || true
- # legacy / previous container names (same host ports)
- sudo docker rm -f esign alien_gateway_py alien_contract_py \\
- alien_store_produ alien_gateway_produ alien_contract_produ 2>/dev/null || true
- wait_http() {
- url="\$1"
- label="\$2"
- cname="\$3"
- for i in \$(seq 1 30); do
- if curl -sf "\$url" >/dev/null 2>&1; then
- echo ">>> \$label OK: \$url"
- return 0
- fi
- sleep 2
- done
- echo ">>> \$label FAILED: \$url"
- if [ -n "\$cname" ]; then
- echo ">>> docker ps -a:"
- sudo docker ps -a --filter name="\$cname" || true
- echo ">>> docker logs --tail 100 \$cname:"
- sudo docker logs --tail 100 "\$cname" 2>&1 || true
- fi
- return 1
- }
- # 1) store(下游)
- sudo docker run -d --name ${CONTAINER_NAME_STORE} \\
- --network ${DOCKER_NET} \\
- --env-file ${ENV_FILE_REMOTE} \\
- -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
- -v ${LOG_ROOT_REMOTE}/store:/app/common/logs/alien_store \\
- -e APP_ENV=produ \\
- -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
- --restart unless-stopped \\
- ${IMAGE_STORE}
- # 2) contract(下游)
- sudo docker run -d --name ${CONTAINER_NAME_CONTRACT} \\
- --network ${DOCKER_NET} \\
- -p ${PORT_CONTRACT_HOST}:${PORT_CONTRACT_INTERNAL} \\
- --env-file ${ENV_FILE_REMOTE} \\
- -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
- -v ${LOG_ROOT_REMOTE}/contract:/app/common/logs/alien_contract \\
- -e APP_ENV=produ \\
- -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
- --restart unless-stopped \\
- ${IMAGE_CONTRACT}
- # 3) gateway(依赖 store/contract;对外 33333)
- sudo docker run -d --name ${CONTAINER_NAME_GATEWAY} \\
- --network ${DOCKER_NET} \\
- -p ${PORT_GATEWAY_HOST}:${PORT_GATEWAY_INTERNAL} \\
- --env-file ${ENV_FILE_REMOTE} \\
- -v ${ENV_FILE_REMOTE}:/app/.env.produ:ro \\
- -v ${LOG_ROOT_REMOTE}/gateway:/app/common/logs/alien_gateway \\
- -e APP_ENV=produ \\
- -e STORE_BASE_URL=http://${CONTAINER_NAME_STORE}:${PORT_STORE_INTERNAL} \\
- -e CONTRACT_BASE_URL=http://${CONTAINER_NAME_CONTRACT}:${PORT_CONTRACT_INTERNAL} \\
- -e SNOWFLAKE_WORKER_IP=127.0.0.1 \\
- --restart unless-stopped \\
- ${IMAGE_GATEWAY}
- wait_http "http://127.0.0.1:${PORT_CONTRACT_HOST}/health" "contract" "${CONTAINER_NAME_CONTRACT}"
- wait_http "http://127.0.0.1:${PORT_GATEWAY_HOST}/health" "gateway" "${CONTAINER_NAME_GATEWAY}"
- sudo docker ps --filter name=${CONTAINER_NAME_STORE} --filter name=${CONTAINER_NAME_GATEWAY} --filter name=${CONTAINER_NAME_CONTRACT}
- REMOTE_EOF
- """
- }
- }
- }
- }
- post {
- success {
- echo ">>> alien_py_cloud deployed on ${env.SSH_TARGET}"
- }
- failure {
- echo '>>> failed: check SSH, .env.produ, sudo docker, and remote git path'
- }
- always {
- cleanWs()
- }
- }
- }
|