I'm pretty new with docker, but running up against a wall trying to get my implementation to work through Docker Compose.
Docker Compose File
version: "3.4"
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- 5000:5000
- 5001:5001
Dockerfile
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app
# Install EF tools
RUN dotnet tool install --global dotnet-ef
ENV PATH="${PATH}:/root/.dotnet/tools"
# Generate Certificates
RUN dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p TestPassword
RUN dotnet dev-certs https --trust
# Copy everything else and build
COPY . ./
COPY Setup.sh Setup.sh
RUN dotnet restore
RUN dotnet build -c Release -o out
# Build runtime image
RUN chmod +x ./Setup.sh
CMD /bin/bash ./Setup.sh
Setup.sh Entry Point
#!/bin/bash
set -e
run_cmd="dotnet run --project Artis.Merchant.API/Artis.Merchant.API.csproj --launch-profile Artis.Merchant.API"
until dotnet ef database update --project Artis.Models/Artis.Models.csproj; do
>&2 echo "SQL Server is starting up"
sleep 1
done
>&2 echo "SQL Server is up - executing command"
exec $run_cmd
Launch Settings for Project
"profiles": {
"Artis.Merchant.API": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Local"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
},
So both my http or https endpoints seem to be unreachable when launched through Docker. The CLI output is the exact same, so it appears to be up and running through Docker. Any ideas what I'm doing wrong?
Locally running dotnet run --project Artis.Merchant.API/Artis.Merchant.API.csproj --launch-profile Artis.Merchant.API
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Local
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\Users\ddrob\source\Artis.Merchant.API
The above works fine I and access it as normal through https://localhost:5001 or http://localhost:5000
Output from Docker after running docker compose up
artis_api-app-1 | info: Microsoft.Hosting.Lifetime[14]
artis_api-app-1 | Now listening on: http://localhost:5000
artis_api-app-1 | info: Microsoft.Hosting.Lifetime[14]
artis_api-app-1 | Now listening on: https://localhost:5001
artis_api-app-1 | info: Microsoft.Hosting.Lifetime[0]
artis_api-app-1 | Application started. Press Ctrl+C to shut down.
artis_api-app-1 | info: Microsoft.Hosting.Lifetime[0]
artis_api-app-1 | Hosting environment: Local
artis_api-app-1 | info: Microsoft.Hosting.Lifetime[0]
artis_api-app-1 | Content root path: /app/Artis.Merchant.API
Been testing by just making an HTTP GET call to https://localhost:5001/api/health which should just return a 200. Works fine running locally, Docker returns either a socket hang up if accessed through non-https, and client network socket disconnected before secure TLS connection was established when accessed through https
EDIT
For more insight, here are the outputs from docker ps and docker inspect artis_api-app
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4b71ffc2c5a1 artis_api-app "/bin/sh -c '/bin/ba…" 43 minutes ago Up 23 minutes 0.0.0.0:5000-5001->5000-5001/tcp artis_api-app-1
[
{
"Id": "sha256:505685ec26fb58cc87fe4ec5166f2b3c0978b251953f5e9d431776ad036fc839",
"RepoTags": [
"artis_api-app:latest"
],
"RepoDigests": [],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2022-09-14T18:40:33.7696322Z",
"Container": "",
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.dotnet/tools",
"ASPNETCORE_URLS=",
"DOTNET_RUNNING_IN_CONTAINER=true",
"DOTNET_VERSION=6.0.9",
"ASPNET_VERSION=6.0.9",
"DOTNET_GENERATE_ASPNET_CERTIFICATE=false",
"DOTNET_NOLOGO=true",
"DOTNET_SDK_VERSION=6.0.401",
"DOTNET_USE_POLLING_FILE_WATCHER=true",
"NUGET_XMLDOC_MODE=skip",
"POWERSHELL_DISTRIBUTION_CHANNEL=PSDocker-DotnetSDK-Debian-11"
],
"Cmd": [
"/bin/sh",
"-c",
"/bin/bash ./Setup.sh"
],
"ArgsEscaped": true,
"Image": "",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 6245959471,
"VirtualSize": 6245959471,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/uqv91vlzccv2h5y9g9mzcbl2a/diff:/var/lib/docker/overlay2/dewh3h889lvrnae1qq1gaucga/diff:/var/lib/docker/overlay2/21fioiit0habui6whx5x56e4w/diff:/var/lib/docker/overlay2/xgcecdok1kdh5je5ti1xuyylx/diff:/var/lib/docker/overlay2/yxu9wlvfmwn5rp9lth9f9ff8s/diff:/var/lib/docker/overlay2/imqsg5pxz3xkzxsaucymd3xv5/diff:/var/lib/docker/overlay2/etcmf1dskml8g13hg0eeqgtrq/diff:/var/lib/docker/overlay2/3orhtkibg5z6eeosvazrsjjwx/diff:/var/lib/docker/overlay2/e903ebed1d7345de8bd1780dbb132091b2930ddaa014ef4f399ce87be1e105d4/diff:/var/lib/docker/overlay2/d49d1b24c5821a65689ef573e9f6e7f4562cc2cd7fb4d1e8f2f6144f31cbb1dc/diff:/var/lib/docker/overlay2/bbf9acaefd8441bb31972a56526870d63995056b59f59166560007d0a114b2f9/diff:/var/lib/docker/overlay2/2306e276d00d98d2aaff2af655cba48efe5b4c0c072f54b6883818a5063d2623/diff:/var/lib/docker/overlay2/7ab5f58b84e23d093901394612c6cc71f8b704f8408fcaab10ed9c2b799e71e4/diff:/var/lib/docker/overlay2/2cd518af44aa8bae9adaa6460d9c88a761f2fdccdd36b69ddcd4809d26fbb2a0/diff:/var/lib/docker/overlay2/ea6cf0ad92836e7d871430c029e19c688f5b7caeaee475f1b7fb18b215511cd9/diff:/var/lib/docker/overlay2/892c98581f39f02c87c8ca05c73b98bdc29ab6862ebb2e70ee8c7006d1f90ccf/diff",
"MergedDir": "/var/lib/docker/overlay2/u0v4b4saadkhe84ztlc2blsnj/merged",
"UpperDir": "/var/lib/docker/overlay2/u0v4b4saadkhe84ztlc2blsnj/diff",
"WorkDir": "/var/lib/docker/overlay2/u0v4b4saadkhe84ztlc2blsnj/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:b45078e74ec97c5e600f6d5de8ce6254094fb3cb4dc5e1cc8335fb31664af66e",
"sha256:5ec686cbc3c7aea55c4f80c574962f120e5f81ed0b7ccacbbde51f8d819f8247",
"sha256:e487c4dad54c656811ed2064a764f7240bb3b5936d497ec757991f9344be616d",
"sha256:64d665f70cc187b1c5a5c1fc8d0a4431ea0f0069c1985ce330c55523466c22b2",
"sha256:efccb7d95dee67a40c57966066356e47a301cc6028db923ab58fe4f21564fefb",
"sha256:b4d89feca49ab5217ab7d09079ab1f07c618570d0822ad74ccce634313cb0c91",
"sha256:d5471ff23747a10089f58397f39c2f66c6c8937687dd2b3592ab6fe09c6756d0",
"sha256:08affa1f86cb7d7262620e2517bc3308598db5d047135c5b7db00994d22f6701",
"sha256:6f1bf9eb1c14548bc0b119efb283637880394c2cae2117de367238ab3b7fcb80",
"sha256:be544cd1ea837e49241d66815afaeddfe79b3d869972f64451e3c2dcdf8c10eb",
"sha256:7c2ba258f59487f4dacf912a4f2c0a7598e2b4082283555fd5ca127da145cdc9",
"sha256:3bcd28ee7f58f12baceeb1ab2c097675ca35e66f3e350869a73d5bc508fcfd57",
"sha256:11f2bbe76890bfd069e0f1b75dd4acd35dc33f071f061e5c6751e5af7723e897",
"sha256:d5f7661f5ac2f07ba5836972af96f89358381cbb5399342ef6fd03b6306fe000",
"sha256:5879a59c7c2aba6ffcc9535592116cc92e7efd4d7acff9f7716e1e2ac167c3e8",
"sha256:fdedee5f422b0f13237dd54f9894c64c4323f48d7d06e10a7640991ce9dd62ce",
"sha256:01104bf88915fea5e113a37e57b450afa15ec647816e61b17bea508082a8ee32"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
I noticed the outputs are different when I inspect artis_api-app-1 instead of the Image named artis_api-app. I figured the only relevant portion of the former is the network settings output.
"NetworkSettings": {
"Bridge": "",
"SandboxID": "174a63cebce5ca8ff7c6b218a73c90e5b813caad60b008777a1fdb031c595ced",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"5000/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "5000"
}
],
"5001/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "5001"
}
]
},
"SandboxKey": "/var/run/docker/netns/174a63cebce5",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"artis_api_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"artis_api-app-1",
"app",
"4b71ffc2c5a1"
],
"NetworkID": "dc60832ac2b09450067b3edeb1cd944ad9c7c4805a674da5dba456654db49125",
"EndpointID": "cd04c2b9261b8ec3a095a6c3db6001484e41a41ca0dd3c32a72c093cf3787e7b",
"Gateway": "172.22.0.1",
"IPAddress": "172.22.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:16:00:03",
"DriverOpts": null
}
}
}
EDIT 2
Here is my initial Program.cs entry point since I've had some questions regarding that.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureAppConfiguration((context, configBuilder) =>
{
string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
string envName = context.HostingEnvironment.EnvironmentName;
configBuilder.Sources.Clear();
configBuilder.AddJsonFile($"{assemblyName}.appsettings.json", optional: false, reloadOnChange: true);
configBuilder.AddJsonFile($"{assemblyName}.appsettings.{envName}.json", optional: true, reloadOnChange: true);
});
webBuilder.UseStartup<Startup>();
});
}
Answer
Along with the accepted answer I also needed to include a Kestrel configuration in my appsettings.json file such as this:
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:5000"
},
"Https": {
"Url": "https://0.0.0.0:5001"
}
},
"EndpointDefaults": {
"Url": "https://0.0.0.0:5001",
"Protocols": "Http1"
}
}
- ASPNETCORE_Kestrel__Endpoints__Http__Url=http://0.0.0.0:5000Same function, just different presentation.