From 3edb151c1404f7a5e3db73641992fad0c9573839 Mon Sep 17 00:00:00 2001 From: phette23 Date: Wed, 26 Feb 2025 13:51:31 -0800 Subject: [PATCH] ci: production gh actions closes #165 --- .github/workflows/prod.yml | 150 ++++++++++++++++++++++++++++++++++++ .github/workflows/stage.yml | 45 ++++++----- 2 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/prod.yml diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml new file mode 100644 index 0000000..9e4bfd8 --- /dev/null +++ b/.github/workflows/prod.yml @@ -0,0 +1,150 @@ +# git tag prod-build-X -> build docker image +# git tag prod-deploy-X -> build image & deploy to GKE +name: 'Production CD' +on: + push: + tags: + - 'prod-build-*' + - 'prod-deploy-*' + +env: + GAR_LOCATION: 'us-west2' + PROJECT_ID: 'cca-web-0' + REPOSITORY: 'us-west2-docker.pkg.dev/cca-web-0/docker-web' + IMAGE: 'libraries' + SERVICE_ACCOUNT: 'libraries-wagtail-gh-actions@cca-web-0.iam.gserviceaccount.com' + WORKLOAD_IDENTITY_PROVIDER: projects/681601623218/locations/global/workloadIdentityPools/github/providers/libraries-wagtail + CLUSTER_LOCATION: 'us-west1-b' + CLUSTER_NAME: 'ccaedu-prod' + K8S_NAMESPACE: 'lib-production' + +jobs: + build: + name: 'Setup, Build, and Push Docker image to Artifact Registry' + runs-on: ubuntu-latest + environment: production + + permissions: + contents: read + id-token: write + + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + + # Configure Workload Identity Federation and generate an access token. + # See https://github.com/google-github-actions/auth for more options, + # including authenticating via a JSON credentials file. + - id: auth + name: Authenticate to Google Cloud + uses: google-github-actions/auth@v2.1.8 + with: + create_credentials_file: true # Important for Docker auth + project_id: ${{ env.PROJECT_ID }} + service_account: ${{ env.SERVICE_ACCOUNT }} + token_format: access_token # Explicitly request OAuth token + workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }} + + # Configure Docker to use the gcloud credentials + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@v2.1.4 + + # This step is necessary too, google-github-actions/auth is not enough + - name: Configure Docker to use GCloud auth + run: gcloud auth configure-docker ${{ env.GAR_LOCATION }}-docker.pkg.dev + + # Authenticate Docker to Google Cloud Artifact Registry + - name: Docker Auth + uses: docker/login-action@v3.3.0 + with: + username: oauth2accesstoken + password: ${{ steps.auth.outputs.auth_token }} + registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev + + # Unique Docker tag like prod-deploy-20-abcd123 + - name: Generate tags + id: tag + run: | + SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7) + if [ "${{ github.ref_type }}" = "tag" ]; then + VERSION="${{ github.ref_name }}-${SHORT_SHA}" + else + VERSION="${SHORT_SHA}" + fi + echo "tag=${VERSION}" >> $GITHUB_OUTPUT + shell: bash + + # From https://docs.docker.com/build/ci/github-actions/cache/ + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.9.0 + + - name: Build and push + uses: docker/build-push-action@v6.14.0 + with: + cache-to: type=inline + cache-from: type=registry,ref=${{ env.REPOSITORY }}/${{ env.IMAGE}}:latest + tags: | + ${{ env.REPOSITORY }}/${{ env.IMAGE}}:latest + ${{ env.REPOSITORY }}/${{ env.IMAGE}}:${{ steps.tag.outputs.tag }} + push: true + + deploy: + needs: build + if: startsWith(github.ref_name, 'prod-deploy-') + runs-on: ubuntu-latest + environment: production + + permissions: + contents: read + id-token: write + + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + + - name: Set up Google Cloud Auth + uses: google-github-actions/auth@v2.1.8 + with: + project_id: ${{ env.PROJECT_ID }} + service_account: ${{ env.SERVICE_ACCOUNT }} + workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }} + + - name: Set up GKE credentials + uses: google-github-actions/get-gke-credentials@v2.3.1 + with: + cluster_name: ${{ env.CLUSTER_NAME }} + location: ${{ env.CLUSTER_LOCATION }} + + - name: Determine Docker tag + id: tag + run: | + SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7) + if [ "${{ github.ref_type }}" = "tag" ]; then + VERSION="${{ github.ref_name }}-${SHORT_SHA}" + else + VERSION="${SHORT_SHA}" + fi + echo "tag=${VERSION}" >> $GITHUB_OUTPUT + shell: bash + + - name: Deploy to GKE + env: + # see staging.yaml for needed vars, most are derived from namespace + IMAGE: ${{ env.REPOSITORY }}/${{ env.IMAGE}}:${{ steps.tag.outputs.tag }} + run: | + # Ensure namespace exists + kubectl get namespace ${K8S_NAMESPACE} || kubectl create namespace ${K8S_NAMESPACE} + + # Apply configuration with error checking + if ! cat kubernetes/staging.yaml | envsubst | kubectl apply -f -; then + echo "Failed to apply Kubernetes configuration" + exit 1 + fi + + # Wait for deployment to roll out + kubectl rollout status deployment/app --namespace ${K8S_NAMESPACE} --timeout=300s + + - name: Verify deployment + run: | + kubectl wait --for=condition=available deployment/app --namespace ${K8S_NAMESPACE} --timeout=60s + kubectl get pods --namespace ${K8S_NAMESPACE} --selector app=libraries -o jsonpath='{.items[*].status.containerStatuses[*].ready}' | grep -q true diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 1aa1465..0f0d96a 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -1,7 +1,5 @@ -# Staging CD: # git tag stg-build-X -> build docker image # git tag stg-deploy-X -> build image & deploy to GKE - name: 'Staging CD' on: push: @@ -22,45 +20,45 @@ env: jobs: build: - name: 'Setup, Build, and Push Docker image to Artifact Registry' - runs-on: 'ubuntu-latest' - environment: 'staging' + name: Setup, Build, and Push Docker image to Artifact Registry + runs-on: ubuntu-latest + environment: staging permissions: - contents: 'read' - id-token: 'write' + contents: read + id-token: write steps: - - name: 'Checkout' - uses: 'actions/checkout@v4.2.2' + - name: Checkout + uses: actions/checkout@v4.2.2 # Configure Workload Identity Federation and generate an access token. # See https://github.com/google-github-actions/auth for more options, # including authenticating via a JSON credentials file. - - id: 'auth' - name: 'Authenticate to Google Cloud' - uses: 'google-github-actions/auth@v2.1.8' + - id: auth + name: Authenticate to Google Cloud + uses: google-github-actions/auth@v2.1.8 with: create_credentials_file: true # Important for Docker auth project_id: ${{ env.PROJECT_ID }} service_account: ${{ env.SERVICE_ACCOUNT }} - token_format: 'access_token' # Explicitly request OAuth token + token_format: access_token # Explicitly request OAuth token workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }} # Configure Docker to use the gcloud credentials - - name: 'Set up Cloud SDK' - uses: 'google-github-actions/setup-gcloud@v2.1.4' + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@v2.1.4 # This step is necessary too, google-github-actions/auth is not enough - - name: 'Configure Docker to use GCloud auth' + - name: Configure Docker to use GCloud auth run: gcloud auth configure-docker ${{ env.GAR_LOCATION }}-docker.pkg.dev # Authenticate Docker to Google Cloud Artifact Registry - - name: 'Docker Auth' - uses: 'docker/login-action@v3.3.0' + - name: Docker Auth + uses: docker/login-action@v3.3.0 with: - username: 'oauth2accesstoken' - password: '${{ steps.auth.outputs.auth_token }}' + username: oauth2accesstoken + password: ${{ steps.auth.outputs.auth_token }} registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev # Unique Docker tag like stg-deploy-20-abcd123 @@ -97,11 +95,12 @@ jobs: environment: staging permissions: - contents: 'read' - id-token: 'write' + contents: read + id-token: write steps: - - uses: actions/checkout@v4.2.2 + - name: Checkout + uses: actions/checkout@v4.2.2 - name: Set up Google Cloud Auth uses: google-github-actions/auth@v2.1.8