diff --git a/.gitea/workflows/staging_release.yml b/.gitea/workflows/staging_release.yml index 1a455f4a..893183e8 100644 --- a/.gitea/workflows/staging_release.yml +++ b/.gitea/workflows/staging_release.yml @@ -11,6 +11,7 @@ on: jobs: deploy-staging: runs-on: ubuntu-latest + steps: - name: Checkout code uses: actions/checkout@v4 @@ -27,8 +28,7 @@ jobs: USERFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/userfront ADMINFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/adminfront DEVFRONT_IMAGE_NAME: ${{ vars.HARBOR_HOSTNAME }}/baron_sso/devfront - - # Staging-specific variables + DEPLOY_PATH: ${{ vars.STAGE_DEPLOY_PATH }} STAGE_HOST: ${{ vars.STAGE_HOST }} STAGE_USER: ${{ vars.STAGE_USER }} @@ -36,80 +36,97 @@ jobs: HARBOR_ENDPOINT: ${{ vars.HARBOR_ENDPOINT }} HARBOR_ROBOT_ACCOUNT: ${{ vars.HARBOR_ROBOT_ACCOUNT }} HARBOR_ROBOT_KEY: ${{ secrets.HARBOR_ROBOT_KEY }} + run: | set -euo pipefail - echo "DEBUG: STAGE_USER='${STAGE_USER}'" - echo "DEBUG: STAGE_HOST='${STAGE_HOST}'" - echo "DEBUG: DEPLOY_PATH='${DEPLOY_PATH}'" + echo "STAGE_USER=${STAGE_USER}" + echo "STAGE_HOST=${STAGE_HOST}" + echo "DEPLOY_PATH=${DEPLOY_PATH}" - # Sanity check if [ -z "${STAGE_USER}" ] || [ -z "${STAGE_HOST}" ] || [ -z "${DEPLOY_PATH}" ]; then - echo "::error::Missing required vars (STAGE_USER/STAGE_HOST/DEPLOY_PATH). Check Gitea repo variables." + echo "::error::Missing required staging variables" exit 1 fi ssh-keyscan -H "${STAGE_HOST}" >> ~/.ssh/known_hosts - ssh "${STAGE_USER}@${STAGE_HOST}" "mkdir -p '${DEPLOY_PATH}'" - # Create .env for Staging using a HEREDOC to prevent shell expansion issues + # ---------- create .env ---------- cat <<'EOF' > .env APP_ENV=stage TZ=Asia/Seoul IDP_PROVIDER=ory + DB_PORT=${{ vars.DB_PORT }} CLICKHOUSE_PORT_HTTP=${{ vars.CLICKHOUSE_PORT_HTTP }} CLICKHOUSE_PORT_NATIVE=${{ vars.CLICKHOUSE_PORT_NATIVE }} + BACKEND_PORT=${{ vars.BACKEND_PORT }} ADMINFRONT_PORT=${{ vars.ADMINFRONT_PORT }} DEVFRONT_PORT=${{ vars.DEVFRONT_PORT }} USERFRONT_PORT=${{ vars.USERFRONT_PORT }} + DB_USER=${{ vars.DB_USER }} DB_PASSWORD=${{ secrets.STG_DB_PASSWORD }} DB_NAME=${{ vars.DB_NAME }} + COOKIE_SECRET=${{ secrets.STG_COOKIE_SECRET }} JWT_SECRET=${{ secrets.STG_JWT_SECRET }} + REDIS_ADDR=${{ vars.REDIS_ADDR }} CORS_ALLOWED_ORIGINS=${{ vars.CORS_ALLOWED_ORIGINS }} + AUDIT_WORKER_COUNT=5 AUDIT_QUEUE_SIZE=2000 PROFILE_CACHE_TTL=${{ vars.PROFILE_CACHE_TTL }} + DESCOPE_PROJECT_ID=${{ vars.DESCOPE_PROJECT_ID }} DESCOPE_MANAGEMENT_KEY=${{ secrets.DESCOPE_MANAGEMENT_KEY }} DESCOPE_TEST_ACCOUNT=${{ vars.DESCOPE_TEST_ACCOUNT }} + NAVER_CLOUD_ACCESS_KEY=${{ vars.NAVER_CLOUD_ACCESS_KEY }} NAVER_CLOUD_SECRET_KEY=${{ secrets.NAVER_CLOUD_SECRET_KEY }} NAVER_CLOUD_SERVICE_ID=${{ vars.NAVER_CLOUD_SERVICE_ID }} NAVER_SENDER_PHONE_NUMBER=${{ vars.NAVER_SENDER_PHONE_NUMBER }} + AWS_REGION=${{ vars.AWS_REGION }} AWS_ACCESS_KEY_ID=${{ vars.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_SES_SENDER=${{ vars.AWS_SES_SENDER }} + ADMIN_EMAIL=${{ vars.ADMIN_EMAIL }} ADMIN_PASSWORD=${{ secrets.STG_ADMIN_PASSWORD }} + USERFRONT_URL=${{ vars.USERFRONT_URL }} BACKEND_URL=${{ vars.BACKEND_URL }} + OATHKEEPER_PUBLIC_URL=${{ vars.OATHKEEPER_PUBLIC_URL }} + ORY_POSTGRES_TAG=${{ vars.ORY_POSTGRES_TAG }} ORY_POSTGRES_USER=${{ vars.ORY_POSTGRES_USER }} ORY_POSTGRES_PASSWORD=${{ secrets.STG_ORY_POSTGRES_PASSWORD }} ORY_POSTGRES_DB=${{ vars.ORY_POSTGRES_DB }} + KRATOS_DB=${{ vars.KRATOS_DB }} HYDRA_DB=${{ vars.HYDRA_DB }} KETO_DB=${{ vars.KETO_DB }} + KRATOS_VERSION=${{ vars.KRATOS_VERSION }} KRATOS_UI_NODE_VERSION=${{ vars.KRATOS_UI_NODE_VERSION }} HYDRA_VERSION=${{ vars.HYDRA_VERSION }} KETO_VERSION=${{ vars.KETO_VERSION }} + ORY_SDK_URL=${{ vars.ORY_SDK_URL }} KRATOS_PUBLIC_URL=${{ vars.KRATOS_PUBLIC_URL }} KRATOS_ADMIN_URL=${{ vars.KRATOS_ADMIN_URL }} KRATOS_BROWSER_URL=${{ vars.KRATOS_BROWSER_URL }} KRATOS_UI_URL=${{ vars.KRATOS_UI_URL }} + HYDRA_ADMIN_URL=${{ vars.HYDRA_ADMIN_URL }} HYDRA_PUBLIC_URL=${{ vars.HYDRA_PUBLIC_URL }} JWKS_URL=${{ vars.JWKS_URL }} + OATHKEEPER_VERSION=${{ vars.OATHKEEPER_VERSION }} OATHKEEPER_UID=${{ vars.OATHKEEPER_UID }} OATHKEEPER_GID=${{ vars.OATHKEEPER_GID }} @@ -117,40 +134,53 @@ jobs: OATHKEEPER_HEALTH_INTERVAL_SECONDS=${{ vars.OATHKEEPER_HEALTH_INTERVAL_SECONDS }} OATHKEEPER_HEALTH_TIMEOUT_SECONDS=${{ vars.OATHKEEPER_HEALTH_TIMEOUT_SECONDS }} OATHKEEPER_HEALTH_ENABLED=${{ vars.OATHKEEPER_HEALTH_ENABLED }} + CSRF_COOKIE_NAME=${{ vars.CSRF_COOKIE_NAME }} CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }} + OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }} OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }} EOF - # Copy artifacts to remote - # Using compose.infra.yaml as base for staging (assuming simplified structure compared to prod) - # OR use docker-compose.template.yaml if staging follows prod structure strictly - scp docker/docker-compose.template.yaml .env "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/" - scp docker/compose.infra.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.infra.yml" - # Ory compose files might be needed too - scp docker/compose.ory.yaml "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.ory.yml" - scp -r docker/ory "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/docker/" + # ---------- copy files ---------- + scp docker/docker-compose.template.yaml .env \ + "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/" - # Deploy - echo "${HARBOR_ROBOT_KEY}" | ssh "${STAGE_USER}@${STAGE_HOST}" \ - "export DEPLOY_PATH='${DEPLOY_PATH}'; \ - export BACKEND_IMAGE_NAME='${BACKEND_IMAGE_NAME}'; \ - export USERFRONT_IMAGE_NAME='${USERFRONT_IMAGE_NAME}'; \ - export ADMINFRONT_IMAGE_NAME='${ADMINFRONT_IMAGE_NAME}'; \ - export DEVFRONT_IMAGE_NAME='${DEVFRONT_IMAGE_NAME}'; \ - export IMAGE_TAG='${IMAGE_TAG}'; \ - export HARBOR_ENDPOINT='${HARBOR_ENDPOINT}'; \ - export HARBOR_ROBOT_ACCOUNT='${HARBOR_ROBOT_ACCOUNT}'; \ - set -e; \ - cd \"\${DEPLOY_PATH}\"; \ - docker login \"\${HARBOR_ENDPOINT}\" -u \"\${HARBOR_ROBOT_ACCOUNT}\" --password-stdin; \ - set -a; \ - . ./.env; \ - set +a; \ - # Assuming template usage similar to prod - envsubst < docker-compose.template.yaml > docker-compose.yml; \ - # Pull & Up - # Assuming staging runs both infra, ory, and app stack - docker compose -f compose.infra.yml -f compose.ory.yml -f docker-compose.yml pull; \ - docker compose -f compose.infra.yml -f compose.ory.yml -f docker-compose.yml up -d --remove-orphans" + scp docker/compose.infra.yaml \ + "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.infra.yml" + + scp docker/compose.ory.yaml \ + "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/compose.ory.yml" + + scp -r docker/ory \ + "${STAGE_USER}@${STAGE_HOST}:${DEPLOY_PATH}/docker/" + + # ---------- deploy ---------- + echo "${HARBOR_ROBOT_KEY}" | ssh "${STAGE_USER}@${STAGE_HOST}" " + set -e + cd '${DEPLOY_PATH}' + + docker login '${HARBOR_ENDPOINT}' \ + -u '${HARBOR_ROBOT_ACCOUNT}' --password-stdin + + # 🔥 CREATE EXTERNAL NETWORKS + for net in baron_net public_net ory-net hydranet kratosnet; do + docker network inspect \"\$net\" >/dev/null 2>&1 || docker network create \"\$net\" + done + + set -a + . ./.env + set +a + + envsubst < docker-compose.template.yaml > docker-compose.yml + + docker compose \ + -f compose.infra.yml \ + -f compose.ory.yml \ + -f docker-compose.yml pull + + docker compose \ + -f compose.infra.yml \ + -f compose.ory.yml \ + -f docker-compose.yml up -d --remove-orphans + "