diff --git a/.github/workflows/deploy_to_development.yml b/.github/workflows/deploy_to_development.yml new file mode 100644 index 0000000..e4211f7 --- /dev/null +++ b/.github/workflows/deploy_to_development.yml @@ -0,0 +1,92 @@ +name: Deploy to development (reusable) + +# Composes build_and_publish_docker_image_to_container_registry.yml and +# update_kubernetes_deployment.yml into a "publish short-sha image and +# update development kustomize overlay" pipeline. +# +# Scope: single-image services deploying via kustomize to an equinor +# infrastructure repository. + +on: + workflow_call: + inputs: + registry: + description: "Container registry for development images." + required: true + type: string + image_name: + description: "Image name (e.g. robotics/sara-anonymizer)." + required: true + type: string + infrastructure_repository: + description: "Target infrastructure repository (kustomize)." + required: true + type: string + path_to_dockerfile: + required: false + type: string + default: "Dockerfile" + path_to_context: + required: false + type: string + default: "." + environment_name: + description: "Optional GitHub Environment to gate the deploy on (e.g. 'Development'). Leave empty to disable the gate." + required: false + type: string + default: "" + secrets: + registry_username: + required: true + registry_password: + required: true + deploy_key: + description: "SSH deploy key for the infrastructure repository." + required: true + +permissions: + contents: read + packages: write + +jobs: + get-short-sha: + name: Compute short-sha tag + runs-on: ubuntu-latest + environment: ${{ inputs.environment_name }} + outputs: + tag: ${{ steps.get-tag.outputs.tag }} + steps: + - id: get-tag + run: echo "tag=dev.$(echo ${{ github.sha }} | cut -c1-8)" >> "$GITHUB_OUTPUT" + + publish: + name: Build and publish image + needs: get-short-sha + permissions: + contents: read + packages: write + uses: ./.github/workflows/build_and_publish_docker_image_to_container_registry.yml + with: + registry: ${{ inputs.registry }} + image_name: ${{ inputs.image_name }} + tag: ${{ needs.get-short-sha.outputs.tag }} + path_to_dockerfile: ${{ inputs.path_to_dockerfile }} + path_to_context: ${{ inputs.path_to_context }} + secrets: + registry_username: ${{ secrets.registry_username }} + registry_password: ${{ secrets.registry_password }} + + deploy: + name: Update deployment in development + needs: [publish, get-short-sha] + uses: ./.github/workflows/update_kubernetes_deployment.yml + with: + environment: development + registry: ${{ inputs.registry }} + image_name: ${{ inputs.image_name }} + tag: ${{ needs.get-short-sha.outputs.tag }} + author_email: ${{ github.event.head_commit.author.email }} + author_name: ${{ github.event.head_commit.author.name }} + infrastructure_repository: ${{ inputs.infrastructure_repository }} + secrets: + deploy_key: ${{ secrets.deploy_key }} diff --git a/.github/workflows/deploy_to_staging.yml b/.github/workflows/deploy_to_staging.yml new file mode 100644 index 0000000..b5b52bf --- /dev/null +++ b/.github/workflows/deploy_to_staging.yml @@ -0,0 +1,81 @@ +name: Deploy to staging (reusable) + +# Composes build_and_publish_docker_image_to_container_registry.yml and +# update_kubernetes_deployment.yml into a "publish release image and +# update staging kustomize overlay" pipeline. +# +# Scope: single-image services deploying via kustomize to an equinor +# infrastructure repository. Publishes both `:` and `:latest`. + +on: + workflow_call: + inputs: + registry: + description: "Container registry for staging images." + required: true + type: string + image_name: + description: "Image name (e.g. robotics/sara-anonymizer)." + required: true + type: string + tag: + description: "Release tag to publish and deploy." + required: true + type: string + infrastructure_repository: + required: true + type: string + author_name: + required: true + type: string + path_to_dockerfile: + required: false + type: string + default: "Dockerfile" + path_to_context: + required: false + type: string + default: "." + secrets: + registry_username: + required: true + registry_password: + required: true + deploy_key: + required: true + +permissions: + contents: read + packages: write + +jobs: + publish: + name: Build and publish image + permissions: + contents: read + packages: write + uses: ./.github/workflows/build_and_publish_docker_image_to_container_registry.yml + with: + registry: ${{ inputs.registry }} + image_name: ${{ inputs.image_name }} + tag: ${{ inputs.tag }} + secondary_tag: latest + path_to_dockerfile: ${{ inputs.path_to_dockerfile }} + path_to_context: ${{ inputs.path_to_context }} + secrets: + registry_username: ${{ secrets.registry_username }} + registry_password: ${{ secrets.registry_password }} + + deploy: + name: Update deployment in staging + needs: publish + uses: ./.github/workflows/update_kubernetes_deployment.yml + with: + environment: staging + registry: ${{ inputs.registry }} + image_name: ${{ inputs.image_name }} + tag: ${{ inputs.tag }} + author_name: ${{ inputs.author_name }} + infrastructure_repository: ${{ inputs.infrastructure_repository }} + secrets: + deploy_key: ${{ secrets.deploy_key }} diff --git a/.github/workflows/promote_to_production.yml b/.github/workflows/promote_to_production.yml new file mode 100644 index 0000000..adc84a6 --- /dev/null +++ b/.github/workflows/promote_to_production.yml @@ -0,0 +1,116 @@ +name: Promote to production (reusable) + +# Reusable "promote to production" workflow. +# +# Reads the tag currently deployed to staging from the infrastructure +# repository's kustomization, copies that image from the staging registry +# to the production registry (both `:tag` and `:latest`), and updates the +# production deployment. + +on: + workflow_call: + inputs: + image_name: + description: "Image name, e.g. robotics/sara-anonymizer." + required: true + type: string + staging_registry: + required: true + type: string + production_registry: + required: true + type: string + infrastructure_repository: + required: true + type: string + author_name: + required: true + type: string + secrets: + staging_registry_username: + required: true + staging_registry_password: + required: true + production_registry_username: + required: true + production_registry_password: + required: true + deploy_key: + required: true + +permissions: + contents: read + packages: write + +jobs: + get-staging-version: + name: Get version currently in staging + runs-on: ubuntu-latest + outputs: + version_tag: ${{ steps.get.outputs.tag }} + steps: + - name: Checkout infrastructure + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6 + with: + ref: main + repository: ${{ inputs.infrastructure_repository }} + ssh-key: ${{ secrets.deploy_key }} + + - name: Read staging tag from kustomization + id: get + run: | + KUSTOMIZATION=k8s_kustomize/overlays/staging/kustomization.yaml + IMAGE_LINE=$(grep -n "newName: ${{ inputs.staging_registry }}/${{ inputs.image_name }}$" "$KUSTOMIZATION" | cut -d: -f1) + if [ -z "$IMAGE_LINE" ]; then + echo "Error: image ${{ inputs.staging_registry }}/${{ inputs.image_name }} not found in $KUSTOMIZATION" + exit 1 + fi + TAG_LINE=$((IMAGE_LINE + 1)) + VERSION_TAG=$(sed -n "${TAG_LINE}p" "$KUSTOMIZATION" | awk -F': ' '{print $2}' | tr -d ' ') + if [ -z "$VERSION_TAG" ]; then + echo "Error: could not parse newTag on line ${TAG_LINE} of $KUSTOMIZATION" + exit 1 + fi + echo "tag=$VERSION_TAG" >> "$GITHUB_OUTPUT" + + copy-image-to-production: + name: Copy staging image to production registry + needs: get-staging-version + runs-on: ubuntu-latest + steps: + - name: Log in to staging registry + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4 + with: + registry: ${{ inputs.staging_registry }} + username: ${{ secrets.staging_registry_username }} + password: ${{ secrets.staging_registry_password }} + + - name: Log in to production registry + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 #v4 + with: + registry: ${{ inputs.production_registry }} + username: ${{ secrets.production_registry_username }} + password: ${{ secrets.production_registry_password }} + + - name: Copy image (tag + latest) from staging to production + env: + TAG: ${{ needs.get-staging-version.outputs.version_tag }} + run: | + docker buildx imagetools create \ + --tag ${{ inputs.production_registry }}/${{ inputs.image_name }}:${TAG} \ + --tag ${{ inputs.production_registry }}/${{ inputs.image_name }}:latest \ + ${{ inputs.staging_registry }}/${{ inputs.image_name }}:${TAG} + + deploy: + name: Update deployment in production + needs: [get-staging-version, copy-image-to-production] + uses: ./.github/workflows/update_kubernetes_deployment.yml + with: + environment: production + registry: ${{ inputs.production_registry }} + image_name: ${{ inputs.image_name }} + tag: ${{ needs.get-staging-version.outputs.version_tag }} + author_name: ${{ inputs.author_name }} + infrastructure_repository: ${{ inputs.infrastructure_repository }} + secrets: + deploy_key: ${{ secrets.deploy_key }}