Table of contents
Intro
In this post we will see how to deploy your dotnet core app with docker container.
Create ABP Tired application
1abp new AbpDocker -t app -u mvc --tiered -dbms PostgreSQL
Once the app is created update the connection string in all the project and run the DbMigration
project to setup the migrations and database seeding.
Create a same site cookies extension
you can find the code for that here: https://community.abp.io/articles/patch-for-chrome-login-issue-identityserver4-samesite-cookie-problem-weypwp3n
Here is the code
1public static class SameSiteCookiesServiceCollectionExtensions 2{ 3 public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services) 4 { 5 services.Configure<CookiePolicyOptions>(options => 6 { 7 options.MinimumSameSitePolicy = SameSiteMode.Lax; 8 options.OnAppendCookie = cookieContext => 9 CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); 10 options.OnDeleteCookie = cookieContext => 11 CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); 12 }); 13 14 return services; 15 } 16 17 private static void CheckSameSite(HttpContext httpContext, CookieOptions options) 18 { 19 if (options.SameSite == SameSiteMode.None) 20 { 21 var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); 22 if (!httpContext.Request.IsHttps || DisallowsSameSiteNone(userAgent)) 23 { 24 // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1) 25 options.SameSite = SameSiteMode.Lax; 26 } 27 } 28 } 29 30 private static bool DisallowsSameSiteNone(string userAgent) 31 { 32 // Cover all iOS based browsers here. This includes: 33 // - Safari on iOS 12 for iPhone, iPod Touch, iPad 34 // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad 35 // - Chrome on iOS 12 for iPhone, iPod Touch, iPad 36 // All of which are broken by SameSite=None, because they use the iOS networking stack 37 if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12")) 38 { 39 return true; 40 } 41 42 // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes: 43 // - Safari on Mac OS X. 44 // This does not include: 45 // - Chrome on Mac OS X 46 // Because they do not use the Mac OS networking stack. 47 if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && 48 userAgent.Contains("Version/") && userAgent.Contains("Safari")) 49 { 50 return true; 51 } 52 53 // Cover Chrome 50-69, because some versions are broken by SameSite=None, 54 // and none in this range require it. 55 // Note: this covers some pre-Chromium Edge versions, 56 // but pre-Chromium Edge does not require SameSite=None. 57 if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6")) 58 { 59 return true; 60 } 61 62 return false; 63 } 64}
Add the following line to ConfigureServices()
method in all 3 projects.
1context.Services.AddSameSiteCookiePolicy();
Go to OnApplicationInitialization()
method in AcmeBookStoreWebModule.cs add app.UseCookiePolicy();
in all 3 projects.
1app.UseCookiePolicy(); // added this, Before UseAuthentication or anything else that writes cookies.
Create a new client for the production app
Update the appsettings.json
from the DbMigrator
to add the new client.
1"AbpDocker_Web_Docker": { 2 "ClientId": "AbpDocker_Web_Docker", 3 "ClientSecret": "1q2w3e*", 4 "RootUrl": "http://host.docker.internal:9005" 5},
Update the IdentityServerDataSeedContributor
in the Domain
project and add the new client to the identity server.
1//webDockerClient Client 2var webDockerClientId = configurationSection["AbpDocker_Web_Docker:ClientId"]; 3if (!webClientId.IsNullOrWhiteSpace()) 4{ 5 var webClientRootUrl = configurationSection["AbpDocker_Web_Docker:RootUrl"].EnsureEndsWith('/'); 6 7 await CreateClientAsync( 8 name: webDockerClientId, 9 scopes: commonScopes, 10 grantTypes: new[] { "hybrid" }, 11 secret: (configurationSection["AbpDocker_Web_Docker:ClientSecret"] ?? "1q2w3e*").Sha256(), 12 redirectUri: $"{webClientRootUrl}signin-oidc", 13 postLogoutRedirectUri: $"{webClientRootUrl}signout-callback-oidc", 14 frontChannelLogoutUri: $"{webClientRootUrl}Account/FrontChannelLogout", 15 corsOrigins: new[] { webClientRootUrl.RemovePostFix("/") } 16 ); 17}
Run the DbMigrator
project again to see the new client.
Create production config
Create the appsettings.Production.json
in all the three projects.
HttpApi.Host
1{ 2 "App": { 3 "CorsOrigins": "https://*.AbpDocker.com" 4 }, 5 "ConnectionStrings": { 6 "Default": "Host=host.docker.internal;Port=5432;Database=AbpDocker;User ID=postgres;Password=postgres;" 7 }, 8 "Redis": { 9 "Configuration": "host.docker.internal" 10 }, 11 "AuthServer": { 12 "Authority": "http://host.docker.internal:9006", 13 "RequireHttpsMetadata": "false", 14 "SwaggerClientId": "AbpDocker_Swagger", 15 "SwaggerClientSecret": "1q2w3e*" 16 }, 17 "StringEncryption": { 18 "DefaultPassPhrase": "WBN0szwYr7wL8Dou" 19 } 20}
IdentityServer
1{ 2 "App": { 3 "SelfUrl": "http://host.docker.internal:9006", 4 "ClientUrl": "http://localhost:4200", 5 "CorsOrigins": "https://*.AbpDocker.com,http://localhost:4200,https://localhost:44307,https://localhost:44375,http://host.docker.internal:9006,http://host.docker.internal:9005,http://host.docker.internal:9007", 6 "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307,http://host.docker.internal:9006,http://host.docker.internal:9005,http://host.docker.internal:9007" 7 }, 8 "ConnectionStrings": { 9 "Default": "Host=host.docker.internal;Port=5432;Database=AbpDocker;User ID=postgres;Password=postgres;" 10 }, 11 "Redis": { 12 "Configuration": "host.docker.internal" 13 } 14}
Web
1{ 2 "App": { 3 "SelfUrl": "http://host.docker.internal:9005" 4 }, 5 "RemoteServices": { 6 "Default": { 7 "BaseUrl": "http://host.docker.internal:9007/" 8 } 9 }, 10 "Redis": { 11 "Configuration": "host.docker.internal" 12 }, 13 "AuthServer": { 14 "Authority": "http://host.docker.internal:9006", 15 "RequireHttpsMetadata": "false", 16 "ClientId": "AbpDocker_Web_Docker", 17 "ClientSecret": "1q2w3e*" 18 } 19}
Add docker support
Do the following in all 3 projects.
-
Right Click -> Add -> Docker Support
This will add
Docker
file into the project. -
Right Click -> Add -> Container Orchestrator Support
This will add the docker file to the
docker-compose.yml
Add port mapping to the services to the expose the services.
Final docker-compose.yml
will look like this.
1version: "3.4" 2 3services: 4 web: 5 image: abpdockerweb 6 ports: 7 - 9005:80 8 build: 9 context: . 10 dockerfile: src/AbpDocker.Web/Dockerfile 11 12 identityserver: 13 image: abpdockeridentityserver 14 ports: 15 - 9006:80 16 build: 17 context: . 18 dockerfile: src/AbpDocker.IdentityServer/Dockerfile 19 20 httpapi: 21 image: abpdockerhttpapihost 22 ports: 23 - 9007:80 24 build: 25 context: . 26 dockerfile: src/AbpDocker.HttpApi.Host/Dockerfile
Build docker containers
Navigate to the directory where the docker-compose.yml
file is present and then run the following command.
1docker-compose build
Deploy the docker stack
1docker stack deploy -c .\docker-compose.yml abpdocker
Run the app
Visit the web app in http://host.docker.internal:9005/
Visit the identity server in http://host.docker.internal:9006/
Visit the api in http://host.docker.internal:9007/