Skip to content

Deploy: ENSNode to Blue/Green Environment on Railway platform #3

Deploy: ENSNode to Blue/Green Environment on Railway platform

Deploy: ENSNode to Blue/Green Environment on Railway platform #3

name: "Deploy: ENSNode to Blue/Green Environment on Railway platform"
on:
workflow_dispatch:
inputs:
target:
description: "Target environment (green or blue)"
required: true
type: choice
options:
- green
- blue
tag:
description: "Docker Image Tag (also used for schema name generation)"
required: true
type: string
permissions:
id-token: write
contents: read
jobs:
deploy-environment:
runs-on: blacksmith-4vcpu-ubuntu-2204
env:
TARGET_ENVIRONMENT: ${{ inputs.target }}
TAG: ${{ inputs.tag }}
ENSINDEXER_DOCKER_IMAGE: "ghcr.io/namehash/ensnode/ensindexer:${{ inputs.tag }}"
ENSAPI_DOCKER_IMAGE: "ghcr.io/namehash/ensnode/ensapi:${{ inputs.tag }}"
ENSRAINBOW_DOCKER_IMAGE: "ghcr.io/namehash/ensnode/ensrainbow:${{ inputs.tag }}"
ENSADMIN_DOCKER_IMAGE: "ghcr.io/namehash/ensnode/ensadmin:${{ inputs.tag }}"
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
RAILWAY_ENVIRONMENT_ID: ${{ secrets.RAILWAY_ENVIRONMENT_ID}}
RAILWAY_TEAM_TOKEN: ${{ secrets.RAILWAY_TEAM_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Check if Docker images exists
run: |
docker manifest inspect ${{ env.ENSINDEXER_DOCKER_IMAGE }} || { echo "Given docker image does not exist: ${{ env.ENSINDEXER_DOCKER_IMAGE }}"; exit 1; }
docker manifest inspect ${{ env.ENSAPI_DOCKER_IMAGE }} || { echo "Given docker image does not exist: ${{ env.ENSAPI_DOCKER_IMAGE }}"; exit 1; }
docker manifest inspect ${{ env.ENSRAINBOW_DOCKER_IMAGE }} || { echo "Given docker image does not exist: ${{ env.ENSRAINBOW_DOCKER_IMAGE }}"; exit 1; }
docker manifest inspect ${{ env.ENSADMIN_DOCKER_IMAGE }} || { echo "Given docker image does not exist: ${{ env.ENSADMIN_DOCKER_IMAGE }}"; exit 1; }
- name: Print switch target
run: |
echo "Deploying on: $TARGET_ENVIRONMENT"
- name: Calculate env variables
run: |
case "$TARGET_ENVIRONMENT" in
"green")
#ENVIRONMENT
echo "RAILWAY_ENVIRONMENT_ID=${{ secrets.GREEN_RAILWAY_ENVIRONMENT_ID }}" >> $GITHUB_ENV
#ALPHA
echo "ALPHA_API_SVC_ID="${{ secrets.GREEN_ALPHA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "ALPHA_INDEXER_SVC_ID="${{ secrets.GREEN_ALPHA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#MAINNET
echo "MAINNET_API_SVC_ID="${{ secrets.GREEN_MAINNET_API_SVC_ID }} >> "$GITHUB_ENV"
echo "MAINNET_INDEXER_SVC_ID="${{ secrets.GREEN_MAINNET_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#ALPHA-SEPOLIA
echo "ALPHA_SEPOLIA_API_SVC_ID="${{ secrets.GREEN_ALPHA_SEPOLIA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "ALPHA_SEPOLIA_INDEXER_SVC_ID="${{ secrets.GREEN_ALPHA_SEPOLIA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#SEPOLIA
echo "SEPOLIA_API_SVC_ID="${{ secrets.GREEN_SEPOLIA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "SEPOLIA_INDEXER_SVC_ID="${{ secrets.GREEN_SEPOLIA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#HOLESKY
echo "HOLESKY_API_SVC_ID="${{ secrets.GREEN_HOLESKY_API_SVC_ID }} >> "$GITHUB_ENV"
echo "HOLESKY_INDEXER_SVC_ID="${{ secrets.GREEN_HOLESKY_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#ENSRAINBOW
echo "ENSRAINBOW_SVC_ID="${{ secrets.GREEN_ENSRAINBOW_SVC_ID }} >> "$GITHUB_ENV"
#ENSADMIN
echo "ENSADMIN_SVC_ID="${{ secrets.GREEN_ENSADMIN_SVC_ID }} >> "$GITHUB_ENV"
echo "SLACK_TITLE=':large_green_circle: GREEN environment is now having new ENSNode version - '"${{ env.TAG }} >> "$GITHUB_ENV"
;;
"blue")
#ENVIRONMENT
echo "RAILWAY_ENVIRONMENT_ID=${{ secrets.BLUE_RAILWAY_ENVIRONMENT_ID }}" >> $GITHUB_ENV
#ALPHA
echo "ALPHA_API_SVC_ID="${{ secrets.BLUE_ALPHA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "ALPHA_INDEXER_SVC_ID="${{ secrets.BLUE_ALPHA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#MAINNET
echo "MAINNET_API_SVC_ID="${{ secrets.BLUE_MAINNET_API_SVC_ID }} >> "$GITHUB_ENV"
echo "MAINNET_INDEXER_SVC_ID="${{ secrets.BLUE_MAINNET_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#ALPHA-SEPOLIA
echo "ALPHA_SEPOLIA_API_SVC_ID="${{ secrets.BLUE_ALPHA_SEPOLIA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "ALPHA_SEPOLIA_INDEXER_SVC_ID="${{ secrets.BLUE_ALPHA_SEPOLIA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#SEPOLIA
echo "SEPOLIA_API_SVC_ID="${{ secrets.BLUE_SEPOLIA_API_SVC_ID }} >> "$GITHUB_ENV"
echo "SEPOLIA_INDEXER_SVC_ID="${{ secrets.BLUE_SEPOLIA_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#HOLESKY
echo "HOLESKY_API_SVC_ID="${{ secrets.BLUE_HOLESKY_API_SVC_ID }} >> "$GITHUB_ENV"
echo "HOLESKY_INDEXER_SVC_ID="${{ secrets.BLUE_HOLESKY_INDEXER_SVC_ID }} >> "$GITHUB_ENV"
#ENSRAINBOW
echo "ENSRAINBOW_SVC_ID="${{ secrets.BLUE_ENSRAINBOW_SVC_ID }} >> "$GITHUB_ENV"
#ENSADMIN
echo "ENSADMIN_SVC_ID="${{ secrets.BLUE_ENSADMIN_SVC_ID }} >> "$GITHUB_ENV"
echo "SLACK_TITLE=':large_blue_circle: BLUE environment is now having new ENSNode version - '"${{ env.TAG }} >> "$GITHUB_ENV"
;;
*)
echo "Environment not recognized, skipping workflow"
exit 1
esac
# Update indexer source docker image
- name: Update shared environment variable
run: |
update_service_image() {
local environment_id=$1
local service_id=$2
local docker_image=$3
echo "Updating service $service_id"
curl --request POST \
--silent \
--fail \
--url https://backboard.railway.app/graphql/v2 \
--header 'Authorization: Bearer '${{ env.RAILWAY_TOKEN }} \
--header 'Content-Type: application/json' \
--data '{
"query": "mutation serviceInstanceUpdate($environmentId: String, $input: ServiceInstanceUpdateInput!, $serviceId: String!) { serviceInstanceUpdate(environmentId: $environmentId input: $input serviceId: $serviceId) }",
"variables": {
"environmentId": "'$environment_id'",
"input": {"source": {"image": "'$docker_image'"}},
"serviceId": "'$service_id'"
}
}'
echo "Finished updating $service_id"
}
#ALPHA
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_API_SVC_ID} ${{ env.ENSAPI_DOCKER_IMAGE }}
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_INDEXER_SVC_ID} ${{ env.ENSINDEXER_DOCKER_IMAGE }}
#MAINNET
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${MAINNET_API_SVC_ID} ${{ env.ENSAPI_DOCKER_IMAGE }}
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${MAINNET_INDEXER_SVC_ID} ${{ env.ENSINDEXER_DOCKER_IMAGE }}
#ALPHA-SEPOLIA
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_SEPOLIA_API_SVC_ID} ${{ env.ENSAPI_DOCKER_IMAGE }}
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_SEPOLIA_INDEXER_SVC_ID} ${{ env.ENSINDEXER_DOCKER_IMAGE }}
#SEPOLIA
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${SEPOLIA_API_SVC_ID} ${{ env.ENSAPI_DOCKER_IMAGE }}
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${SEPOLIA_INDEXER_SVC_ID} ${{ env.ENSINDEXER_DOCKER_IMAGE }}
#HOLESKY
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${HOLESKY_API_SVC_ID} ${{ env.ENSAPI_DOCKER_IMAGE }}
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${HOLESKY_INDEXER_SVC_ID} ${{ env.ENSINDEXER_DOCKER_IMAGE }}
#ENSRAINBOW
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ENSRAINBOW_SVC_ID} ${{ env.ENSRAINBOW_DOCKER_IMAGE }}
#ENSADMIN
update_service_image ${RAILWAY_ENVIRONMENT_ID} ${ENSADMIN_SVC_ID} ${{ env.ENSADMIN_DOCKER_IMAGE }}
# Update DATABASE_SCHEMA for each indexer based on input tag
- name: Update shared environment variable
run: |
set_shared_variable() {
local environment_id=$1
local variable_name=$2
local variable_value=$3
echo "Setting $variable_name"
curl --request POST \
--silent \
--fail \
--url https://backboard.railway.app/graphql/v2 \
--header 'Authorization: Bearer '${{ env.RAILWAY_TOKEN }} \
--header 'Content-Type: application/json' \
--data '{"query": "mutation variableUpsert { variableUpsert(input: { projectId: \"'${{ env.RAILWAY_PROJECT_ID }}'\", environmentId: \"'${environment_id}'\", name: \"'${variable_name}'\", value: \"'${variable_value}'\" }) }"}'
echo "Finished setting $variable_name"
}
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "ALPHA_DATABASE_SCHEMA" "alphaSchema${TAG}"
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "MAINNET_DATABASE_SCHEMA" "mainnetSchema${TAG}"
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "ALPHA-SEPOLIA_DATABASE_SCHEMA" "alphaSepoliaSchema${TAG}"
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "SEPOLIA_DATABASE_SCHEMA" "sepoliaSchema${TAG}"
set_shared_variable ${RAILWAY_ENVIRONMENT_ID} "HOLESKY_DATABASE_SCHEMA" "holeskySchema${TAG}"
- name: Redeploy ENSNode instances
run: |
redeploy_service() {
local environment_id=$1
local service_id=$2
echo "Redeploying $service_id"
curl --request POST \
--silent \
--url https://backboard.railway.app/graphql/v2 \
--header 'Authorization: Bearer '${{ env.RAILWAY_TOKEN }} \
--header 'Content-Type: application/json' \
--data "{\"query\":\"mutation serviceInstanceDeploy(\$serviceId: String!, \$environmentId: String!) { serviceInstanceDeploy(serviceId: \$serviceId, environmentId: \$environmentId) }\",\"variables\":{\"environmentId\":\"${environment_id}\",\"serviceId\":\"${service_id}\"}}"
echo "Finished redeploying $service_id"
}
#ALPHA
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_API_SVC_ID}
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_INDEXER_SVC_ID}
#MAINNET
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${MAINNET_API_SVC_ID}
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${MAINNET_INDEXER_SVC_ID}
#ALPHA-SEPOLIA
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_SEPOLIA_API_SVC_ID}
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ALPHA_SEPOLIA_INDEXER_SVC_ID}
#SEPOLIA
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${SEPOLIA_API_SVC_ID}
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${SEPOLIA_INDEXER_SVC_ID}
#HOLESKY
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${HOLESKY_API_SVC_ID}
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${HOLESKY_INDEXER_SVC_ID}
#ENSRAINBOW
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ENSRAINBOW_SVC_ID}
#ENSADMIN
redeploy_service ${RAILWAY_ENVIRONMENT_ID} ${ENSADMIN_SVC_ID}
- uses: ./.github/actions/send_slack_notification
with:
slack_webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
slack_title: ${{ env.SLACK_TITLE }}
slack_message: "✅ Deploy ENSNode completed"