Source code for my sample app, a simple ASP.NET 6.0 WebAPI with default WeatherForecast controller, can be found here: https://github.com/andre-engelbrecht/sample_net_api
cloudbuild.yaml:
steps:
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/sample-api'
- '-f'
- 'Sample_API/Sample_API.API/Dockerfile' # Update the path to your Dockerfile
- '.' # Set the build context to the root directory
images:
- 'gcr.io/$PROJECT_ID/sample-api'
Dockerfile: (which builds successfully on CloudBuild)
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["Sample_API/Sample_API.API/Sample_API.API.csproj", "Sample_API.API/"]
COPY ["Sample_API/Sample_API.API/", "Sample_API.API/"]
RUN dotnet restore "Sample_API.API/Sample_API.API.csproj"
WORKDIR "/src/Sample_API.API"
RUN ls -a
RUN dotnet build "Sample_API.API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Sample_API.API.csproj" -c Release -o /app/publish /p:UseAppHost=true
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
#Set the environment variable to listen on the specified port
ENV ASPNETCORE_URLS=http://*:$PORT
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Sample_API.API.dll"]
Cloud Run complains of the following:
The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable
Cloud Run Logs:
- A fatal error was encountered. The library 'libhostpolicy.so' required to execute the application was not found in '/app/'.
- Failed to run as a self-contained app.
- The application was run as a self-contained app because '/app/Sample_API.API.runtimeconfig.json' was not found.
- If this should be a framework-dependent app, add the '/app/Sample_API.API.runtimeconfig.json' file and specify the appropriate framework.
What can I do to get this to work? I'm new to Docker and GCP, so I really don't know what I'm doing wrong? And though there are many guides out there, I could not find one for my particular use case.
According to this post, the problem is that my service is not listening on the defined port (8080), but how/where do I specify what port it should listen on when in Cloud Run? Locally I've set it up so that it starts on port 8080, but that didn't fix GCP.
I followed the following guides to get this far:
Any help will be appreciated!
I finally got it all working!
Initially I had (unknowingly) created my project with top-level statements, this meant that there was no "Main" method in Program.cs to use as an entry point.
cloudbuild.yaml
to define build and deploy stepsThere's likely more then one way to do this, but I ended up adding a couldbuild.yaml
file to the root of my repo to define build and deploy steps for Cloud Build.
cloudbuild.yaml
file looks like:steps:
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/sample-api'
- '-f'
- 'Sample_API/Sample_API.API/Dockerfile' # Update the path to your Dockerfile
- '.' # Set the build context to the root directory
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/sample-api']
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'run'
- 'deploy'
- 'sample-net-api' # Update with your service name
- '--image=gcr.io/$PROJECT_ID/sample-api'
- '--region=us-central1'
- '--platform=managed'
# Additional deployment options go here
images:
- 'gcr.io/$PROJECT_ID/sample-api'
Dockerfile
My Dockerfile
has some errors, most notably the commands to copy the project- and other files to the /src
directory during build.
I also added a 2nd project to my solution, a class-library to define core code and keep my controller lean. Which mandated further updates to make the COPY more generic.
Dockerfile
looks likeFROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
# Copy all files to /src directory
COPY ["Sample_API/", "Sample_API/"]
# "Navigate" to main project directory
WORKDIR "/src/Sample_API/Sample_API.API"
# Restore and build
RUN dotnet restore "Sample_API.API.csproj"
RUN dotnet build "Sample_API.API.csproj" -c Release -o /app/build
FROM build AS publish
# Publish
RUN dotnet publish "Sample_API.API.csproj" -c Release -o /app/publish /p:UseAppHost=true
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
# Set the environment variable to listen on the specified port
# Only used in load Docker test deployments - not used in Cloud Run
# ENV ASPNETCORE_URLS=http://*:$PORT
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Sample_API.API.dll"]
Lastly I had to ensure my service started on the port that was specified in Cloud Run setup, to avoid the infamous The user-provided container failed to start and listen on the port defined provided by the PORT=$PORT environment variable
error.
I did this by adding the following to Program.cs
:
if (Environment.GetEnvironmentVariable("PORT") != null)
{
builder.WebHost.UseUrls($"http://0.0.0.0:{Environment.GetEnvironmentVariable("PORT")}");
}
A big shoutout to ChatGPT, which when you ask the right questions, can indeed be very useful.