-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
318 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
# This workflow build and push a Docker container to Google Artifact Registry and deploy it on Cloud Run when a commit is pushed to the $default-branch branch | ||
# | ||
# Overview: | ||
# | ||
# 1. Authenticate to Google Cloud | ||
# 2. Authenticate Docker to Artifact Registry | ||
# 3. Build a docker container | ||
# 4. Publish it to Google Artifact Registry | ||
# 5. Deploy it to Cloud Run | ||
# | ||
# To configure this workflow: | ||
# | ||
# 1. Ensure the required Google Cloud APIs are enabled: | ||
# | ||
# Cloud Run run.googleapis.com | ||
# Artifact Registry artifactregistry.googleapis.com | ||
# | ||
# 2. Create and configure Workload Identity Federation for GitHub (https://github.com/google-github-actions/auth#setting-up-workload-identity-federation) | ||
# | ||
# 3. Ensure the required IAM permissions are granted | ||
# | ||
# Cloud Run | ||
# roles/run.admin | ||
# roles/iam.serviceAccountUser (to act as the Cloud Run runtime service account) | ||
# | ||
# Cloud Storage | ||
# roles/storage.admin (if using Google Container Registry (gcr) instead) | ||
# | ||
# Artifact Registry | ||
# roles/artifactregistry.admin (project or repository level) | ||
# | ||
# NOTE: You should always follow the principle of least privilege when assigning IAM roles | ||
# | ||
# 4. Create GitHub secrets for WIF_PROVIDER and WIF_SERVICE_ACCOUNT | ||
# | ||
# 5. Change the values for the GAR_LOCATION, SERVICE and REGION environment variables (below). | ||
# | ||
# NOTE: To use Google Container Registry instead, replace ${{ env.GAR_LOCATION }}-docker.pkg.dev with gcr.io | ||
# | ||
# For more support on how to run this workflow, please visit https://github.com/marketplace/actions/deploy-to-cloud-run | ||
# | ||
# Further reading: | ||
# Cloud Run IAM permissions - https://cloud.google.com/run/docs/deploying | ||
# Artifact Registry IAM permissions - https://cloud.google.com/artifact-registry/docs/access-control#roles | ||
# Container Registry vs Artifact Registry - https://cloud.google.com/blog/products/application-development/understanding-artifact-registry-vs-container-registry | ||
# Principle of least privilege - https://cloud.google.com/blog/products/identity-security/dont-get-pwned-practicing-the-principle-of-least-privilege | ||
|
||
name: Run deploy | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: | ||
- main | ||
- develop | ||
- infrastructure/setup | ||
paths: | ||
- 'frontend/**' | ||
- 'cms/**' | ||
- '.github/workflows/*' | ||
|
||
env: | ||
PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} | ||
GAR_LOCATION: ${{ secrets.GCP_REGION }} | ||
# TODO: update Artifact Registry repository name | ||
# TODO: update Cloud Run service name | ||
REGION: ${{ secrets.GCP_REGION }} # TODO: update Cloud Run service region | ||
|
||
jobs: | ||
deploy_client: | ||
# Add 'id-token' with the intended permissions for workload identity federation | ||
permissions: | ||
contents: 'read' | ||
id-token: 'write' | ||
|
||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Extract branch name | ||
shell: bash | ||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT | ||
id: extract_branch | ||
|
||
- name: Extract environment name | ||
env: | ||
ENVIRONMENT: ${{ steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || 'STAGING' }} | ||
run: echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT | ||
id: extract_environment | ||
|
||
#- name: Google Auth | ||
# id: auth | ||
# uses: 'google-github-actions/auth@v0' | ||
# with: | ||
# token_format: 'access_token' | ||
# workload_identity_provider: '${{ secrets.WIF_PROVIDER }}' # e.g. - projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider | ||
# service_account: '${{ secrets.WIF_SERVICE_ACCOUNT }}' # e.g. - [email protected] | ||
|
||
# NOTE: Alternative option - authentication via credentials json | ||
- name: Google Auth | ||
id: auth | ||
uses: 'google-github-actions/auth@v1' | ||
with: | ||
credentials_json: "${{ secrets[format('{0}_GCP_SA_KEY', steps.extract_environment.outputs.environment)] }}" | ||
token_format: 'access_token' | ||
|
||
# BEGIN - Docker auth and build (NOTE: If you already have a container image, these Docker steps can be omitted) | ||
|
||
# Authenticate Docker to Google Cloud Artifact Registry | ||
# - name: Docker Auth | ||
# id: docker-auth | ||
# uses: 'docker/login-action@v3' | ||
# with: | ||
# username: 'oauth2accesstoken' | ||
# password: '${{ steps.auth.outputs.access_token }}' | ||
# registry: '${{ env.GAR_LOCATION }}-docker.pkg.dev' | ||
|
||
# NOTE: Alternative option - authentication via credentials json | ||
- name: Docker Auth | ||
id: docker-auth | ||
uses: 'docker/login-action@v3' | ||
with: | ||
registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev | ||
username: _json_key | ||
password: ${{ secrets[format('{0}_GCP_SA_KEY', steps.extract_environment.outputs.environment)] }} | ||
|
||
- name: Copy env variables to docker | ||
run: | | ||
echo "${{ secrets[format('{0}_CLIENT_ENV', steps.extract_environment.outputs.environment)] }}" > frontend/.env.local | ||
# append Terraform managed secrets | ||
echo "${{ secrets[format('{0}_CLIENT_ENV_TF_MANAGED', steps.extract_environment.outputs.environment)] }}" >> frontend/.env.local | ||
- name: Build and Push Container | ||
env: | ||
REPOSITORY: ${{ secrets[format('{0}_CLIENT_REPOSITORY', steps.extract_environment.outputs.environment)] }} | ||
SERVICE: ${{ secrets[format('{0}_CLIENT_SERVICE', steps.extract_environment.outputs.environment)] }} | ||
run: |- | ||
docker build -f frontend/Dockerfile.prod -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" ./frontend | ||
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" | ||
# tag as "latest" | ||
docker tag "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" | ||
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" | ||
# END - Docker auth and build | ||
|
||
- name: Deploy to Cloud Run | ||
env: | ||
REPOSITORY: ${{ secrets[format('{0}_CLIENT_REPOSITORY', steps.extract_environment.outputs.environment)] }} | ||
SERVICE: ${{ secrets[format('{0}_CLIENT_SERVICE', steps.extract_environment.outputs.environment)] }} | ||
id: deploy | ||
uses: google-github-actions/deploy-cloudrun@v1 | ||
with: | ||
service: ${{ env.SERVICE }} | ||
region: ${{ env.REGION }} | ||
# NOTE: If using a pre-built image, update the image name here | ||
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }} | ||
# NOTE: You can also set env variables here: | ||
# env_vars: | | ||
# NODE_ENV=production | ||
# TOKEN_EXPIRE=6400 | ||
|
||
# If required, use the Cloud Run url output in later steps | ||
- name: Show Output | ||
run: echo ${{ steps.deploy.outputs.url }} | ||
|
||
deploy_cms: | ||
# Add 'id-token' with the intended permissions for workload identity federation | ||
permissions: | ||
contents: 'read' | ||
id-token: 'write' | ||
|
||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Extract branch name | ||
shell: bash | ||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT | ||
id: extract_branch | ||
|
||
- name: Extract environment name | ||
env: | ||
ENVIRONMENT: ${{ steps.extract_branch.outputs.branch == 'main' && 'PRODUCTION' || 'STAGING' }} | ||
run: echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT | ||
id: extract_environment | ||
|
||
#- name: Google Auth | ||
# id: auth | ||
# uses: 'google-github-actions/auth@v0' | ||
# with: | ||
# token_format: 'access_token' | ||
# workload_identity_provider: '${{ secrets.WIF_PROVIDER }}' # e.g. - projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider | ||
# service_account: '${{ secrets.WIF_SERVICE_ACCOUNT }}' # e.g. - [email protected] | ||
|
||
# NOTE: Alternative option - authentication via credentials json | ||
- name: Google Auth | ||
id: auth | ||
uses: 'google-github-actions/auth@v1' | ||
with: | ||
credentials_json: "${{ secrets[format('{0}_GCP_SA_KEY', steps.extract_environment.outputs.environment)] }}" | ||
token_format: 'access_token' | ||
|
||
# BEGIN - Docker auth and build (NOTE: If you already have a container image, these Docker steps can be omitted) | ||
|
||
# Authenticate Docker to Google Cloud Artifact Registry | ||
# - name: Docker Auth | ||
# id: docker-auth | ||
# uses: 'docker/login-action@v3' | ||
# with: | ||
# username: 'oauth2accesstoken' | ||
# password: '${{ steps.auth.outputs.access_token }}' | ||
# registry: '${{ env.GAR_LOCATION }}-docker.pkg.dev' | ||
|
||
# NOTE: Alternative option - authentication via credentials json | ||
- name: Docker Auth | ||
id: docker-auth | ||
uses: 'docker/login-action@v3' | ||
with: | ||
registry: ${{ env.GAR_LOCATION }}-docker.pkg.dev | ||
username: _json_key | ||
password: ${{ secrets[format('{0}_GCP_SA_KEY', steps.extract_environment.outputs.environment)] }} | ||
|
||
- name: Copy env variables to docker | ||
run: | | ||
echo "${{ secrets[format('{0}_CMS_ENV_TF_MANAGED', steps.extract_environment.outputs.environment)] }}" > cms/.env | ||
- name: Build and Push Container | ||
env: | ||
REPOSITORY: ${{ secrets[format('{0}_CMS_REPOSITORY', steps.extract_environment.outputs.environment)] }} | ||
SERVICE: ${{ secrets[format('{0}_CMS_SERVICE', steps.extract_environment.outputs.environment)] }} | ||
run: |- | ||
docker build -f cms/Dockerfile.prod -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" ./cms | ||
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" | ||
# tag as "latest" | ||
docker tag "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" | ||
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:latest" | ||
# END - Docker auth and build | ||
|
||
- name: Deploy to Cloud Run | ||
env: | ||
REPOSITORY: ${{ secrets[format('{0}_CMS_REPOSITORY', steps.extract_environment.outputs.environment)] }} | ||
SERVICE: ${{ secrets[format('{0}_CMS_SERVICE', steps.extract_environment.outputs.environment)] }} | ||
id: deploy | ||
uses: google-github-actions/deploy-cloudrun@v1 | ||
with: | ||
service: ${{ env.SERVICE }} | ||
region: ${{ env.REGION }} | ||
# NOTE: If using a pre-built image, update the image name here | ||
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }} | ||
# NOTE: You can also set env variables here: | ||
# env_vars: | | ||
# NODE_ENV=production | ||
# TOKEN_EXPIRE=6400 | ||
|
||
# If required, use the Cloud Run url output in later steps | ||
- name: Show Output | ||
run: echo ${{ steps.deploy.outputs.url }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Install dependencies only when needed | ||
FROM node:18.15-bullseye AS deps | ||
|
||
WORKDIR /app | ||
|
||
# COPY .yarn ./.yarn # TODO: no idea if we want this or not, not in repo | ||
COPY package.json yarn.lock .yarnrc.yml ./ | ||
|
||
RUN yarn install --immutable | ||
|
||
# If using npm with a `package-lock.json` comment out above and use below instead | ||
# COPY package.json package-lock.json ./ | ||
# RUN npm ci | ||
|
||
# Rebuild the source code only when needed | ||
FROM node:18.15-bullseye AS builder | ||
WORKDIR /app | ||
COPY . . | ||
COPY --from=deps /app/node_modules ./node_modules | ||
|
||
# Next.js collects completely anonymous telemetry data about general usage. | ||
# Learn more here: https://nextjs.org/telemetry | ||
# Uncomment the following line in case you want to disable telemetry during the build. | ||
ENV NEXT_TELEMETRY_DISABLED 1 | ||
|
||
RUN yarn build | ||
|
||
# Production image, copy all the files and run next | ||
FROM node:18.15-bullseye AS runner | ||
WORKDIR /app | ||
|
||
ENV NODE_ENV production | ||
# Uncomment the following line in case you want to disable telemetry during runtime. | ||
ENV NEXT_TELEMETRY_DISABLED 1 | ||
|
||
RUN addgroup --system --gid 1001 nodejs | ||
RUN adduser --system --uid 1001 nextjs | ||
|
||
# You only need to copy next.config.js if you are NOT using the default configuration | ||
COPY --from=builder /app/next.config.js ./ | ||
COPY --from=builder /app/public ./public | ||
COPY --from=builder /app/package.json ./package.json | ||
COPY --from=builder /app/.env.local ./.env.local | ||
|
||
# Automatically leverage output traces to reduce image size | ||
# https://nextjs.org/docs/advanced-features/output-file-tracing | ||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ | ||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static | ||
|
||
USER nextjs | ||
|
||
EXPOSE 3000 | ||
|
||
ENV PORT 3000 | ||
|
||
CMD ["node", "server.js"] |