/** * alien_py_cloud production deploy (repo root Jenkinsfile) * Jenkins: 39.106.135.88 | Target: 39.105.153.68 | Script Path: Jenkinsfile */ 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 } 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 SNOWFLAKE_WORKER_IP=127.0.0.1 \\ --restart unless-stopped \\ ${IMAGE_STORE} 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 SNOWFLAKE_WORKER_IP=127.0.0.1 \\ --restart unless-stopped \\ ${IMAGE_CONTRACT} 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 STORE_BASE_URL=http://${CONTAINER_NAME_STORE}:${PORT_STORE_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() } } }