diff --git a/README.md b/README.md index 6b75ff7c9..4637f13ce 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ For a list on the new .NET Core 2.0 related implemented features, see this [blog However, this sample application should not be considered as an "eCommerce reference model", at all. The implemented business domain might not be ideal from an eCommerce business point of view. It is neither trying to solve all the problems in a large, scalable and mission-critical distributed system. It is just a bootstrap for developers to easily get started in the world of Docker containers and microservices with .NET Core. >

For example, the next step after running the solution in the local dev PC and understanding Docker containers and microservices development with .NET Core, is to select a microservice cluster/orchestrator like Kubernetes in Azure (AKS) or Azure Service Fabric, both environments tested and supported by this solution. > Additional steps would be to move your databases to HA cloud services (like Azure SQL Database), or switch your EventBus to use Azure Service Bus (instead of bare-bone RabbitMQ) or any other production ready Service Bus in the market. ->

-> + +![image](https://user-images.githubusercontent.com/1712635/40397331-059a7ec6-5de7-11e8-8542-a597eca16fef.png) + > Read the planned Roadmap and Milestones for future releases of eShopOnContainers within the Wiki for further info about possible new implementations and provide feedback at the ISSUES section if you'd like to see any specific scenario implemented or improved. Also, feel free to discuss on any current issue. ### Architecture overview diff --git a/build/acr-build/queue-all.ps1 b/build/acr-build/queue-all.ps1 new file mode 100644 index 000000000..aacffea95 --- /dev/null +++ b/build/acr-build/queue-all.ps1 @@ -0,0 +1,37 @@ +Param( + [parameter(Mandatory=$false)][string]$acrName, + [parameter(Mandatory=$false)][string]$gitUser, + [parameter(Mandatory=$false)][string]$repoName="eShopOnContainers", + [parameter(Mandatory=$false)][string]$gitBranch="dev", + [parameter(Mandatory=$true)][string]$patToken +) + +$gitContext = "https://github.com/$gitUser/$repoName" + +$services = @( + @{ Name="eshopbasket"; Image="eshop/basket.api"; File="src/Services/Basket/Basket.API/Dockerfile" }, + @{ Name="eshopcatalog"; Image="eshop/catalog.api"; File="src/Services/Catalog/Catalog.API/Dockerfile" }, + @{ Name="eshopidentity"; Image="eshop/identity.api"; File="src/Services/Identity/Identity.API/Dockerfile" }, + @{ Name="eshopordering"; Image="eshop/ordering.api"; File="src/Services/Ordering/Ordering.API/Dockerfile" }, + @{ Name="eshoporderingbg"; Image="eshop/ordering.backgroundtasks"; File="src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile" }, + @{ Name="eshopmarketing"; Image="eshop/marketing.api"; File="src/Services/Marketing/Marketing.API/Dockerfile" }, + @{ Name="eshopwebspa"; Image="eshop/webspa"; File="src/Web/WebSPA/Dockerfile" }, + @{ Name="eshopwebmvc"; Image="eshop/webmvc"; File="src/Web/WebMVC/Dockerfile" }, + @{ Name="eshopwebstatus"; Image="eshop/webstatus"; File="src/Web/WebStatus/Dockerfile" }, + @{ Name="eshoppayment"; Image="eshop/payment.api"; File="src/Services/Payment/Payment.API/Dockerfile" }, + @{ Name="eshoplocations"; Image="eshop/locations.api"; File="src/Services/Location/Locations.API/Dockerfile" }, + @{ Name="eshopocelotapigw"; Image="eshop/ocelotapigw"; File="src/ApiGateways/ApiGw-Base/Dockerfile" }, + @{ Name="eshopmobileshoppingagg"; Image="eshop/mobileshoppingagg"; File="src/ApiGateways/Mobile.Bff.Shopping/aggregator/Dockerfile" }, + @{ Name="eshopwebshoppingagg"; Image="eshop/webshoppingagg"; File="src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile" }, + @{ Name="eshoporderingsignalrhub"; Image="eshop/ordering.signalrhub"; File="src/Services/Ordering/Ordering.SignalrHub/Dockerfile" } +) + +$services |% { + $bname = $_.Name + $bimg = $_.Image + $bfile = $_.File + Write-Host "Setting ACR build $bname ($bimg)" + az acr build-task create --registry $acrName --name $bname --image ${bimg}:$gitBranch --context $gitContext --branch $gitBranch --git-access-token $patToken --file $bfile +} + +# Basket.API diff --git a/docker-compose.override.yml b/docker-compose.override.yml index f55cf5025..d523b328a 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -224,24 +224,7 @@ services: ports: - "5109:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes. # The API Gateway redirects and access through the internal port (80). - - ordering.backgroundtasks: - environment: - - ASPNETCORE_ENVIRONMENT=Development - - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} - - EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD} - - UseCustomizationData=True - - AzureServiceBusEnabled=False - - CheckUpdateTime=30000 - - GracePeriodTime=1 - - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - - OrchestratorType=${ORCHESTRATOR_TYPE} - - UseLoadTest=${USE_LOADTEST:-False} - ports: - - "5111:80" + sql.data: environment: diff --git a/docker-compose.yml b/docker-compose.yml index 8deef97c0..414d9a1ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -153,14 +153,6 @@ services: context: . dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile - ordering.backgroundtasks: - image: eshop/ordering.backgroundtasks:${TAG:-latest} - build: - context: . - dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile - depends_on: - - sql.data - - rabbitmq ordering.signalrhub: image: eshop/ordering.signalrhub:${TAG:-latest} build: diff --git a/k8s/README.k8s.md b/k8s/README.k8s.md index 77acdf236..62841aba1 100644 --- a/k8s/README.k8s.md +++ b/k8s/README.k8s.md @@ -4,16 +4,23 @@ The k8s directory contains Kubernetes configuration for the eShopOnContainers ap ## Prerequisites * A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one. * A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one. -* Optionally, previous steps can be skipped if you run gen-k8s-env.ps1 (or gen-k8s-env-aks.ps1 if you would like to use AKS instead of ACS) script to automatically create the azure environment needed for kubernetes deployment. Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example: +* Optionally, previous steps can be skipped if you run the **gen-k8s-env-aks.ps1** script to create an AKS cluster environment or gen-k8s-env.ps1 script to create an ACS for Kuberentes cluster environment including the creation of additional Azure environment needed like an Azure Resource Manager and ACR registry. + +Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example: **Important**: Note the parameter "-createAcr true". If you are creating the K8s cluster but you want to re-use and existing ACR, say "-createAcr false". + +For AKS: + >``` ->./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -createAcr true -orchestratorName k8s-cluster -dnsName k8s-dns +>./gen-k8s-env-aks -resourceGroupName YoureShopAksResgroup -location centralus -serviceName YoureShopAksCluster -dnsNamePrefix youreshopaks -registryName YoureShopAcrRegistry -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2 >``` -or using AKS instead of ACS + +For ACS: + >``` ->./gen-k8s-env-aks -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -dnsName k8s-dns -serviceName k8s-cluster -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2 +>./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -createAcr true -orchestratorName k8s-cluster -dnsName k8s-dns >``` * A Docker development environment with `docker` and `docker-compose`. diff --git a/k8s/build-push-images.ps1 b/k8s/build-push-images.ps1 new file mode 100644 index 000000000..e2c8e06b6 --- /dev/null +++ b/k8s/build-push-images.ps1 @@ -0,0 +1,72 @@ +Param( + [parameter(Mandatory=$false)][string]$registry, + [parameter(Mandatory=$false)][string]$dockerUser, + [parameter(Mandatory=$false)][string]$dockerPassword, + [parameter(Mandatory=$false)][string]$imageTag, + [parameter(Mandatory=$false)][bool]$buildImages=$true, + [parameter(Mandatory=$false)][bool]$pushImages=$true, + [parameter(Mandatory=$false)][string]$dockerOrg="eshop" +) + +# Initialization + +$useDockerHub = [string]::IsNullOrEmpty($registry) + +# Check required commands (only if not in CI environment) + +$requiredCommands = ("docker", "docker-compose") +foreach ($command in $requiredCommands) { + if ((Get-Command $command -ErrorAction SilentlyContinue) -eq $null) { + Write-Host "$command must be on path" -ForegroundColor Red + exit + } +} + +# Get tag to use from current branch if no tag is passed +if ([string]::IsNullOrEmpty($imageTag)) { + $imageTag = $(git rev-parse --abbrev-ref HEAD) +} +Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow + +# Build docker images if needed +if ($buildImages) { + Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow + $env:TAG=$imageTag + docker-compose -p .. -f ../docker-compose.yml build +} + +# Login to Docker registry +if (-not [string]::IsNullOrEmpty($dockerUser)) { + $registryFDQN = if (-not $useDockerHub) {$registry} else {"index.docker.io/v1/"} + + Write-Host "Logging in to $registryFDQN as user $dockerUser" -ForegroundColor Yellow + if ($useDockerHub) { + docker login -u $dockerUser -p $dockerPassword + } + else { + docker login -u $dockerUser -p $dockerPassword $registryFDQN + } + + if (-not $LastExitCode -eq 0) { + Write-Host "Login failed" -ForegroundColor Red + exit + } + +} + +# Push images to Docker registry +if ($pushImages) { + Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow + $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub") + + foreach ($service in $services) { + $imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"} + docker tag eshop/${service}:$imageTag ${imageFqdn}:$imageTag + docker push ${imageFqdn}:$imageTag + } +} + + + + + diff --git a/k8s/conf_cloud.yml b/k8s/conf_cloud.yaml similarity index 100% rename from k8s/conf_cloud.yml rename to k8s/conf_cloud.yaml diff --git a/k8s/conf_local.yml b/k8s/conf_local.yaml similarity index 100% rename from k8s/conf_local.yml rename to k8s/conf_local.yaml diff --git a/k8s/deploy.ps1 b/k8s/deploy.ps1 index 443edb4a1..f0905096a 100644 --- a/k8s/deploy.ps1 +++ b/k8s/deploy.ps1 @@ -8,6 +8,7 @@ Param( [parameter(Mandatory=$false)][string]$imageTag, [parameter(Mandatory=$false)][bool]$deployCI=$false, [parameter(Mandatory=$false)][bool]$buildImages=$true, + [parameter(Mandatory=$false)][bool]$pushImages=$true, [parameter(Mandatory=$false)][bool]$deployInfrastructure=$true, [parameter(Mandatory=$false)][string]$dockerOrg="eshop" ) @@ -63,7 +64,9 @@ if ($buildImages) { Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow $env:TAG=$imageTag docker-compose -p .. -f ../docker-compose.yml build +} +if ($pushImages) { Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub") @@ -91,7 +94,10 @@ if (-not [string]::IsNullOrEmpty($dockerUser)) { exit } - # create registry key secret + # Try to delete the Docker registry key secret + ExecKube -cmd 'delete secret docker-registry registry-key' + + # Create the Docker registry key secret ExecKube -cmd 'create secret docker-registry registry-key ` --docker-server=$registryFDQN ` --docker-username=$dockerUser ` diff --git a/k8s/deployments.yaml b/k8s/deployments.yaml index ca97df9eb..f362c319c 100644 --- a/k8s/deployments.yaml +++ b/k8s/deployments.yaml @@ -702,6 +702,11 @@ spec: configMapKeyRef: name: internalurls key: ordering__hc + - name: OrderingBackgroundTasksUrl + valueFrom: + configMapKeyRef: + name: internalurls + key: ordering-background__hc - name: LocationsUrl valueFrom: configMapKeyRef: diff --git a/k8s/gen-k8s-env-aks.ps1 b/k8s/gen-k8s-env-aks.ps1 index ef36a390d..727a9ca53 100644 --- a/k8s/gen-k8s-env-aks.ps1 +++ b/k8s/gen-k8s-env-aks.ps1 @@ -1,15 +1,16 @@ Param( [parameter(Mandatory=$true)][string]$resourceGroupName, [parameter(Mandatory=$true)][string]$location, - [parameter(Mandatory=$false)][string]$registryName, [parameter(Mandatory=$true)][string]$serviceName, + [parameter(Mandatory=$true)][string]$dnsNamePrefix, + [parameter(Mandatory=$false)][string]$registryName, [parameter(Mandatory=$true)][string]$createAcr=$true, [parameter(Mandatory=$false)][int]$nodeCount=3, [parameter(Mandatory=$false)][string]$nodeVMSize="Standard_D2_v2" ) # Create resource group -Write-Host "Creating resource group..." -ForegroundColor Yellow +Write-Host "Creating Azure Resource Group..." -ForegroundColor Yellow az group create --name=$resourceGroupName --location=$location if ($createAcr -eq $true) { @@ -18,14 +19,16 @@ if ($createAcr -eq $true) { az acr create -n $registryName -g $resourceGroupName -l $location --admin-enabled true --sku Basic } -# Create kubernetes orchestrator -Write-Host "Creating kubernetes orchestrator..." -ForegroundColor Yellow -az aks create --resource-group=$resourceGroupName --name=$serviceName --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize +# Create kubernetes cluster in AKS +Write-Host "Creating Kubernetes cluster in AKS..." -ForegroundColor Yellow +az aks create --resource-group=$resourceGroupName --name=$serviceName --dns-name-prefix=$dnsNamePrefix --generate-ssh-keys --node-count=$nodeCount --node-vm-size=$nodeVMSize # Retrieve kubernetes cluster configuration and save it under ~/.kube/config +Write-Host "Getting Kubernetes config..." -ForegroundColor Yellow az aks get-credentials --resource-group=$resourceGroupName --name=$serviceName if ($createAcr -eq $true) { # Show ACR credentials + Write-Host "ACR credentials" -ForegroundColor Yellow az acr credential show -n $registryName } diff --git a/k8s/internalurls.yaml b/k8s/internalurls.yaml index e42ef23ec..df317b5d5 100644 --- a/k8s/internalurls.yaml +++ b/k8s/internalurls.yaml @@ -14,6 +14,8 @@ data: identity__hc: http://identity/hc ordering: http://ordering ordering__hc: http://ordering/hc + ordering-background: http://ordering-background + ordering-background__hc: http://ordering-background/hc marketing: http://marketing marketing__hc: http://marketing/hc locations: http://locations diff --git a/k8s/services.yaml b/k8s/services.yaml index 035f1c798..ad537eaf0 100644 --- a/k8s/services.yaml +++ b/k8s/services.yaml @@ -59,14 +59,14 @@ kind: Service metadata: labels: app: eshop - component: ordering-background + component: ordering-backgroundtasks name: ordering-background spec: ports: - port: 80 selector: app: eshop - component: ordering-background + component: ordering-backgroundtasks --- apiVersion: v1 kind: Service diff --git a/src/ApiGateways/ApiGw-Base/Program.cs b/src/ApiGateways/ApiGw-Base/Program.cs index 782681901..effd5684e 100644 --- a/src/ApiGateways/ApiGw-Base/Program.cs +++ b/src/ApiGateways/ApiGw-Base/Program.cs @@ -20,11 +20,11 @@ namespace OcelotApiGw public static IWebHost BuildWebHost(string[] args) { - var builder = WebHost.CreateDefaultBuilder(args); + IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args); builder.ConfigureServices(s => s.AddSingleton(builder)) .ConfigureAppConfiguration(ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json"))) .UseStartup(); - var host = builder.Build(); + IWebHost host = builder.Build(); return host; } } diff --git a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs index dd8b166c1..b2bc2346a 100644 --- a/src/Services/Ordering/Ordering.SignalrHub/Startup.cs +++ b/src/Services/Ordering/Ordering.SignalrHub/Startup.cs @@ -46,13 +46,6 @@ namespace Ordering.SignalrHub services .AddSignalR() .AddRedis(Configuration["SignalrStoreConnectionString"]); - - //services - // .AddSignalR() - // .AddRedis(options => options.Factory = writer => - // { - // return ConnectionMultiplexer.Connect(Configuration["SignalrStoreConnectionString"], writer); - // }); } else { diff --git a/src/Web/WebSPA/package.json b/src/Web/WebSPA/package.json index e0a3f4b6b..3349cd6d2 100644 --- a/src/Web/WebSPA/package.json +++ b/src/Web/WebSPA/package.json @@ -36,7 +36,7 @@ "@angular/platform-browser": "^4.0.0", "@angular/platform-browser-dynamic": "^4.0.0", "@angular/router": "^4.0.0", - "@aspnet/signalr": "^1.0.0-preview2-final", + "@aspnet/signalr": "1.0.0-preview2-final", "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22", "bootstrap": "4.0.0-alpha.5", "core-js": "^2.4.1",