Skip to content

Commit eda5b06

Browse files
Nathan ParkerNathan Parker
authored andcommitted
ci/cd troubleshooting
1 parent 7595665 commit eda5b06

File tree

2 files changed

+209
-4
lines changed

2 files changed

+209
-4
lines changed

.github/workflows/ci-cd.yml

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ env:
1212
PYTHON_VERSION: '3.11'
1313
REGISTRY: ghcr.io
1414
IMAGE_NAME: ${{ github.repository }}
15+
GCP_PROJECT_ID: nathan-playground-368310
16+
GCP_REGION: us-west1
17+
AR_REGISTRY: us-west1-docker.pkg.dev
18+
AR_REPOSITORY: cloud-run-source-deploy
1519

1620
jobs:
1721
# Linting and code quality checks
@@ -105,18 +109,37 @@ jobs:
105109
- name: Set up Docker Buildx
106110
uses: docker/setup-buildx-action@v3
107111

108-
- name: Log in to Container Registry
112+
- name: Log in to GitHub Container Registry
109113
uses: docker/login-action@v3
110114
with:
111115
registry: ${{ env.REGISTRY }}
112116
username: ${{ github.actor }}
113117
password: ${{ secrets.GITHUB_TOKEN }}
114118

119+
- name: Authenticate to Google Cloud
120+
if: github.event_name != 'pull_request'
121+
uses: google-github-actions/auth@v2
122+
with:
123+
credentials_json: ${{ secrets.GCP_SA_KEY_PRODUCTION }}
124+
125+
- name: Set up Cloud SDK
126+
if: github.event_name != 'pull_request'
127+
uses: google-github-actions/setup-gcloud@v2
128+
129+
- name: Configure Docker for Artifact Registry
130+
if: github.event_name != 'pull_request'
131+
env:
132+
GCP_REGION: ${{ env.GCP_REGION }}
133+
run: |
134+
gcloud auth configure-docker ${GCP_REGION}-docker.pkg.dev --quiet
135+
115136
- name: Extract metadata
116137
id: meta
117138
uses: docker/metadata-action@v5
118139
with:
119-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
140+
images: |
141+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
142+
${{ env.AR_REGISTRY }}/${{ env.GCP_PROJECT_ID }}/${{ env.AR_REPOSITORY }}/supply-graph-ai
120143
tags: |
121144
type=ref,event=branch
122145
type=ref,event=pr
@@ -137,6 +160,17 @@ jobs:
137160
cache-to: type=gha,mode=max
138161
platforms: linux/amd64,linux/arm64
139162

163+
- name: Verify Artifact Registry push
164+
if: github.event_name != 'pull_request'
165+
env:
166+
GCP_REGION: ${{ env.GCP_REGION }}
167+
GCP_PROJECT_ID: ${{ env.GCP_PROJECT_ID }}
168+
AR_REGISTRY: ${{ env.AR_REGISTRY }}
169+
AR_REPOSITORY: ${{ env.AR_REPOSITORY }}
170+
run: |
171+
echo "Verifying images were pushed to Artifact Registry..."
172+
gcloud artifacts docker images list ${AR_REGISTRY}/${GCP_PROJECT_ID}/${AR_REPOSITORY}/supply-graph-ai --limit=10 || echo "No images found yet"
173+
140174
# Security scanning
141175
security:
142176
name: Security Scan
@@ -207,17 +241,71 @@ jobs:
207241

208242
- name: Deploy to Cloud Run
209243
id: deploy
244+
env:
245+
PROJECT_ID: ${{ env.GCP_PROJECT_ID }}
246+
SA_EMAIL: supply-graph-ai@${{ env.GCP_PROJECT_ID }}.iam.gserviceaccount.com
247+
AR_REGISTRY: ${{ env.AR_REGISTRY }}
248+
AR_REPOSITORY: ${{ env.AR_REPOSITORY }}
210249
run: |
211250
# Determine image tag
251+
# For main branch, the build step creates a "latest" tag
212252
if [ "${{ github.event_name }}" == "release" ]; then
213253
IMAGE_TAG="${{ github.event.release.tag_name }}"
254+
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
255+
IMAGE_TAG="latest"
214256
else
215257
IMAGE_TAG="main"
216258
fi
217259
260+
# Use Artifact Registry image (Cloud Run doesn't support GHCR)
261+
AR_IMAGE="${AR_REGISTRY}/${PROJECT_ID}/${AR_REPOSITORY}/supply-graph-ai:${IMAGE_TAG}"
262+
263+
echo "=== Deployment Configuration ==="
264+
echo "IMAGE_TAG: ${IMAGE_TAG}"
265+
echo "AR_REGISTRY: ${AR_REGISTRY}"
266+
echo "PROJECT_ID: ${PROJECT_ID}"
267+
echo "AR_REPOSITORY: ${AR_REPOSITORY}"
268+
echo "AR_IMAGE: ${AR_IMAGE}"
269+
echo "================================"
270+
271+
echo "Verifying image exists..."
272+
gcloud artifacts docker images describe ${AR_IMAGE} || {
273+
echo "ERROR: Image ${AR_IMAGE} not found in Artifact Registry"
274+
echo "Trying with 'latest' tag instead..."
275+
AR_IMAGE_LATEST="${AR_REGISTRY}/${PROJECT_ID}/${AR_REPOSITORY}/supply-graph-ai:latest"
276+
gcloud artifacts docker images describe ${AR_IMAGE_LATEST} && {
277+
echo "Found image with 'latest' tag, using that instead"
278+
AR_IMAGE=${AR_IMAGE_LATEST}
279+
} || {
280+
echo "Available images in repository:"
281+
gcloud artifacts docker images list ${AR_REGISTRY}/${PROJECT_ID}/${AR_REPOSITORY}/supply-graph-ai || true
282+
exit 1
283+
}
284+
}
285+
286+
echo "Deploying with image: ${AR_IMAGE}"
287+
echo "Full deployment command will use: --image ${AR_IMAGE}"
288+
289+
# Check current service configuration (if it exists)
290+
echo "Checking current service configuration..."
291+
CURRENT_IMAGE=$(gcloud run services describe supply-graph-ai \
292+
--region="${{ env.GCP_REGION }}" \
293+
--format="value(spec.template.spec.containers[0].image)" 2>/dev/null || echo "")
294+
if [ -n "${CURRENT_IMAGE}" ]; then
295+
echo "Current service image: ${CURRENT_IMAGE}"
296+
else
297+
echo "Service does not exist yet"
298+
fi
299+
300+
# Deploy with explicit image override (image flag must be provided)
301+
# Using explicit variable to ensure it's set correctly
302+
IMAGE_TO_DEPLOY="${AR_IMAGE}"
303+
echo "Final image to deploy: ${IMAGE_TO_DEPLOY}"
304+
218305
gcloud run deploy supply-graph-ai \
219-
--image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG} \
220-
--region us-central1 \
306+
--image "${IMAGE_TO_DEPLOY}" \
307+
--service-account "${SA_EMAIL}" \
308+
--region "${{ env.GCP_REGION }}" \
221309
--platform managed \
222310
--no-allow-unauthenticated \
223311
--set-env-vars ENVIRONMENT=production \
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# CI/CD Deployment Permissions
2+
3+
## Overview
4+
5+
For CI/CD deployment to Cloud Run, the service account used in GitHub Actions needs specific IAM permissions to deploy services.
6+
7+
## Required Permissions
8+
9+
The service account needs the **Cloud Run Admin** role to deploy services, and permission to act as itself:
10+
11+
```bash
12+
export PROJECT_ID="nathan-playground-368310"
13+
export SA_EMAIL="supply-graph-ai@${PROJECT_ID}.iam.gserviceaccount.com"
14+
15+
# Grant Cloud Run Admin role (includes all necessary permissions)
16+
gcloud projects add-iam-policy-binding $PROJECT_ID \
17+
--member="serviceAccount:${SA_EMAIL}" \
18+
--role="roles/run.admin"
19+
20+
# Grant permission to act as the service account itself (required for deployment)
21+
gcloud iam service-accounts add-iam-policy-binding ${SA_EMAIL} \
22+
--member="serviceAccount:${SA_EMAIL}" \
23+
--role="roles/iam.serviceAccountUser"
24+
25+
# Grant permission to act as the Compute Engine default service account
26+
# (required even when specifying a different service account)
27+
# Note: The Compute Engine default SA uses PROJECT_NUMBER, not PROJECT_ID
28+
PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
29+
export COMPUTE_SA="${PROJECT_NUMBER}[email protected]"
30+
gcloud iam service-accounts add-iam-policy-binding ${COMPUTE_SA} \
31+
--member="serviceAccount:${SA_EMAIL}" \
32+
--role="roles/iam.serviceAccountUser"
33+
```
34+
35+
## What This Role Includes
36+
37+
The `roles/run.admin` role includes all necessary permissions for Cloud Run deployment:
38+
- `run.services.get` - Get service information
39+
- `run.services.create` - Create new services
40+
- `run.services.update` - Update existing services
41+
- `run.services.delete` - Delete services (if needed)
42+
- `run.revisions.create` - Create new revisions
43+
- `run.revisions.get` - Get revision information
44+
- `run.revisions.update` - Update revisions
45+
- `iam.serviceAccounts.actAs` - Act as the runtime service account
46+
- And other Cloud Run management permissions
47+
48+
## Alternative: Minimum Required Permissions
49+
50+
If you prefer to grant only the minimum required permissions instead of the full admin role:
51+
52+
```bash
53+
# Grant individual permissions (more granular control)
54+
gcloud projects add-iam-policy-binding $PROJECT_ID \
55+
--member="serviceAccount:${SA_EMAIL}" \
56+
--role="roles/run.developer"
57+
58+
# Also need to act as the service account
59+
gcloud projects add-iam-policy-binding $PROJECT_ID \
60+
--member="serviceAccount:${SA_EMAIL}" \
61+
--role="roles/iam.serviceAccountUser"
62+
```
63+
64+
However, `roles/run.admin` is recommended for CI/CD deployments as it provides all necessary permissions in one role.
65+
66+
## Verify Permissions
67+
68+
After granting permissions, verify the service account has the required role:
69+
70+
```bash
71+
gcloud projects get-iam-policy $PROJECT_ID \
72+
--flatten="bindings[].members" \
73+
--filter="bindings.members:serviceAccount:${SA_EMAIL}" \
74+
--format="table(bindings.role)"
75+
```
76+
77+
You should see `roles/run.admin` (or the individual permissions) in the output.
78+
79+
## Artifact Registry Permissions
80+
81+
The service account also needs permission to push images to Artifact Registry:
82+
83+
```bash
84+
# Grant Artifact Registry Writer role (for pushing images)
85+
gcloud projects add-iam-policy-binding $PROJECT_ID \
86+
--member="serviceAccount:${SA_EMAIL}" \
87+
--role="roles/artifactregistry.writer"
88+
```
89+
90+
## Summary of All Required Permissions
91+
92+
Your service account needs:
93+
1. `roles/run.admin` - For Cloud Run deployment operations
94+
2. `roles/iam.serviceAccountUser` on itself - To act as itself during deployment
95+
3. `roles/iam.serviceAccountUser` on Compute Engine default SA - Required by Cloud Run
96+
4. `roles/artifactregistry.writer` - To push images to Artifact Registry
97+
98+
## Important Notes
99+
100+
1. **Separate Service Accounts**: Consider using a separate service account for CI/CD deployment (e.g., `ci-cd-deployer@...`) rather than the runtime service account. This follows the principle of least privilege.
101+
102+
2. **Service Account User Role**: If deploying with a different service account than the runtime service account, you may also need `roles/iam.serviceAccountUser` to allow the deployment service account to act as the runtime service account.
103+
104+
3. **Region-Specific**: Cloud Run permissions are typically project-wide, but ensure the service account has access to the specific region where you're deploying.
105+
106+
## Troubleshooting
107+
108+
If you still get permission errors after granting `roles/run.admin`:
109+
110+
1. **Wait a few minutes** - IAM policy changes can take a few minutes to propagate
111+
2. **Verify the service account email** - Ensure you're using the correct service account
112+
3. **Check project ID** - Ensure you're granting permissions in the correct project
113+
4. **Verify API is enabled** - Ensure Cloud Run API is enabled:
114+
```bash
115+
gcloud services enable run.googleapis.com
116+
```
117+

0 commit comments

Comments
 (0)