|
| 1 | +name: Spring CD (Test Server) |
| 2 | + |
| 3 | +on: |
| 4 | + push: |
| 5 | + branches: |
| 6 | + - develop |
| 7 | + |
| 8 | +jobs: |
| 9 | + cd-test: |
| 10 | + runs-on: ubuntu-latest |
| 11 | + |
| 12 | + steps: |
| 13 | + - name: Checkout code |
| 14 | + uses: actions/checkout@v4 |
| 15 | + |
| 16 | + - name: Deploy to Test Environment |
| 17 | + |
| 18 | + with: |
| 19 | + host: ${{ secrets.TEST_SERVER_HOST }} |
| 20 | + username: ec2-user |
| 21 | + key: ${{ secrets.SSH_PRIVATE_KEY }} |
| 22 | + script: | |
| 23 | + # GHCR 로그인 |
| 24 | + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.repository_owner }}" --password-stdin |
| 25 | + docker pull ghcr.io/${{ github.repository }}/zoopzoop:latest |
| 26 | +
|
| 27 | + NPM_HOST="localhost:81" |
| 28 | + NPM_EMAIL="${{ secrets.NPM_ADMIN_EMAIL }}" |
| 29 | + NPM_PASSWORD="${{ secrets.NPM_ADMIN_PASSWORD }}" |
| 30 | + PROXY_HOST_ID="${{ secrets.NPM_PROXY_HOST_ID }}" |
| 31 | +
|
| 32 | + # NPM 토큰 |
| 33 | + TOKEN=$(curl -s -X POST "http://${NPM_HOST}/api/tokens" \ |
| 34 | + -H "Content-Type: application/json" \ |
| 35 | + -d "{\"identity\":\"${NPM_EMAIL}\",\"secret\":\"${NPM_PASSWORD}\"}" | jq -r '.token') |
| 36 | + if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then |
| 37 | + echo "❌ Failed to get NPM API token" |
| 38 | + exit 1 |
| 39 | + fi |
| 40 | +
|
| 41 | + CURRENT_CONFIG=$(curl -s -H "Authorization: Bearer $TOKEN" \ |
| 42 | + "http://${NPM_HOST}/api/nginx/proxy-hosts/${PROXY_HOST_ID}") |
| 43 | +
|
| 44 | + CURRENT_TARGET=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_host // .forward_host') |
| 45 | + CURRENT_PORT=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_port // .forward_port') |
| 46 | + echo "Current NPM target: $CURRENT_TARGET:$CURRENT_PORT" |
| 47 | +
|
| 48 | + if [ "$(docker ps -q -f name=zoopzoop-blue)" ]; then |
| 49 | + NEW_CONTAINER=zoopzoop-green |
| 50 | + OLD_CONTAINER=zoopzoop-blue |
| 51 | + NEW_PORT=8082 |
| 52 | + else |
| 53 | + NEW_CONTAINER=zoopzoop-blue |
| 54 | + OLD_CONTAINER=zoopzoop-green |
| 55 | + NEW_PORT=8081 |
| 56 | + fi |
| 57 | +
|
| 58 | + docker run -d --restart unless-stopped \ |
| 59 | + -p $NEW_PORT:8080 \ |
| 60 | + --name $NEW_CONTAINER \ |
| 61 | + --network common \ |
| 62 | + -e SPRING_DATASOURCE_URL="${{secrets.TEST_DB_URL}}" \ |
| 63 | + -e SPRING_DATASOURCE_USERNAME="${{secrets.TEST_DB_USERNAME}}" \ |
| 64 | + -e SPRING_DATASOURCE_PASSWORD="${{secrets.TEST_DB_PASSWORD}}" \ |
| 65 | + ghcr.io/${{ github.repository }}/zoopzoop:latest |
| 66 | +
|
| 67 | + # 헬스체크 |
| 68 | + for i in {1..30}; do |
| 69 | + if curl -s http://localhost:$NEW_PORT/actuator/health | grep -q '"status":"UP"'; then |
| 70 | + echo "✅ New container is healthy!" |
| 71 | + break |
| 72 | + else |
| 73 | + echo "Waiting for new container to be healthy..." |
| 74 | + sleep 5 |
| 75 | + fi |
| 76 | + if [ $i -eq 30 ]; then |
| 77 | + echo "❌ Health check failed. Rolling back..." |
| 78 | + docker stop $NEW_CONTAINER || true |
| 79 | + docker rm $NEW_CONTAINER || true |
| 80 | + exit 1 |
| 81 | + fi |
| 82 | + done |
| 83 | +
|
| 84 | + # NPM 트래픽 스위칭 |
| 85 | + DOMAIN_NAME=$(echo $CURRENT_CONFIG | jq -r '.domain_names[0]') |
| 86 | + CERT_ID=$(echo "$CURRENT_CONFIG" | jq -r '.certificate_id') |
| 87 | +
|
| 88 | + SWITCH_RESPONSE=$(curl -s -w "%{http_code}" -X PUT "http://${NPM_HOST}/api/nginx/proxy-hosts/${PROXY_HOST_ID}" \ |
| 89 | + -H "Authorization: Bearer $TOKEN" \ |
| 90 | + -H "Content-Type: application/json" \ |
| 91 | + -d "{ |
| 92 | + \"domain_names\": [\"$DOMAIN_NAME\"], |
| 93 | + \"forward_scheme\": \"http\", |
| 94 | + \"forward_host\": \"$NEW_CONTAINER\", |
| 95 | + \"forward_port\": 8080, |
| 96 | + \"caching_enabled\": false, |
| 97 | + \"block_exploits\": true, |
| 98 | + \"advanced_config\": \"\", |
| 99 | + \"locations\": [], |
| 100 | + \"certificate_id\": $CERT_ID, |
| 101 | + \"ssl_forced\": 1, |
| 102 | + \"hsts_enabled\": 1, |
| 103 | + \"hsts_subdomains\": 1 |
| 104 | + }") |
| 105 | +
|
| 106 | + HTTP_CODE=${SWITCH_RESPONSE: -3} |
| 107 | + if [ "$HTTP_CODE" -ne 200 ] && [ "$HTTP_CODE" -ne 201 ]; then |
| 108 | + echo "❌ Traffic switching failed! HTTP Code: $HTTP_CODE" |
| 109 | + echo "Response: ${SWITCH_RESPONSE%???}" |
| 110 | + docker stop $NEW_CONTAINER || true |
| 111 | + docker rm $NEW_CONTAINER || true |
| 112 | + exit 1 |
| 113 | + fi |
| 114 | +
|
| 115 | + docker stop $OLD_CONTAINER || true |
| 116 | + docker rm $OLD_CONTAINER || true |
0 commit comments