Skip to content

Commit

Permalink
add cd workflow (continuation) (#3)
Browse files Browse the repository at this point in the history
* modify trigger branch

* remove trigger branch

* add temporary trigger that is not workflow_run (which can only happen on default branch)

* pull image from ci by sha tag

* change to pull_request as push returns a different github.sha

* correct name

* update readme

* update readme

* deploy to google cloud run

* fix context of variables

* update readme

* fix variable and secret names

* add missing variables

* use google-github-actions/deploy-cloudrun@v2

* fix service name

* add service account for google-github-actions/auth@v2 to generate tokens used when impersonating the service account

* remove setting up cloud sdk

* remove service account

* Revert "remove service account"

This reverts commit 8e9533a.

* pass service account to use into cloud run

* add some hardcodes for debugging

* update initial gcp setup in readme

* update readme

* update readme

* update readme

* update image

* re-enable tagging latest image

* update readme

* add retrieving artifact registry creds and pushing to Artifact Registry for Cloud Run to be able to deploy

* fix incorrect image spec

* move gcp instructions to shell script

* update cd.yml

* remove extraneous Github variable

* remove temporary trigger
  • Loading branch information
epiccoolguy authored Jan 31, 2024
1 parent cb21df5 commit ed2b677
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 143 deletions.
70 changes: 53 additions & 17 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,86 @@ name: CD
on:
workflow_run:
workflows: [CI]
branches: [add-cd]
branches: [master]
types:
- completed

env:
GO_VERSION: ^1.21.5
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
GHCR_REGISTRY: ghcr.io
GAR_REGISTRY: ${{ vars.GAR_LOCATION }}-docker.pkg.dev
GHCR_IMAGE_NAME: ${{ github.repository }}
GAR_IMAGE_NAME: ${{ vars.GCP_PROJECT_ID }}/${{ vars.GAR_REPOSITORY }}/${{ github.repository }}
TAG: sha-${{ github.sha }}

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: "read"
packages: write
packages: "write"
id-token: "write"
steps:
- name: Check out code
uses: actions/checkout@v4

- name: Login to GitHub Container Registry
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull image
run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Tag image as latest
run: docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

- name: Push latest image
run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

- name: Log into Google Cloud Platform
- name: Log in to Google Cloud Platform
uses: "google-github-actions/auth@v2"
with:
project_id: "go-modproxy"
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
workload_identity_provider: ${{ secrets.WIF_PROVIDER_ID }}
service_account: "${{ secrets.WIF_SERVICE_ACCOUNT }}"

- name: "Set up Google Cloud SDK"
uses: "google-github-actions/setup-gcloud@v2"
with:
version: ">= 461.0.0"

- name: "Get Google Artifacts Registry credentials"
run: |
gcloud auth configure-docker "${{ vars.GCR_REGION }}-docker.pkg.dev" --quiet
- name: Pull image built by CI
env:
IMAGE: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${{ env.TAG }}
run: docker pull ${{ env.IMAGE }}

- name: Tag image as latest for GHCR and specific for GAR
env:
IMAGE: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${{ env.TAG }}
GHCR_IMAGE: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:latest
GAR_IMAGE: ${{ env.GAR_REGISTRY }}/${{ env.GAR_IMAGE_NAME }}:${{ env.TAG }}
run: |
docker tag ${{ env.IMAGE }} ${{ env.GHCR_IMAGE }}
docker tag ${{ env.IMAGE }} ${{ env.GAR_IMAGE }}
- name: Push images to GHCR and GAR
env:
GHCR_IMAGE: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:latest
GAR_IMAGE: ${{ env.GAR_REGISTRY }}/${{ env.GAR_IMAGE_NAME }}:${{ env.TAG }}
run: |
docker push ${{ env.GHCR_IMAGE }}
docker push ${{ env.GAR_IMAGE }}
- name: "Deploy to Cloud Run"
uses: "google-github-actions/deploy-cloudrun@v2"
env:
GAR_IMAGE: ${{ env.GAR_REGISTRY }}/${{ env.GAR_IMAGE_NAME }}:${{ env.TAG }}
with:
service: "${{ vars.GCR_SERVICE }}"
image: "${{ env.GAR_IMAGE }}"
env_vars: |
HOST_PATTERN=${{ vars.HOST_PATTERN }}
HOST_REPLACEMENT=${{ vars.HOST_REPLACEMENT }}
PATH_PATTERN=${{ vars.PATH_PATTERN }}
PATH_REPLACEMENT=${{ vars.PATH_REPLACEMENT }}
region: "${{ vars.GCR_REGION }}"
project_id: "${{ vars.GCP_PROJECT_ID }}"
flags: "--service-account=${{ secrets.WIF_SERVICE_ACCOUNT}}" # action does not expose this feature
127 changes: 1 addition & 126 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,129 +55,4 @@ curl -H 'Host: go.loafoe.dev' localhost:8080/modproxy

## Run using Google Cloud Platform

```sh
SERVICE="go-modproxy"
REGION="europe-west4"
BUILD_REGION="europe-west1" # https://cloud.google.com/build/docs/locations#restricted_regions_for_some_projects
BILLING_ACCOUNT_ID=$(gcloud billing accounts list --filter="OPEN = True" --format="value(ACCOUNT_ID)") # use first enabled billing account
PROJECT_ID="go-modproxy"
CLOUDBUILD_BUCKET="gs://${PROJECT_ID}_cloudbuild"
ARTIFACTS_REPOSITORY="cloud-run-source-deploy"
REPOSITORY_URI=$REGION-docker.pkg.dev/$PROJECT_ID/$ARTIFACTS_REPOSITORY/$SERVICE
HOST_PATTERN="go.loafoe.dev"
HOST_REPLACEMENT="github.com"
PATH_PATTERN="/"
PATH_REPLACEMENT="/epiccoolguy/go-"

# Create new GCP project
gcloud projects create "$PROJECT_ID"

# Link billing account
gcloud billing projects link "$PROJECT_ID" --billing-account="$BILLING_ACCOUNT_ID"

# Enable required GCP services
gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com --project="$PROJECT_ID"

# Create GCS bucket for builds
gcloud storage buckets create "$CLOUDBUILD_BUCKET" --location="$REGION" --project="$PROJECT_ID"

# Create Docker artifact repository
gcloud artifacts repositories create "$ARTIFACTS_REPOSITORY" --repository-format=docker --location="$REGION" --project="$PROJECT_ID"

# Submit build to Cloud Build
gcloud builds submit . --config cloudbuild.yaml --substitutions=_REPOSITORY_URI=$REPOSITORY_URI,COMMIT_SHA=$(git rev-parse HEAD) --region="$BUILD_REGION" --project="$PROJECT_ID"

# Deploy service to Cloud Run
gcloud run deploy "$SERVICE" --image="$REPOSITORY_URI:$(git rev-parse HEAD)" --set-env-vars="HOST_PATTERN=$HOST_PATTERN,HOST_REPLACEMENT=$HOST_REPLACEMENT,PATH_PATTERN=$PATH_PATTERN,PATH_REPLACEMENT=$PATH_REPLACEMENT" --no-allow-unauthenticated --region="$REGION" --project="$PROJECT_ID"
```

Enable unauthenticated invocations in an organisation enforcing DRS using Resource Manager tags and a conditional DRS policy:

```sh
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format="value(projectNumber)")
ORGANIZATION_ID=$(gcloud projects describe "$PROJECT_ID" --format="value(parent.id)")

gcloud resource-manager tags bindings create \
--tag-value="$ORGANIZATION_ID/allUsersIngress/True" \
--parent="//run.googleapis.com/projects/$PROJECT_NUMBER/locations/$REGION/services/$SERVICE" \
--location=$REGION

# This can fail until the binding has propagated
gcloud run services add-iam-policy-binding "$SERVICE" \
--member="allUsers" \
--role="roles/run.invoker" \
--region="$REGION" \
--project="$PROJECT_ID"
```

---

Map the Cloud Run instance to a custom domain:

```sh
DOMAIN="go.loafoe.dev"

# It can take up to 30 minutes for Cloud Run to issue provision a certificate and route
gcloud beta run domain-mappings create --service="$SERVICE" --domain="$DOMAIN" --region="$REGION" --project="$PROJECT_ID"
```

Retrieve the necessary DNS record information for the domain mappings:

```sh
gcloud beta run domain-mappings describe --domain="$DOMAIN" --region="$REGION" --project="$PROJECT_ID"
```

## Direct Workload Identity Federation

Set up variables:

```sh
PROJECT_ID="go-modproxy"
REPOSITORY="go-modproxy"
SERVICE="go-modproxy"
```

Create a Workload Identity Pool and get its full ID:

```sh
gcloud iam workload-identity-pools create "github" \
--display-name="GitHub Actions Pool" \
--location="global" \
--project="$PROJECT_ID"

WORKLOAD_IDENTITY_POOL_ID=$(gcloud iam workload-identity-pools describe "github" \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)")
```

Create a Workload Identity Provider within the pool and get its resource name:

```sh
gcloud iam workload-identity-pools providers create-oidc "$REPOSITORY" \
--workload-identity-pool="github" \
--display-name="$REPOSITORY provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--location="global" \
--project="$PROJECT_ID"

# this is the field used for {workload_identity_provider} in google-github-actions/auth@v2
WORKLOAD_IDENTITY_PROVIDER_ID=$(gcloud iam workload-identity-pools providers describe "$REPOSITORY" \
--workload-identity-pool="github" \
--project="$PROJECT_ID" \
--location="global" \
--format="value(name)")
```

```sh
REPOSITORY="epiccoolguy/go-modproxy"
SERVICE="go-modproxy"
REGION="europe-west4"

gcloud run services add-iam-policy-binding "$SERVICE" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPOSITORY}" \
--role="roles/run.admin" \
--region="$REGION" \
--project="$PROJECT_ID"
```
See [gcp.sh](./gcp.sh)
Loading

0 comments on commit ed2b677

Please sign in to comment.