Skip to content

Commit

Permalink
Switch to Azure Linux base image (#956)
Browse files Browse the repository at this point in the history
- Reduces the overall final image size by using Azure
- Offers maximum compatibility with Azure infrastructure
- Uses arbitrary user instead of 'root'
- Supported by Microsoft
  • Loading branch information
DrizzlyOwl authored Nov 15, 2024
1 parent f49df38 commit 80d93d4
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 84 deletions.
76 changes: 33 additions & 43 deletions Dockerfile.api
Original file line number Diff line number Diff line change
@@ -1,46 +1,36 @@
# Stage 1
ARG ASPNET_IMAGE_TAG=8.0-bookworm-slim
ARG DOTNET_SDK_IMAGE_TAG=8.0

FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_SDK_IMAGE_TAG} AS publish
# Set the major version of dotnet
ARG DOTNET_VERSION=8.0

# Build the app using the dotnet SDK
FROM "mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-azurelinux3.0" AS build
WORKDIR /build

ENV DEBIAN_FRONTEND=noninteractive

COPY Dfe.ManageFreeSchoolProjects/. .

RUN dotnet restore Dfe.ManageFreeSchoolProjects.API
RUN dotnet build Dfe.ManageFreeSchoolProjects.API -c Release

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

RUN mkdir -p /app/SQL
RUN dotnet ef migrations script --output /app/SQL/DbMigrationScript.sql --idempotent -p /build/Dfe.ManageFreeSchoolProjects.Data
RUN touch /app/SQL/DbMigrationScript.sql

RUN dotnet publish Dfe.ManageFreeSchoolProjects.API -c Release -o /app --no-build

COPY ./script/api-docker-entrypoint.sh /app/docker-entrypoint.sh

# Stage 3 - Final
FROM "mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG}" AS final
LABEL org.opencontainers.image.source=https://github.com/DFE-Digital/manage-free-school-projects
LABEL org.opencontainers.image.description="Manage Free School Projects - API"

ENV ASPNETCORE_HTTP_PORTS=80

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 msodbcsql18 mssql-tools18 -y

COPY --from=publish /app /app
COPY ./Dfe.ManageFreeSchoolProjects/ /build
RUN ["dotnet", "restore", "Dfe.ManageFreeSchoolProjects.API"]
RUN ["dotnet", "build", "Dfe.ManageFreeSchoolProjects.API", "--no-restore", "-c", "Release"]
RUN ["dotnet", "publish", "Dfe.ManageFreeSchoolProjects.API", "--no-build", "-o", "/app"]

RUN ["dotnet", "new", "tool-manifest"]
RUN ["dotnet", "tool", "install", "dotnet-ef", "--version", "8.0.11"]
RUN ["mkdir", "-p", "/app/SQL"]
RUN ["dotnet", "restore", "Dfe.ManageFreeSchoolProjects.Data"]
RUN ["dotnet", "build", "Dfe.ManageFreeSchoolProjects.Data", "--no-restore"]
RUN ["dotnet", "ef", "migrations", "script", "--output", "/app/SQL/DbMigrationScript.sql", "--idempotent", "-p", "/build/Dfe.ManageFreeSchoolProjects.Data", "--no-build"]
RUN ["touch", "/app/SQL/DbMigrationScript.sql"]

# Install SQL tools to allow migrations to be run
FROM "mcr.microsoft.com/dotnet/aspnet:${DOTNET_VERSION}-azurelinux3.0" AS base
RUN curl "https://packages.microsoft.com/config/rhel/9/prod.repo" | tee /etc/yum.repos.d/mssql-release.repo
ENV ACCEPT_EULA=Y
RUN ["tdnf", "update"]
RUN ["tdnf", "install", "-y", "mssql-tools18"]
RUN ["tdnf", "clean", "all"]

# Build a runtime environment
FROM base AS runtime
WORKDIR /app
RUN chmod +x ./docker-entrypoint.sh

EXPOSE 80/tcp
LABEL org.opencontainers.image.source="https://github.com/DFE-Digital/manage-free-school-projects"
LABEL org.opencontainers.image.description="Manage Free School Projects - API"
COPY --from=build /app /app
COPY ./script/api-docker-entrypoint.sh /app/docker-entrypoint.sh
RUN ["chmod", "+x", "/app/docker-entrypoint.sh"]
USER $APP_UID
65 changes: 24 additions & 41 deletions Dockerfile.web
Original file line number Diff line number Diff line change
@@ -1,47 +1,30 @@
# Stage 1
ARG ASPNET_IMAGE_TAG=8.0-bookworm-slim
ARG DOTNET_SDK_IMAGE_TAG=8.0
ARG NODEJS_IMAGE_TAG=20.15-bullseye
# Set the major version of dotnet
ARG DOTNET_VERSION=8.0
# Set the major version of nodejs
ARG NODEJS_VERSION_MAJOR=22

FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_SDK_IMAGE_TAG} AS publish

WORKDIR /build

ENV DEBIAN_FRONTEND=noninteractive

COPY Dfe.ManageFreeSchoolProjects/. .

RUN dotnet restore Dfe.ManageFreeSchoolProjects
RUN dotnet build Dfe.ManageFreeSchoolProjects -c Release
RUN dotnet publish Dfe.ManageFreeSchoolProjects -c Release -o /app --no-build

COPY ./script/web-docker-entrypoint.sh /app/docker-entrypoint.sh

# Stage 2 - Build assets
FROM node:${NODEJS_IMAGE_TAG} as build
COPY --from=publish /app /app
WORKDIR /app/wwwroot
# Build frontend assets using node js
FROM "node:${NODEJS_VERSION_MAJOR}-bullseye-slim" AS assets
WORKDIR /app
COPY ./Dfe.ManageFreeSchoolProjects/Dfe.ManageFreeSchoolProjects/wwwroot /app
RUN npm install
RUN npm run build

# Stage 3 - Final
FROM "mcr.microsoft.com/dotnet/aspnet:${ASPNET_IMAGE_TAG}" AS final
LABEL org.opencontainers.image.source=https://github.com/DFE-Digital/manage-free-school-projects
LABEL org.opencontainers.image.description="Manage Free School Projects - App"

ARG COMMIT_SHA
ENV ASPNETCORE_HTTP_PORTS=80

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 msodbcsql18 mssql-tools18 -y
# Build the app using the dotnet SDK
FROM "mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-azurelinux3.0" AS build
WORKDIR /build
COPY ./Dfe.ManageFreeSchoolProjects/ /build
RUN ["dotnet", "restore", "Dfe.ManageFreeSchoolProjects"]
RUN ["dotnet", "build", "Dfe.ManageFreeSchoolProjects", "--no-restore", "-c", "Release"]
RUN ["dotnet", "publish", "Dfe.ManageFreeSchoolProjects", "--no-build", "-o", "/app"]

COPY --from=build /app /app
# Build a runtime environment
FROM "mcr.microsoft.com/dotnet/aspnet:${DOTNET_VERSION}-azurelinux3.0" AS runtime
WORKDIR /app
RUN chmod +x ./docker-entrypoint.sh

EXPOSE 80/tcp
LABEL org.opencontainers.image.source="https://github.com/DFE-Digital/manage-free-school-projects"
LABEL org.opencontainers.image.description="Manage Free School Projects - App"
COPY --from=build /app /app
COPY --from=assets /app /app/wwwroot
COPY ./script/web-docker-entrypoint.sh /app/docker-entrypoint.sh
RUN ["chmod", "+x", "/app/docker-entrypoint.sh"]
USER $APP_UID
1 change: 1 addition & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ No resources.
| <a name="input_container_command"></a> [container\_command](#input\_container\_command) | Container command | `list(any)` | n/a | yes |
| <a name="input_container_health_probe_path"></a> [container\_health\_probe\_path](#input\_container\_health\_probe\_path) | Specifies the path that is used to determine the liveness of the Container | `string` | n/a | yes |
| <a name="input_container_min_replicas"></a> [container\_min\_replicas](#input\_container\_min\_replicas) | Container min replicas | `number` | `1` | no |
| <a name="input_container_port"></a> [container\_port](#input\_container\_port) | Container port | `number` | `8080` | no |
| <a name="input_container_scale_http_concurrency"></a> [container\_scale\_http\_concurrency](#input\_container\_scale\_http\_concurrency) | When the number of concurrent HTTP requests exceeds this value, then another replica is added. Replicas continue to add to the pool up to the max-replicas amount. | `number` | `10` | no |
| <a name="input_container_secret_environment_variables"></a> [container\_secret\_environment\_variables](#input\_container\_secret\_environment\_variables) | Container secret environment variables | `map(string)` | n/a | yes |
| <a name="input_custom_container_apps"></a> [custom\_container\_apps](#input\_custom\_container\_apps) | Custom container apps, by default deployed within the container app environment managed by this module. | <pre>map(object({<br/> container_app_environment_id = optional(string, "")<br/> resource_group_name = optional(string, "")<br/> revision_mode = optional(string, "Single")<br/> container_port = optional(number, 0)<br/> ingress = optional(object({<br/> external_enabled = optional(bool, true)<br/> target_port = optional(number, null)<br/> traffic_weight = object({<br/> percentage = optional(number, 100)<br/> })<br/> cdn_frontdoor_custom_domain = optional(string, "")<br/> cdn_frontdoor_origin_fqdn_override = optional(string, "")<br/> cdn_frontdoor_origin_host_header_override = optional(string, "")<br/> enable_cdn_frontdoor_health_probe = optional(bool, false)<br/> cdn_frontdoor_health_probe_protocol = optional(string, "")<br/> cdn_frontdoor_health_probe_interval = optional(number, 120)<br/> cdn_frontdoor_health_probe_request_type = optional(string, "")<br/> cdn_frontdoor_health_probe_path = optional(string, "")<br/> cdn_frontdoor_forwarding_protocol_override = optional(string, "")<br/> }), null)<br/> identity = optional(list(object({<br/> type = string<br/> identity_ids = list(string)<br/> })), [])<br/> secrets = optional(list(object({<br/> name = string<br/> value = string<br/> })), [])<br/> registry = object({<br/> server = optional(string, "")<br/> username = optional(string, "")<br/> password_secret_name = optional(string, "")<br/> identity = optional(string, "")<br/> }),<br/> image = string<br/> cpu = number<br/> memory = number<br/> command = list(string)<br/> liveness_probes = optional(list(object({<br/> interval_seconds = number<br/> transport = string<br/> port = number<br/> path = optional(string, null)<br/> })), [])<br/> env = optional(list(object({<br/> name = string<br/> value = optional(string, null)<br/> secretRef = optional(string, null)<br/> })), [])<br/> min_replicas = number<br/> max_replicas = number<br/> }))</pre> | `{}` | no |
Expand Down
1 change: 1 addition & 0 deletions terraform/container-apps-hosting.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module "azure_container_apps_hosting" {
container_secret_environment_variables = local.container_secret_environment_variables
container_scale_http_concurrency = local.container_scale_http_concurrency
container_min_replicas = local.container_min_replicas
container_port = local.container_port
enable_health_insights_api = local.enable_health_insights_api
health_insights_api_cors_origins = local.health_insights_api_cors_origins
health_insights_api_ipv4_allow_list = local.health_insights_api_ipv4_allow_list
Expand Down
1 change: 1 addition & 0 deletions terraform/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ locals {
container_secret_environment_variables = var.container_secret_environment_variables
container_scale_http_concurrency = var.container_scale_http_concurrency
container_min_replicas = var.container_min_replicas
container_port = var.container_port
enable_event_hub = var.enable_event_hub
enable_logstash_consumer = var.enable_logstash_consumer
eventhub_export_log_analytics_table_names = var.eventhub_export_log_analytics_table_names
Expand Down
6 changes: 6 additions & 0 deletions terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,9 @@ variable "health_insights_api_ipv4_allow_list" {
type = list(string)
default = []
}

variable "container_port" {
description = "Container port"
type = number
default = 8080
}

0 comments on commit 80d93d4

Please sign in to comment.