Skip to content

Commit

Permalink
Deploy initContainer for Entity Framework migrations (#1367)
Browse files Browse the repository at this point in the history
* Multistage build for Docker InitContainer
* Updated Container App module to v1.12.0
* Update Docker Build CI workflow to test initContainer
* Build but do not deploy the initContainer
* Correctly handle appsettings overrides
* Move appsettings into ConcernsCaseWork dir
  • Loading branch information
DrizzlyOwl authored Sep 13, 2024
1 parent 8615aa4 commit e6f96ba
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 143 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/build-and-push-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,24 @@ jobs:
deploy-image:
name: Deploy '${{ needs.set-env.outputs.branch }}' to ${{ needs.set-env.outputs.environment }}
needs: [ set-env ]
uses: DFE-Digital/deploy-azure-container-apps-action/.github/workflows/[email protected]
strategy:
matrix:
stage: [
"final",
"initcontainer"
]
include:
- stage: "final"
tag-prefix: ""
- stage: "initcontainer"
tag-prefix: "init-"
uses: DFE-Digital/deploy-azure-container-apps-action/.github/workflows/[email protected]
with:
docker-image-name: 'amsd-app'
docker-build-target: ${{ matrix.stage }}
docker-build-file-name: './Dockerfile'
docker-tag-prefix: ${{ matrix.tag-prefix }}
import-without-deploy: ${{ matrix.stage == 'initcontainer' }}
environment: ${{ needs.set-env.outputs.environment }}
annotate-release: true
docker-build-args: |
Expand Down
25 changes: 0 additions & 25 deletions .github/workflows/docker-build.yml

This file was deleted.

19 changes: 15 additions & 4 deletions .github/workflows/docker-test.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
name: Scan Docker image
name: Run Docker tests

on:
push:
branches: main
pull_request:
paths:
- Dockerfile
types: [opened, synchronize]

jobs:
scan:
runs-on: ubuntu-latest
strategy:
matrix:
stage: [
"final",
"initcontainer"
]
outputs:
image: ${{ steps.build.outputs.imageid }}
steps:
Expand All @@ -16,23 +26,24 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build docker image
- name: Build Docker image
uses: docker/build-push-action@v6
id: build
with:
secrets: github_token=${{ secrets.GITHUB_TOKEN }}
load: true
cache-from: type=gha
cache-to: type=gha
target: ${{ matrix.stage }}
push: false

- name: Export docker image as tar
run: docker save -o ${{ github.ref_name }}.tar ${{ steps.build.outputs.imageid }}
run: docker save -o ${{ matrix.stage }}.tar ${{ steps.build.outputs.imageid }}

- name: Scan Docker image for CVEs
uses: aquasecurity/[email protected]
with:
input: ${{ github.ref_name }}.tar
input: ${{ matrix.stage }}.tar
format: 'sarif'
output: 'trivy-results.sarif'
limit-severities-for-sarif: true
Expand Down
81 changes: 41 additions & 40 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,63 +1,64 @@
# Stage 1
ARG ASPNET_SDK_TAG=8.0
ARG ASPNET_IMAGE_TAG=8.0-bookworm-slim
ARG NODEJS_IMAGE_TAG=20.15-bullseye
ARG COMMIT_SHA=not-set

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS publish

# ==============================================
# Base SDK
# ==============================================
FROM "mcr.microsoft.com/dotnet/sdk:${ASPNET_SDK_TAG}" AS builder
ARG COMMIT_SHA

WORKDIR /build

ENV DEBIAN_FRONTEND=noninteractive

COPY ConcernsCaseWork/. .

RUN dotnet restore ConcernsCaseWork
RUN dotnet build ConcernsCaseWork "/p:customBuildMessage=Manifest commit SHA... ${COMMIT_SHA};" -c Release

RUN dotnet new tool-manifest
RUN dotnet tool install dotnet-ef

RUN mkdir -p /app/SQL
RUN dotnet ef migrations script --output /app/SQL/DbMigrationScript.sql --idempotent -p /build/ConcernsCaseWork.Data
RUN touch /app/SQL/DbMigrationScript.sql /app/SQL/DbMigrationScriptOutput.txt

RUN dotnet publish ConcernsCaseWork -c Release -o /app --no-build
WORKDIR /app
COPY ./script/set-appsettings-release-tag.sh set-appsettings-release-tag.sh
RUN chmod +x ./set-appsettings-release-tag.sh
RUN echo "Setting appsettings releasetag=${COMMIT_SHA}"
RUN ./set-appsettings-release-tag.sh "$COMMIT_SHA"
RUN rm ./set-appsettings-release-tag.sh

COPY ./script/web-docker-entrypoint.sh /app/docker-entrypoint.sh
COPY ./script/set-appsettings-release-tag.sh /app/set-appsettings-release-tag.sh

# Stage 2 - Build assets
FROM node:${NODEJS_IMAGE_TAG} as build
COPY --from=publish /app /app
# ==============================================
# Entity Framework: Migration Builder
# ==============================================
FROM builder AS efbuilder
WORKDIR /build
ENV PATH=$PATH:/root/.dotnet/tools
RUN dotnet tool install --global dotnet-ef
RUN mkdir /sql
RUN dotnet ef migrations bundle -r linux-x64 --configuration Release -p ConcernsCaseWork.Data --no-build -o /sql/migratedb

# ==============================================
# Entity Framework: Migration Runner
# ==============================================
FROM "mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG}" AS initcontainer
WORKDIR /sql
COPY --from=efbuilder /sql /sql
COPY --from=builder /app/appsettings* /ConcernsCaseWork/

# ==============================================
# Front End Builder
# ==============================================
FROM node:${NODEJS_IMAGE_TAG} AS frontend
COPY --from=builder /app/wwwroot /app/wwwroot
WORKDIR /app/wwwroot
RUN npm install
RUN npm run build

# Stage 3 - Final
# ==============================================
# Application
# ==============================================
FROM "mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG}" AS final
LABEL org.opencontainers.image.source=https://github.com/DFE-Digital/record-concerns-support-trusts

ARG COMMIT_SHA

RUN apt-get update
RUN apt-get install unixodbc curl gnupg jq -y
RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
RUN curl https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc
RUN curl https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list

RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql18
RUN ACCEPT_EULA=Y apt-get install -y mssql-tools18

COPY --from=build /app /app
COPY --from=builder /app /app
COPY --from=frontend /app/wwwroot /app/wwwroot
COPY ./script/web-docker-entrypoint.sh /app/docker-entrypoint.sh
WORKDIR /app
RUN chown -R app:app /app
RUN chmod +x ./docker-entrypoint.sh
RUN chmod +x ./set-appsettings-release-tag.sh
RUN echo "Setting appsettings releasetag=${COMMIT_SHA}"
RUN ./set-appsettings-release-tag.sh "$COMMIT_SHA"

RUN chown app:app ./SQL/ -R
USER app
EXPOSE 8080/tcp
2 changes: 2 additions & 0 deletions script/set-appsettings-release-tag.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
set -e
set -o pipefail

apt-get update && apt-get install jq -y

RELEASE_TAG="$1"

APP_SETTINGS_FILES=(
Expand Down
18 changes: 0 additions & 18 deletions script/web-docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,4 @@
set -e
set -o pipefail

ConnectionStrings__DefaultConnection=${ConnectionStrings__DefaultConnection:?}

declare -A mysqlconn

for keyvaluepair in $(echo "$ConnectionStrings__DefaultConnection" | sed "s/ //g; s/;/ /g")
do
IFS=" " read -r -a ARR <<< "${keyvaluepair//=/ }"
mysqlconn[${ARR[0]}]=${ARR[1]}
done

echo "Running database migrations ..."
until /opt/mssql-tools18/bin/sqlcmd -S "${mysqlconn[Server]}" -U "${mysqlconn[UserId]}" -P "${mysqlconn[Password]}" -d "${mysqlconn[Database]}" -C -I -i /app/SQL/DbMigrationScript.sql -o /app/SQL/DbMigrationScriptOutput.txt
do
cat /app/SQL/DbMigrationScriptOutput.txt
echo "Retrying database migrations ..."
sleep 5
done

exec "$@"
92 changes: 41 additions & 51 deletions terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ No providers.

| Name | Source | Version |
|------|--------|---------|
| <a name="module_azure_container_apps_hosting"></a> [azure\_container\_apps\_hosting](#module\_azure\_container\_apps\_hosting) | github.com/DFE-Digital/terraform-azurerm-container-apps-hosting | v1.11.0 |
| <a name="module_azurerm_key_vault"></a> [azurerm\_key\_vault](#module\_azurerm\_key\_vault) | github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars | v0.4.2 |
| <a name="module_azure_container_apps_hosting"></a> [azure\_container\_apps\_hosting](#module\_azure\_container\_apps\_hosting) | github.com/DFE-Digital/terraform-azurerm-container-apps-hosting | v1.12.0 |
| <a name="module_azurerm_key_vault"></a> [azurerm\_key\_vault](#module\_azurerm\_key\_vault) | github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars | v0.5.0 |
| <a name="module_statuscake-tls-monitor"></a> [statuscake-tls-monitor](#module\_statuscake-tls-monitor) | github.com/dfe-digital/terraform-statuscake-tls-monitor | v0.1.4 |

## Resources
Expand Down Expand Up @@ -184,6 +184,7 @@ No resources.
| <a name="input_enable_container_registry"></a> [enable\_container\_registry](#input\_enable\_container\_registry) | Set to true to create a container registry | `bool` | n/a | yes |
| <a name="input_enable_dns_zone"></a> [enable\_dns\_zone](#input\_enable\_dns\_zone) | Conditionally create a DNS zone | `bool` | n/a | yes |
| <a name="input_enable_event_hub"></a> [enable\_event\_hub](#input\_enable\_event\_hub) | Send Azure Container App logs to an Event Hub sink | `bool` | `false` | no |
| <a name="input_enable_init_container"></a> [enable\_init\_container](#input\_enable\_init\_container) | Deploy an Init Container. Init containers run before the primary app container and are used to perform initialization tasks such as downloading data or preparing the environment | `bool` | `false` | no |
| <a name="input_enable_logstash_consumer"></a> [enable\_logstash\_consumer](#input\_enable\_logstash\_consumer) | Create an Event Hub consumer group for Logstash | `bool` | `false` | no |
| <a name="input_enable_monitoring"></a> [enable\_monitoring](#input\_enable\_monitoring) | Create App Insights monitoring groups for the container app | `bool` | n/a | yes |
| <a name="input_enable_mssql_database"></a> [enable\_mssql\_database](#input\_enable\_mssql\_database) | Set to true to create an Azure SQL server/database, with a private endpoint within the virtual network | `bool` | n/a | yes |
Expand All @@ -194,6 +195,8 @@ No resources.
| <a name="input_existing_network_watcher_name"></a> [existing\_network\_watcher\_name](#input\_existing\_network\_watcher\_name) | Use an existing network watcher to add flow logs. | `string` | n/a | yes |
| <a name="input_existing_network_watcher_resource_group_name"></a> [existing\_network\_watcher\_resource\_group\_name](#input\_existing\_network\_watcher\_resource\_group\_name) | Existing network watcher resource group. | `string` | n/a | yes |
| <a name="input_image_name"></a> [image\_name](#input\_image\_name) | Image name | `string` | n/a | yes |
| <a name="input_init_container_command"></a> [init\_container\_command](#input\_init\_container\_command) | Container command for the Init Container | `list(any)` | `[]` | no |
| <a name="input_init_container_image"></a> [init\_container\_image](#input\_init\_container\_image) | Image name for the Init Container. Leave blank to use the same Container image from the primary app | `string` | `""` | no |
| <a name="input_key_vault_access_ipv4"></a> [key\_vault\_access\_ipv4](#input\_key\_vault\_access\_ipv4) | List of IPv4 Addresses that are permitted to access the Key Vault | `list(string)` | n/a | yes |
| <a name="input_monitor_email_receivers"></a> [monitor\_email\_receivers](#input\_monitor\_email\_receivers) | A list of email addresses that will receive alerts from App Insights | `list(string)` | n/a | yes |
| <a name="input_monitor_endpoint_healthcheck"></a> [monitor\_endpoint\_healthcheck](#input\_monitor\_endpoint\_healthcheck) | Specify a route that should be monitored for a 200 OK status | `string` | n/a | yes |
Expand Down
Loading

0 comments on commit e6f96ba

Please sign in to comment.