|
1 | | -name: Deploy to AWS ECS |
| 1 | +name: Deploy to GCP Cloud Run |
2 | 2 |
|
3 | 3 | on: |
4 | 4 | push: |
@@ -40,11 +40,14 @@ jobs: |
40 | 40 | - name: Checkout code |
41 | 41 | uses: actions/checkout@v4 |
42 | 42 |
|
43 | | - - name: Configure AWS credentials |
44 | | - uses: aws-actions/configure-aws-credentials@v4 |
| 43 | + - name: Authenticate to Google Cloud |
| 44 | + uses: google-github-actions/auth@v2 |
45 | 45 | with: |
46 | | - role-to-assume: ${{ secrets.AWS_ROLE_ARN }} |
47 | | - aws-region: ${{ vars.AWS_REGION }} |
| 46 | + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} |
| 47 | + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} |
| 48 | + |
| 49 | + - name: Set up Cloud SDK |
| 50 | + uses: google-github-actions/setup-gcloud@v2 |
48 | 51 |
|
49 | 52 | - name: Setup Terraform |
50 | 53 | uses: hashicorp/setup-terraform@v3 |
@@ -75,181 +78,37 @@ jobs: |
75 | 78 | TF_VAR_logfire_environment: prod |
76 | 79 | run: terraform apply -auto-approve |
77 | 80 |
|
78 | | - - name: Login to Amazon ECR |
79 | | - id: login-ecr |
80 | | - uses: aws-actions/amazon-ecr-login@v2 |
| 81 | + - name: Configure Docker for Artifact Registry |
| 82 | + run: gcloud auth configure-docker ${{ vars.GCP_REGION }}-docker.pkg.dev |
81 | 83 |
|
82 | 84 | - name: Build and push Docker image |
83 | 85 | env: |
84 | | - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} |
85 | | - ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY_NAME }} |
| 86 | + IMAGE_URL: ${{ vars.GCP_REGION }}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.PROJECT_NAME }}/${{ vars.PROJECT_NAME }} |
86 | 87 | IMAGE_TAG: ${{ github.sha }} |
87 | 88 | run: | |
88 | | - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . |
89 | | - docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest |
90 | | - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG |
91 | | - docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest |
| 89 | + docker build -t $IMAGE_URL:$IMAGE_TAG . |
| 90 | + docker tag $IMAGE_URL:$IMAGE_TAG $IMAGE_URL:latest |
| 91 | + docker push $IMAGE_URL:$IMAGE_TAG |
| 92 | + docker push $IMAGE_URL:latest |
92 | 93 |
|
93 | | - - name: Update ECS service (API) |
| 94 | + - name: Deploy API to Cloud Run |
94 | 95 | run: | |
95 | | - aws ecs update-service \ |
96 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
97 | | - --service ${{ vars.ECS_API_SERVICE_NAME }} \ |
98 | | - --force-new-deployment \ |
99 | | - --region ${{ vars.AWS_REGION }} |
| 96 | + gcloud run services update-traffic ${{ vars.API_SERVICE_NAME }} \ |
| 97 | + --region=${{ vars.GCP_REGION }} \ |
| 98 | + --to-latest |
100 | 99 |
|
101 | | - - name: Update ECS service (Worker) |
| 100 | + - name: Deploy Worker to Cloud Run |
102 | 101 | run: | |
103 | | - aws ecs update-service \ |
104 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
105 | | - --service ${{ vars.ECS_WORKER_SERVICE_NAME }} \ |
106 | | - --force-new-deployment \ |
107 | | - --region ${{ vars.AWS_REGION }} |
| 102 | + gcloud run services update-traffic ${{ vars.WORKER_SERVICE_NAME }} \ |
| 103 | + --region=${{ vars.GCP_REGION }} \ |
| 104 | + --to-latest |
108 | 105 |
|
109 | | - - name: Monitor API deployment |
110 | | - run: | |
111 | | - echo "=== Monitoring API deployment ===" |
112 | | - for i in {1..30}; do |
113 | | - STATUS=$(aws ecs describe-services \ |
114 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
115 | | - --services ${{ vars.ECS_API_SERVICE_NAME }} \ |
116 | | - --region ${{ vars.AWS_REGION }} \ |
117 | | - --query 'services[0].deployments[0].{Status:rolloutState,Running:runningCount,Desired:desiredCount,Pending:pendingCount}' \ |
118 | | - --output json) |
119 | | -
|
120 | | - echo "[$i/30] $(date +%H:%M:%S) - $STATUS" |
121 | | -
|
122 | | - # Get latest task and show its logs |
123 | | - TASK_ARN=$(aws ecs list-tasks \ |
124 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
125 | | - --service-name ${{ vars.ECS_API_SERVICE_NAME }} \ |
126 | | - --region ${{ vars.AWS_REGION }} \ |
127 | | - --query 'taskArns[0]' \ |
128 | | - --output text) |
129 | | -
|
130 | | - if [ -n "$TASK_ARN" ] && [ "$TASK_ARN" != "None" ]; then |
131 | | - TASK_ID=$(echo $TASK_ARN | rev | cut -d'/' -f1 | rev) |
132 | | - echo "--- Recent logs from task $TASK_ID ---" |
133 | | - aws logs tail /ecs/policyengine-api-v2-alpha \ |
134 | | - --log-stream-name-prefix "api/$TASK_ID" \ |
135 | | - --since 30s \ |
136 | | - --format short \ |
137 | | - --region ${{ vars.AWS_REGION }} 2>&1 || echo "No logs available yet" |
138 | | - echo "---" |
139 | | - fi |
140 | | -
|
141 | | - # Check if stable |
142 | | - if aws ecs describe-services \ |
143 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
144 | | - --services ${{ vars.ECS_API_SERVICE_NAME }} \ |
145 | | - --region ${{ vars.AWS_REGION }} \ |
146 | | - --query 'services[0].deployments | length(@) == `1`' \ |
147 | | - --output text | grep -q "True"; then |
148 | | - echo "API deployment completed!" |
149 | | - break |
150 | | - fi |
151 | | -
|
152 | | - sleep 20 |
153 | | - done |
154 | | -
|
155 | | - - name: Monitor worker deployment |
156 | | - run: | |
157 | | - echo "=== Monitoring worker deployment ===" |
158 | | - for i in {1..30}; do |
159 | | - STATUS=$(aws ecs describe-services \ |
160 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
161 | | - --services ${{ vars.ECS_WORKER_SERVICE_NAME }} \ |
162 | | - --region ${{ vars.AWS_REGION }} \ |
163 | | - --query 'services[0].deployments[0].{Status:rolloutState,Running:runningCount,Desired:desiredCount,Pending:pendingCount}' \ |
164 | | - --output json) |
165 | | -
|
166 | | - echo "[$i/30] $(date +%H:%M:%S) - $STATUS" |
167 | | -
|
168 | | - # Get latest task and show its logs |
169 | | - TASK_ARN=$(aws ecs list-tasks \ |
170 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
171 | | - --service-name ${{ vars.ECS_WORKER_SERVICE_NAME }} \ |
172 | | - --region ${{ vars.AWS_REGION }} \ |
173 | | - --query 'taskArns[0]' \ |
174 | | - --output text) |
175 | | -
|
176 | | - if [ -n "$TASK_ARN" ] && [ "$TASK_ARN" != "None" ]; then |
177 | | - TASK_ID=$(echo $TASK_ARN | rev | cut -d'/' -f1 | rev) |
178 | | - echo "--- Recent logs from task $TASK_ID ---" |
179 | | - aws logs tail /ecs/policyengine-api-v2-alpha \ |
180 | | - --log-stream-name-prefix "worker/$TASK_ID" \ |
181 | | - --since 30s \ |
182 | | - --format short \ |
183 | | - --region ${{ vars.AWS_REGION }} 2>&1 || echo "No logs available yet" |
184 | | - echo "---" |
185 | | - fi |
186 | | -
|
187 | | - # Check if stable |
188 | | - if aws ecs describe-services \ |
189 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
190 | | - --services ${{ vars.ECS_WORKER_SERVICE_NAME }} \ |
191 | | - --region ${{ vars.AWS_REGION }} \ |
192 | | - --query 'services[0].deployments | length(@) == `1`' \ |
193 | | - --output text | grep -q "True"; then |
194 | | - echo "Worker deployment completed!" |
195 | | - break |
196 | | - fi |
197 | | -
|
198 | | - sleep 20 |
199 | | - done |
200 | | -
|
201 | | - - name: Final deployment status |
202 | | - run: | |
203 | | - echo "=== Final Deployment Status ===" |
204 | | - echo "API Service:" |
205 | | - aws ecs describe-services \ |
206 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
207 | | - --services ${{ vars.ECS_API_SERVICE_NAME }} \ |
208 | | - --region ${{ vars.AWS_REGION }} \ |
209 | | - --query 'services[0].{Status:status,Running:runningCount,Desired:desiredCount}' \ |
210 | | - --output table |
211 | | -
|
212 | | - echo "" |
213 | | - echo "Worker Service:" |
214 | | - aws ecs describe-services \ |
215 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
216 | | - --services ${{ vars.ECS_WORKER_SERVICE_NAME }} \ |
217 | | - --region ${{ vars.AWS_REGION }} \ |
218 | | - --query 'services[0].{Status:status,Running:runningCount,Desired:desiredCount}' \ |
219 | | - --output table |
220 | | -
|
221 | | - - name: Get API endpoint |
| 106 | + - name: Get API URL |
222 | 107 | run: | |
223 | 108 | echo "=== API Endpoint ===" |
224 | | - TASK_ARN=$(aws ecs list-tasks \ |
225 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
226 | | - --service-name ${{ vars.ECS_API_SERVICE_NAME }} \ |
227 | | - --region ${{ vars.AWS_REGION }} \ |
228 | | - --desired-status RUNNING \ |
229 | | - --query 'taskArns[0]' \ |
230 | | - --output text) |
231 | | -
|
232 | | - if [ -n "$TASK_ARN" ] && [ "$TASK_ARN" != "None" ]; then |
233 | | - NETWORK_INTERFACE_ID=$(aws ecs describe-tasks \ |
234 | | - --cluster ${{ vars.ECS_CLUSTER_NAME }} \ |
235 | | - --tasks $TASK_ARN \ |
236 | | - --region ${{ vars.AWS_REGION }} \ |
237 | | - --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' \ |
238 | | - --output text) |
239 | | -
|
240 | | - PUBLIC_IP=$(aws ec2 describe-network-interfaces \ |
241 | | - --network-interface-ids $NETWORK_INTERFACE_ID \ |
242 | | - --region ${{ vars.AWS_REGION }} \ |
243 | | - --query 'NetworkInterfaces[0].Association.PublicIp' \ |
244 | | - --output text) |
245 | | -
|
246 | | - if [ -n "$PUBLIC_IP" ] && [ "$PUBLIC_IP" != "None" ]; then |
247 | | - echo "API is available at: http://$PUBLIC_IP" |
248 | | - echo "Health check: http://$PUBLIC_IP/health" |
249 | | - echo "Documentation: http://$PUBLIC_IP/docs" |
250 | | - else |
251 | | - echo "Could not retrieve public IP" |
252 | | - fi |
253 | | - else |
254 | | - echo "No running API tasks found" |
255 | | - fi |
| 109 | + API_URL=$(gcloud run services describe ${{ vars.API_SERVICE_NAME }} \ |
| 110 | + --region=${{ vars.GCP_REGION }} \ |
| 111 | + --format='value(status.url)') |
| 112 | + echo "API is available at: $API_URL" |
| 113 | + echo "Health check: $API_URL/health" |
| 114 | + echo "Documentation: $API_URL/docs" |
0 commit comments