diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51651ed..9329c26 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,15 +23,20 @@ jobs: if: startsWith(github.ref, 'refs/heads/deploy/') outputs: skip_build: ${{ steps.retag.outputs.skip_build }} + permissions: + id-token: write + contents: read container: docker:stable-git runs-on: ubuntu-latest steps: + - name: Configure AWS credentials for ECR + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.ECR_IAM_ROLE }} + aws-region: ${{ env.AWS_REGION }} - name: Login to Amazon ECR id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + uses: aws-actions/amazon-ecr-login@v2 - name: Retag images with Skopeo id: retag run: | @@ -56,7 +61,6 @@ jobs: echo "skip_build=false" >> $GITHUB_OUTPUT fi - # This job heavily relies on Docker layer caching to make it as fast as possible # It builds the app-test stage first, and tests it, # and only after that builds the rest of the stuff and pushes it to ECR @@ -65,17 +69,25 @@ jobs: # builds the image if the previous job didn't fail and didn't indicate # that this one should be skipped if: ${{ !failure() && (needs.retag-images.outputs.skip_build!='true')}} - needs: [ retag-images ] + needs: [retag-images] + permissions: + id-token: write + contents: read container: docker:stable-git runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 with: - version: v0.6.3 - driver-opts: image=moby/buildkit:v0.11.5 + driver-opts: image=moby/buildkit:v0.26.3 + - name: configure AWS for s3 Docker cache + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.REGISTRY_IAM_ROLE }} + role-session-name: s3 + aws-region: ${{ env.AWS_REGION }} - name: Set dynamic env vars run: | docker version @@ -83,14 +95,18 @@ jobs: echo "VERSION=${SHORT_COMMIT}" >> $GITHUB_ENV echo "DATABASE_PASSWORD=$( head -c 24 /dev/urandom | xxd -p | tr -d '\n ')" >> $GITHUB_ENV echo "ENVIRONMENT=$(basename $GITHUB_REF)" >> $GITHUB_ENV + echo "CACHE=type=s3,region=${{ env.AWS_REGION }},bucket=${{ secrets.REGISTRY_BUCKET_NAME }}" >> $GITHUB_ENV - name: Build test containers - uses: docker/bake-action@v5.11.0 + uses: docker/bake-action@v6 env: - CACHE: type=s3,region=${{ env.AWS_REGION }},bucket=${{ secrets.REGISTRY_BUCKET_NAME }},access_key_id=${{ secrets.REGISTRY_AWS_ACCESS_KEY_ID }},secret_access_key=${{ secrets.REGISTRY_AWS_SECRET_ACCESS_KEY }} + CACHE: ${{ env.CACHE }} + DOCKER_BUILD_RECORD_UPLOAD: "false" with: + source: . files: docker-bake.hcl targets: app-test load: true + provenance: false - name: Test app run: | # there's some limitation on the hostname length @@ -124,41 +140,68 @@ jobs: ${{ env.PROJECT }}/app-test:${{ env.VERSION }} \ ./manage.py makemigrations --check --dry-run + # Configure ECR role and login (token stored in Docker config) + - name: Configure AWS credentials for ECR + if: startsWith(github.ref, 'refs/heads/deploy/') + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.ECR_IAM_ROLE }} + aws-region: ${{ env.AWS_REGION }} - name: Login to Amazon ECR if: startsWith(github.ref, 'refs/heads/deploy/') id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + uses: aws-actions/amazon-ecr-login@v2 + # Reconfigure S3 cache role for Docker build (ECR push uses token from login step) + - name: configure AWS for s3 Docker cache + if: startsWith(github.ref, 'refs/heads/deploy/') + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.REGISTRY_IAM_ROLE }} + role-session-name: s3 + aws-region: ${{ env.AWS_REGION }} + - name: Update CACHE env var for deploy build + if: startsWith(github.ref, 'refs/heads/deploy/') + run: | + echo "CACHE=type=s3,region=${{ env.AWS_REGION }},bucket=${{ secrets.REGISTRY_BUCKET_NAME }}" >> $GITHUB_ENV - name: Build all other app parts and push to ECR if: startsWith(github.ref, 'refs/heads/deploy/') env: REGISTRY: ${{ steps.login-ecr.outputs.registry }} - CACHE: type=s3,region=${{ env.AWS_REGION }},bucket=${{ secrets.REGISTRY_BUCKET_NAME }},access_key_id=${{ secrets.REGISTRY_AWS_ACCESS_KEY_ID }},secret_access_key=${{ secrets.REGISTRY_AWS_SECRET_ACCESS_KEY }} - uses: docker/bake-action@v5.11.0 + CACHE: ${{ env.CACHE }} + DOCKER_BUILD_RECORD_UPLOAD: "false" + uses: docker/bake-action@v6 with: + source: . files: docker-bake.hcl targets: default - # makes it push to the registry push: true + provenance: false deploy: - needs: [ build-and-test, retag-images ] + needs: [build-and-test, retag-images] if: startsWith(github.ref, 'refs/heads/deploy/') && !failure() + permissions: + id-token: write + contents: read container: docker:stable-git runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 + # TODO: Update deploy-user module to support OIDC role creation + # For now, using access keys (created by deploy-user module) + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} - name: Download ecs-tool run: | - wget -O ecs-tool.tar.gz https://github.com/springload/ecs-tool/releases/download/v1.9.9-beta/ecs-tool_1.9.9-beta_linux_amd64.tar.gz && tar -C /usr/bin -xvf ecs-tool.tar.gz ecs-tool + wget -O ecs-tool.tar.gz https://github.com/springload/ecs-tool/releases/download/v1.9.9-beta/ecs-tool_1.9.9-beta_linux_amd64.tar.gz && tar -C /usr/bin -xvf ecs-tool.tar.gz ecs-tool - name: Deploy app env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} EJSON_PRIVATE: ${{ secrets.EJSON_PRIVATE }} run: |- set -eu diff --git a/docker-bake.hcl b/docker-bake.hcl index 7507717..038a135 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,5 +1,7 @@ // this is registry used for caching purposes only variable "CACHE_REGISTRY" { default = "" } +// this is cache definition used for caching purposes only +variable "CACHE" { default = "" } // this is remote registry to push to variable "REGISTRY" { default = "" } variable "ENVIRONMENT" { default = "preview" } @@ -14,15 +16,15 @@ group "default" { target "base" { dockerfile = "docker/application/Dockerfile" target = "base" - cache-from = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/base:${VERSION}", "type=registry,ref=${CACHE_REGISTRY}/base:cache"] : [] - cache-to = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/base:cache,mode=max"] : [] + cache-from = notequal("", CACHE) ? ["${CACHE},name=base"] : [] + cache-to = notequal("", CACHE) ? ["${CACHE},mode=max,name=base"] : [] } target "app" { dockerfile = "docker/application/Dockerfile" target = "app" - cache-from = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/app:${VERSION}", "type=registry,ref=${CACHE_REGISTRY}/app:cache"] : [] - cache-to = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/app:cache,mode=max"] : [] + cache-from = notequal("", CACHE) ? ["${CACHE},name=app"] : [] + cache-to = notequal("", CACHE) ? ["${CACHE},mode=max,name=app"] : [] args = { VERSION : VERSION, @@ -38,8 +40,8 @@ target "app" { target "app-test" { dockerfile = "docker/application/Dockerfile" target = "app-test" - cache-from = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/app-test:${VERSION}", "type=registry,ref=${CACHE_REGISTRY}/app-test:cache"] : [] - cache-to = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/app-test:cache,mode=max"] : [] + cache-from = notequal("", CACHE) ? ["${CACHE},name=app-test", "${CACHE},name=base"] : [] + cache-to = notequal("", CACHE) ? ["${CACHE},mode=max,name=app-test"] : [] args = { VERSION : VERSION, @@ -52,8 +54,8 @@ target "app-test" { target "tasks" { dockerfile = "docker/application/Dockerfile" target = "tasks" - cache-from = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/tasks:${VERSION}", "type=registry,ref=${CACHE_REGISTRY}/tasks:cache"] : [] - cache-to = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/tasks:cache,mode=max"] : [] + cache-from = notequal("", CACHE) ? ["${CACHE},name=tasks"] : [] + cache-to = notequal("", CACHE) ? ["${CACHE},mode=max,name=tasks"] : [] args = { VERSION : VERSION, @@ -69,8 +71,8 @@ target "tasks" { target "httpd" { context = "docker/httpd" - cache-from = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/httpd:${ENVIRONMENT}-${VERSION}", "type=registry,ref=${CACHE_REGISTRY}/httpd:cache"] : [] - cache-to = notequal("", CACHE_REGISTRY) ? ["type=registry,ref=${CACHE_REGISTRY}/httpd:cache,mode=max"] : [] + cache-from = notequal("", CACHE) ? ["${CACHE},name=httpd"] : [] + cache-to = notequal("", CACHE) ? ["${CACHE},mode=max,name=httpd"] : [] args = { VERSION : VERSION,