Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cross-compilation in the Docker build #3

Merged
merged 1 commit into from
Feb 14, 2024

Conversation

baronfel
Copy link
Contributor

The reason the app wasn't launching on arm64 was because the base image (which the final image was based off of) was using the host's platform. Instead, you want the platform of the target, which you get for free if you don't specify a --platform argument for the FROM command.

Here's it working while emulating arm64 on my amd64 desktop:

image

@LanceMcCarthy LanceMcCarthy merged commit db5e9d5 into LanceMcCarthy:main Feb 14, 2024
1 check passed
@LanceMcCarthy
Copy link
Owner

Attempting new build after reverting back to the original setup.

@baronfel
Copy link
Contributor Author

I made an optimization pass at your dockerfile as well if you'd like to take a look at that: baronfel#1

@LanceMcCarthy
Copy link
Owner

LanceMcCarthy commented Feb 14, 2024

Aha, I never explicitly defined the parameters as ARG, so that's why they failed.

Here's the original reason why I started messing with the dockerfile, it fixed the failed arm64 dotnet restore when in GitHub Actions NuGet/Home#12227 (comment)

@LanceMcCarthy
Copy link
Owner

@baronfel Failed https://github.com/LanceMcCarthy/akeyless-web-target/actions/runs/7904655228/job/21575467038#step:9:331

But I think it was just a syntax issue with the variable in the dotnet publish command, The It fails due to the fact that $TARGETARCH is outputting as the correct value if I echo it.

running a new build now, using quotes and brackets --arch "${TARGETARCH}"

@LanceMcCarthy
Copy link
Owner

The command looks good now, but MSBuild doesnt like it

#20 [linux/amd64 build 6/6] RUN dotnet publish './SecretsMocker.csproj'-c Release -o /app/publish /p:UseAppHost=false --self-contained false --arch "amd64"
#20 0.978 MSBUILD : error MSB1008: Only one project can be specified.

@baronfel
Copy link
Contributor Author

Left a comment on the commit directly, but you can remove -c Release entirely - the pack and publish commands are Release-by-default in .NET 8+.

@LanceMcCarthy
Copy link
Owner

LanceMcCarthy commented Feb 14, 2024

The build is fixed, but when I deployed it, it looks liek we messed with the entrypoint to much:

Here's the Docker error when I deploy the container
failed to deploy a stack: Container dyn-secrets-stack-app-1 Recreate Container dyn-secrets-stack-app-1 Recreated Container dyn-secrets-stack-app-1 Starting Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "./SecretsMocker": stat ./SecretsMocker: no such file or directory: unknown

@baronfel
Copy link
Contributor Author

oh, that's because you put UseAppHost=false back after I removed it. you either need to keep the app hosts and the Entrypoint change I made, or revert the EntryPoint change I made.

@baronfel
Copy link
Contributor Author

The annoyance of getting all of this right is one of the reasons we put containerization support directly into the .NET SDK in .NET 8 - you can see an example of what this kind of multi-arch setup might look like in this sample I just made.

@LanceMcCarthy
Copy link
Owner

LOL, I feel ya on that one. Still it's a great learning experience for me when things fails, because it helps me build up my "troubleshooting tips" toolbox (this toolbox is how I am able to help the dev community).

As for UseAppHost=false that was to fix another problem. Though at this point, I can't recall what it was for 😋

Here's the final, successful run:

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG TARGETARCH
ARG BUILDPLATFORM
WORKDIR '/src/SecretsMocker/SecretsMocker'
COPY . .
RUN dotnet publish './SecretsMocker.csproj' -o /app/publish /p:UseAppHost=false --self-contained false --arch "${TARGETARCH}"

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0 as final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "SecretsMocker.dll"]

thank you for the help, I wil be studying those resources, especially now that I'm using Docker more often (already have some Aspire builds running in production 😶)

@baronfel
Copy link
Contributor Author

Glad we got there in the end. I'm gonna reply on Tim's email thread with a quick summary to make sure he knows you got some closure.

@LanceMcCarthy
Copy link
Owner

@baronfel And to the point of having it built-into the SDK directly, I love it... I already use it here https://github.com/LanceMcCarthy/DevOpsExamples/blob/a55c61551947beebc85a5ce2cd7a4e28c4ccabcb/.github/workflows/main_build-blazor.yml#L111

Though I haven't seen any multiarch approaches yet (because how do we instruction multiple architecture to msbuild?) I will take a look at the demo later today.

@baronfel
Copy link
Contributor Author

@LanceMcCarthy you immediately see to the crux of the issue :D My sample just does two publish calls, one each to create an x64 and arm64 image, then asks docker to create the final image, stitching the two SDK-created images together.

We can make this better in the SDK, but to do that we need some kind of officially-supported way to multitarget across architectures the way you can currently multitarget across TFMs. I'm trying to dig into what that would look like for sure.

@LanceMcCarthy
Copy link
Owner

LanceMcCarthy commented Feb 14, 2024

@baronfel If I could make a recommendation, it would be nice to use the same approach docker does, and pass in a comma-separate values list

Maybe something like:

dotnet publish -t:PublishContainer -p multiarch=true -p ContainerBaseImage="linux/arm64,linux/amd64"

And you can obtain both the OS and arch from them... Though, I did notice that the very first time containerization was added to the SDK, you're explicitly keeping the input values for OS separate from the ARCH (which is so that you can concatenate them inside the build?).

@baronfel
Copy link
Contributor Author

We we do move into this space we'll likely keep the platform/arch selection in terms of .NET RIDs, for user consistency. So you could imagine something like dotnet publish --arch x64 --arch arm64 /t:PublishContainer, and under the covers we'd do something like this to publish a container for each of those architectures and stitch it together ourselves.

Regarding OS/Arch being separate, that's just a convenience thing. The SDK is oriented around Runtime Identifiers, but you can infer a RID from a few different sources - the current execution environment for one, or if only an OS or Arch is specified you can pull the other part from the current execution environment. Since most folks are making linux containers e.g. in CI, using just the --arch limits the things you have to repeat. That's all :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants