Squidex v7 build for ARM

I managed to build Squidex v7 for both AMD and ARM. Would appreciate if someone can check it out a verify that it works. Tried to build on both windows and mac and seems to work fine.

Dockerfile:

ARG SQUIDEX_TAG=
ARG SQUIDEX_FRONTEND_TAG=

## Backend build env
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 as backend-build
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG SQUIDEX_TAG
SHELL ["/bin/bash", "-c"]
WORKDIR /

COPY ./dotnet_rdi_translator.sh ./dotnet_rdi_translator.sh

RUN git clone --depth 1 --branch $SQUIDEX_TAG https://github.com/Squidex/squidex.git

RUN source /dotnet_rdi_translator.sh ${TARGETPLATFORM} && \
    dotnet publish /squidex/backend/src/Squidex/Squidex.csproj \
        -c Release \
        -r $DOTNET_RUNTIME \
        --self-contained \
        -p:PublishSingleFile=true \
        -p:version=$SQUIDEX_TAG \
        -o /publish/


## Build Frontend
# NOTE: Use TARGETPLATFORM to ensure npm install is done for expected TARGET (e.g. linux/arm64).
# TODO: Is this needed, or can it be done any other way?
FROM --platform=$TARGETPLATFORM squidex/frontend-build:$SQUIDEX_FRONTEND_TAG as frontend-build
ARG TARGETPLATFORM
ARG SQUIDEX_FRONTEND_TAG
WORKDIR /
ENV CONTINUOUS_INTEGRATION=1

# Copy frontend from backend-env stage, so we don't have to install git and clone repository again.
# TODO: Any more efficient way of doing this?
COPY --from=backend-build /squidex/frontend/package*.json /squidex/frontend/

RUN cd /squidex/frontend/ && \
    npm install --loglevel=error --force

COPY --from=backend-build /squidex/frontend/ /squidex/frontend/

RUN cd /squidex/frontend/ && \
    npm run test:coverage && \
    npm run build

RUN cp -a /squidex/frontend/build /build/

## Runtime env
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine as runtime
ARG TARGETPLATFORM
ARG SQUIDEX_TAG
WORKDIR /app
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false

RUN apk add icu

# Copy from build stages
COPY --from=backend-build /publish/ /app/
COPY --from=frontend-build /build/ /app/wwwroot/build/

EXPOSE 80
EXPOSE 443

ENTRYPOINT ["/app/Squidex"]

ENV EXPOSEDCONFIGURATION__VERSION=$SQUIDEX_TAG

dotnet_rdi_translator:

#!/bin/sh

# Takes the provided first argument and translates docker platform to dotnet runtime identifier (rid)
case "$1" in
	"linux/amd64") DOTNET_RUNTIME="linux-musl-x64" ;;
	"linux/arm64") DOTNET_RUNTIME="linux-musl-arm64" ;;
	*) DOTNET_RUNTIME="$1"
esac

export DOTNET_RUNTIME

DockerCompose for ARM:

version: "3.5"
services:
  squidex_mongo:
    image: "mongo:6"
    volumes:
      - /etc/squidex/mongo/db:/data/db
    networks:
      - internal
    restart: unless-stopped

  squidex_squidex:
    image: "squid/squidex:7.8.2-arm64"
    environment:
      - URLS__BASEURL=https://${SQUIDEX_DOMAIN}:8443
      - EVENTSTORE__TYPE=MongoDB
      - EVENTSTORE__MONGODB__CONFIGURATION=mongodb://squidex_mongo
      - STORE__MONGODB__CONFIGURATION=mongodb://squidex_mongo
      - IDENTITY__ADMINEMAIL=${SQUIDEX_ADMINEMAIL}
      - IDENTITY__ADMINPASSWORD=${SQUIDEX_ADMINPASSWORD}
      - IDENTITY__GOOGLECLIENT=${SQUIDEX_GOOGLECLIENT}
      - IDENTITY__GOOGLESECRET=${SQUIDEX_GOOGLESECRET}
      - IDENTITY__GITHUBCLIENT=${SQUIDEX_GITHUBCLIENT}
      - IDENTITY__GITHUBSECRET=${SQUIDEX_GITHUBSECRET}
      - IDENTITY__MICROSOFTCLIENT=${SQUIDEX_MICROSOFTCLIENT}
      - IDENTITY__MICROSOFTSECRET=${SQUIDEX_MICROSOFTSECRET}
      - ASPNETCORE_URLS=http://+:8443
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8443/healthz"]
      start_period: 60s
    depends_on:
      - squidex_mongo
    volumes:
      - /etc/squidex/assets:/app/Assets
    networks:
      - internal
    restart: unless-stopped

  squidex_proxy:
    image: squidex/caddy-proxy
    ports:
      - "8080:80"
      - "8443:443"
    environment:
      - SITE_ADDRESS=${SQUIDEX_DOMAIN}
      - SITE_SERVER="squidex_squidex:8443"
    volumes:
      - /etc/squidex/caddy/data:/data
      - /etc/squidex/caddy/config:/config
    depends_on:
      - squidex_squidex
    networks:
      - internal
    restart: unless-stopped
    
networks:
  internal:
    driver: bridge

DockerCompose for AMD:

version: "3.5"
services:
  squidex_mongo:
    image: "mongo:6"
    volumes:
      - /etc/squidex/mongo/db:/data/db
    networks:
      - internal
    restart: unless-stopped

  squidex_squidex:
    image: "squid/squidex:7.8.2-amd64"
    environment:
      - URLS__BASEURL=https://${SQUIDEX_DOMAIN}:8443
      - EVENTSTORE__TYPE=MongoDB
      - EVENTSTORE__MONGODB__CONFIGURATION=mongodb://squidex_mongo
      - STORE__MONGODB__CONFIGURATION=mongodb://squidex_mongo
      - IDENTITY__ADMINEMAIL=${SQUIDEX_ADMINEMAIL}
      - IDENTITY__ADMINPASSWORD=${SQUIDEX_ADMINPASSWORD}
      - IDENTITY__GOOGLECLIENT=${SQUIDEX_GOOGLECLIENT}
      - IDENTITY__GOOGLESECRET=${SQUIDEX_GOOGLESECRET}
      - IDENTITY__GITHUBCLIENT=${SQUIDEX_GITHUBCLIENT}
      - IDENTITY__GITHUBSECRET=${SQUIDEX_GITHUBSECRET}
      - IDENTITY__MICROSOFTCLIENT=${SQUIDEX_MICROSOFTCLIENT}
      - IDENTITY__MICROSOFTSECRET=${SQUIDEX_MICROSOFTSECRET}
      - ASPNETCORE_URLS=http://+:8443
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8443/healthz"]
      start_period: 60s
    depends_on:
      - squidex_mongo
    volumes:
      - /etc/squidex/assets:/app/Assets
    networks:
      - internal
    restart: unless-stopped

  squidex_proxy:
    image: squidex/caddy-proxy
    ports:
      - "8080:80"
      - "8443:443"
    environment:
      - SITE_ADDRESS=${SQUIDEX_DOMAIN}
      - SITE_SERVER="squidex_squidex:8443"
    volumes:
      - /etc/squidex/caddy/data:/data
      - /etc/squidex/caddy/config:/config
    depends_on:
      - squidex_squidex
    networks:
      - internal
    restart: unless-stopped
    
networks:
  internal:
    driver: bridge

build.sh:

#!/bin/sh

SQUIDEX_TAG=7.8.2
SQUIDEX_FRONTEND_TAG=18.10

# Build and tag multi-platform
docker buildx build --platform linux/amd64,linux/arm64 --build-arg "SQUIDEX_TAG=$SQUIDEX_TAG" --build-arg "SQUIDEX_FRONTEND_TAG=$SQUIDEX_FRONTEND_TAG" -t squid/squidex:${SQUIDEX_TAG} .

# Build and tag amd64 only. This will be quick, since all amd64 layers has already been built locally.
docker buildx build --load --platform linux/amd64 --build-arg "SQUIDEX_TAG=$SQUIDEX_TAG" --build-arg "SQUIDEX_FRONTEND_TAG=$SQUIDEX_FRONTEND_TAG" -t squid/squidex:$SQUIDEX_TAG-amd64 .

# Build and tag arm64 only. This will be quick, since all arm64 layers has already been built locally.
docker buildx build --load --platform linux/arm64 --build-arg "SQUIDEX_TAG=$SQUIDEX_TAG" --build-arg "SQUIDEX_FRONTEND_TAG=$SQUIDEX_FRONTEND_TAG" -t squid/squidex:$SQUIDEX_TAG-arm64 .

2 Likes

A few comments from my side:

  1. Why do you clone in the Dockerfile?
  2. Do you know if self publishing has any advantages here?
  3. I think with .NET 8 the RID translation is probably not needed anymore.
  1. Why do you clone in the Dockerfile?
    → I don’t want to create a fork. All of this is only a test. What we like is an official arm image that we can deploy. We don’t want to maintain our own arm image.

  2. Do you know if self publishing has any advantages here?
    → Unclear. Might give the ability to use a slimmer base image

  3. I think with .NET 8 the RID translation is probably not needed anymore.

Ideally I would like to have a multi architecture image, so that you only have one image to deploy. But if this does not work, your solution would work as well IF we could integrate it in github actions. Therefore I recommend to fork the repository, and create a PR if everything works as expected.