diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..ad85080 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,109 @@ +pipeline { + agent any + options { + ansiColor('xterm'); timestamps(); disableConcurrentBuilds() + timeout(time: 25, unit: 'MINUTES') + buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '10')) + } + + environment { + REGISTRY = 'registry.aetherframe.tech' + IMAGE = 'simulationable/eop-services-app' // 👈 ชื่ออิมเมจของโปรเจกต์นี้ + APP_PORT = '3000' // Next.js listens in container + HOST_PORT = '5003' // 👈 พอร์ตบนโฮสต์ (ไม่ชนตัวอื่น) + DOCKER_BUILDKIT = '0' + } + + stages { + stage('Checkout'){ steps { checkout scm } } + + stage('Preflight diagnostics') { + steps { + sh ''' + set -eux + echo "== System =="; whoami || true; id || true; uname -a || true + echo "Workspace: $PWD"; df -h || true; free -h || true + echo "== Git =="; git rev-parse --abbrev-ref HEAD || true; git rev-parse --short=12 HEAD || true + echo "== Docker =="; docker version; docker info || true + echo "== Registry =="; getent hosts ${REGISTRY} || true; curl -sS -I https://${REGISTRY}/v2/ || true + ''' + } + } + + stage('Docker Build'){ + steps { + script { + def branch = (env.BRANCH_NAME ?: env.GIT_BRANCH ?: sh(script: 'git rev-parse --abbrev-ref HEAD', returnStdout: true).trim()) + .replaceFirst(/^origin\\//,'').toLowerCase() + def commit = sh(script: 'git rev-parse --short=12 HEAD', returnStdout: true).trim() + def tag = "${branch}-${env.BUILD_NUMBER}" + env.IMAGE_TAG = tag + + sh """ + set -eux + echo "Building image: ${REGISTRY}/${IMAGE}:${tag}" + docker build --pull \ + --label org.opencontainers.image.revision="${commit}" \ + -t ${REGISTRY}/${IMAGE}:${tag} \ + -t ${REGISTRY}/${IMAGE}:latest \ + . + docker images ${REGISTRY}/${IMAGE} --digests || true + """ + } + } + } + + stage('Diagnose registry before push') { + steps { + sh ''' + set -eux + getent hosts ${REGISTRY} || true + curl -sS -I https://${REGISTRY}/v2/ || true + docker images ${REGISTRY}/${IMAGE} --digests || true + ''' + } + } + + stage('Docker Push'){ + steps { + withCredentials([usernamePassword(credentialsId:'reg-creds', usernameVariable:'REG_USER', passwordVariable:'REG_PASS')]){ + sh ''' + set -eux + docker logout ${REGISTRY} || true + echo "$REG_PASS" | docker login ${REGISTRY} -u "$REG_USER" --password-stdin + docker push ${REGISTRY}/${IMAGE}:${IMAGE_TAG} + docker push ${REGISTRY}/${IMAGE}:latest + curl -sS -u "$REG_USER:$REG_PASS" https://${REGISTRY}/v2/${IMAGE}/tags/list || true + docker logout ${REGISTRY} || true + ''' + } + } + } + + stage('Deploy (same host)'){ + when { branch 'main' } + steps { + sh """ + set -eux + docker rm -f eop-services-app || true + docker run -d --name eop-services-app \\ + -p 127.0.0.1:${HOST_PORT}:${APP_PORT} \\ + -e NODE_ENV=production \\ + -e PORT=${APP_PORT} \\ + --restart=always \\ + ${REGISTRY}/${IMAGE}:latest + sleep 2 + docker ps --no-trunc | sed -n '1,5p' || true + docker logs --tail=200 eop-services-app || true + (curl -fsS http://127.0.0.1:${HOST_PORT}/ || true) + """ + } + } + } + + post { + success { echo "✅ Deployed at http://127.0.0.1:${HOST_PORT}" } + failure { echo "❌ Failed — ดูสเตจ Preflight/Push/Deploy" } + always { cleanWs() } + } +}