Browse Source

Deployment template and README for DC/OS

pull/711/head
Charles Lowell 7 years ago
parent
commit
17e379371f
4 changed files with 565 additions and 0 deletions
  1. +92
    -0
      README.dcos.md
  2. +25
    -0
      README.md
  3. +9
    -0
      dcos/generate-config.ps1
  4. +439
    -0
      dcos/template.json

+ 92
- 0
README.dcos.md View File

@ -0,0 +1,92 @@
# eShopOnContainers on DC/OS
## Prerequisites
* 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.
* A DC/OS cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-deployment) to create one.
* The `dcos` CLI (DC/OS docs: [Installing the CLI](https://dcos.io/docs/1.8/usage/cli/install/))
## Prepare the Cluster
1. Install Marathon-LB. ([DC/OS docs](https://dcos.io/docs/1.8/usage/service-discovery/marathon-lb/usage/))
1. Mount an Azure file share on each agent of the cluster at `/mnt/share`. See the Azure Container Service [documentation](https://docs.microsoft.com/en-us/azure/container-service/container-service-dcos-fileshare) for guidance.
1. Copy your private registry credentials to the mounted file share as described in the Azure Container Service [documentation](https://docs.microsoft.com/en-us/azure/container-service/container-service-dcos-acr).
## Deploy the Application
1. Build the eShopOnContainers Docker images, and push them to your registry.
1. Open an SSH tunnel to your cluster as described in the ACS documentation: [Connect with an ACS cluster](https://docs.microsoft.com/en-us/azure/container-service/container-service-connect#connect-to-a-dcos-or-swarm-cluster)
1. Open a PowerShell window with the `dcos` CLI on your path.
1. Navigate to your local `eShopOnContainers` repository's `dcos` directory.
1. Run `generate-config.ps1` to generate configuration for the eShopOnContainers services. The script requires URLs for your cluster's agents and your private registry. Your agents' URL is of the form `[dns prefix]agents.[Azure region].cloudapp.azure.com`:
>```powershell
>./generate-config.ps1 -agentsFqdn mydcosagents.centralus.cloudapp.azure.com -registry myregistry.azurecr.io
>```
6. Use the `dcos` CLI to deploy the application:
>```powershell
>dcos marathon group add eShopOnContainers.json
>```
# DC/OS 101
DC/OS is an operating system based on Apache Mesos, a distributed systems kernel. Similar to the way a desktop OS manages a single machine's compute resources, abstracting away the details of core scheduling and memory allocation, DC/OS manages the compute resources of a cluster of heterogenous machines.
Like a desktop OS, DC/OS is general-purpose; we won't deploy eShopOnContainers to it directly. Instead we'll deploy to Marathon, a container orchestration platform which runs atop DC/OS.
## A Marathon Application
The Maration API defines applications in JSON. Container application definitions are simple. For example, here's one for the eShopOnContainers SQL server:
>```json
>{
> "id": "sql-data",
> "container": {
> "type": "DOCKER",
> "docker": {
> "image": "microsoft/mssql-server-linux:ctp1-4",
> "network": "BRIDGE",
> "portMappings": [
> {
> "hostPort": 1433,
> "labels": {
> "VIP_0": "eshopsql-data:1433"
> }
> }
> ]
> }
> },
> "env": {
> "ACCEPT_EULA": "Y",
> "SA_PASSWORD": "Pass@word"
> },
> "healthChecks": [
> {
> "protocol": "TCP",
> "gracePeriodSeconds": 30,
> "intervalSeconds": 60,
> "timeoutSeconds": 30,
> "maxConsecutiveFailures": 3,
> "port": 1433
> }
> ],
> "cpus": 0.1,
> "mem": 1024,
> "instances": 1
>},
>```
The definition straightforwardly specifies the image, environment variables, compute resources, and health checks for the container. Marathon's port configuration is more complex; for details, see the [Marathon documentation](https://mesosphere.github.io/marathon/docs/ports.html). Basically, the above definition binds the container's port 1433 to the host's port 1433. It also specifies a DC/OS Virtual IP, `eshopsql-data:1433`. Other containers can use this to find an IP for `sql-data` via Marathon's layer 4 load balancer using a simple naming convention: `eshopsql-data` becomes `eshopsql-data.marathon.l4lb.thisdcos.directory`.
## Exposing an Application
Marathon-LB is a useful tool for load balancing applications. It includes HAProxy and, using label metadata from the Marathon event bus, dynamically generates its configuration to match the state of Marathon applications. For example, here are the labels for the `webmvc` application:
>```json
>{
> "id": "webmvc",
> ...
> "labels": {
> "HAPROXY_GROUP": "external",
> "HAPROXY_0_VHOST": "mydcosagents.centralus.cloudapp.azure.com",
> "HAPROXY_0_MODE": "http",
> "HAPROXY_0_PATH": "/webmvc"
> },
> ...
>}
>```
This tells the Marathon-LB application responsible for the "external" group to proxy `http://mydcosagents.centralus.cloudapp.azure.com/webmvc` to a `webmvc` container. When `webmvc` deploys, Marathon-LB generates appropriate configuration for, and restarts, HAProxy.
## Further Reading
* [DC/OS Docs](https://dcos.io/docs/1.8/)
* [Marathon Docs](https://mesosphere.github.io/marathon/docs/)

+ 25
- 0
README.md View File

@ -86,6 +86,31 @@ https://github.com/dotnet/eShopOnContainers/wiki/04.-Setting-eShopOnContainer-so
The <b>Windows Containers scenario is currently being implemented/tested yet</b>. The application should be able to run on Windows Nano Containers based on different Docker base images, as well, as the .NET Core services have also been tested running on plain Windows (with no Docker). The <b>Windows Containers scenario is currently being implemented/tested yet</b>. The application should be able to run on Windows Nano Containers based on different Docker base images, as well, as the .NET Core services have also been tested running on plain Windows (with no Docker).
The app was also partially tested on "Docker for Mac" using a development MacOS machine with .NET Core and VS Code installed, which is still a scenario using Linux containers running on the VM setup in the Mac by the "Docker for Windows" setup. But further testing and feedback on Mac environments and Windows Containers, from the community, will be appreciated. The app was also partially tested on "Docker for Mac" using a development MacOS machine with .NET Core and VS Code installed, which is still a scenario using Linux containers running on the VM setup in the Mac by the "Docker for Windows" setup. But further testing and feedback on Mac environments and Windows Containers, from the community, will be appreciated.
## DC/OS
### Prerequisites
* 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.
* A DC/OS cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-deployment) to create one.
* The `dcos` CLI (DC/OS docs: [Installing the CLI](https://dcos.io/docs/1.8/usage/cli/install/))
### Prepare the Cluster
1. Install Marathon-LB. ([DC/OS docs](https://dcos.io/docs/1.8/usage/service-discovery/marathon-lb/usage/))
1. Mount an Azure file share on each agent of the cluster at `/mnt/share`. See the Azure Container Service [documentation](https://docs.microsoft.com/en-us/azure/container-service/container-service-dcos-fileshare) for guidance.
1. Copy your private registry credentials to the mounted file share as described in the Azure Container Service [documentation](https://docs.microsoft.com/en-us/azure/container-service/container-service-dcos-acr).
### Deploy the Application
1. Build the eShopOnContainers Docker images, and push them to your registry.
1. Open an SSH tunnel to your cluster as described in the ACS documentation: [Connect with an ACS cluster](https://docs.microsoft.com/en-us/azure/container-service/container-service-connect#connect-to-a-dcos-or-swarm-cluster)
1. Open a PowerShell window with the `dcos` CLI on your path.
1. Navigate to your local `eShopOnContainers` repository's `dcos` directory.
1. Run `generate-config.ps1` to generate configuration for the eShopOnContainers services. The script requires URLs for your cluster's agents and your private registry. Your agents' URL is of the form `[dns prefix]agents.[Azure region].cloudapp.azure.com`:
>```powershell
>./generate-config.ps1 -agentsFqdn mydcosagents.centralus.cloudapp.azure.com -registry myregistry.azurecr.io
>```
6. Use the `dcos` CLI to deploy the application:
>```powershell
>dcos marathon group add eShopOnContainers.json
>```
## Sending feedback and pull requests ## Sending feedback and pull requests
As mentioned, we'd appreciate to your feedback, improvements and ideas. As mentioned, we'd appreciate to your feedback, improvements and ideas.
You can create new issues at the issues section, do pull requests and/or send emails to eshop_feedback@service.microsoft.com You can create new issues at the issues section, do pull requests and/or send emails to eshop_feedback@service.microsoft.com


+ 9
- 0
dcos/generate-config.ps1 View File

@ -0,0 +1,9 @@
Param(
[Parameter(Mandatory=$true)][string]$agentsFqdn,
[Parameter(Mandatory=$true)][string]$registry
)
(Get-Content template.json) |
Foreach-Object {
$_.Replace("AGENTS_FQDN", $agentsFqdn).Replace("REGISTRY", $registry)
} | Set-Content eShopOnContainers.json

+ 439
- 0
dcos/template.json View File

@ -0,0 +1,439 @@
{
"id": "/eshop",
"apps": [
{
"id": "basket-data",
"container": {
"type": "DOCKER",
"docker": {
"image": "redis:3.2-alpine",
"network": "BRIDGE",
"portMappings": [
{
"hostPort": 6379,
"labels": {
"VIP_0": "eshopbasket-data:6379"
}
}
]
}
},
"healthChecks": [
{
"protocol": "TCP",
"gracePeriodSeconds": 30,
"intervalSeconds": 60,
"timeoutSeconds": 30,
"maxConsecutiveFailures": 3,
"port": 6379
}
],
"cpus": 0.1,
"mem": 1024,
"instances": 1
},
{
"id": "basket-api",
"dependencies": [
"basket-data",
"rabbitmq"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80/basket",
"ConnectionString": "eshopbasket-data.marathon.l4lb.thisdcos.directory",
"EventBusConnection": "eshoprabbitmq.marathon.l4lb.thisdcos.directory",
"IdentityUrl": "http://AGENTS_FQDN/id"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/basket.api",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/basket"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "catalog",
"dependencies": [
"rabbitmq",
"sql-data"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80/catalog",
"ConnectionString": "Server=eshopsql-data.marathon.l4lb.thisdcos.directory;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
"EventBusConnection": "eshoprabbitmq.marathon.l4lb.thisdcos.directory",
"ExternalCatalogBaseUrl": "http://AGENTS_FQDN/catalog"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/catalog.api",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/catalog"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "identity",
"dependencies": [
"sql-data"
],
"env": {
"MvcClient": "http://AGENTS_FQDN/webmvc",
"SpaClient": "http://AGENTS_FQDN",
"ASPNETCORE_URLS": "http://0.0.0.0:80/id",
"ConnectionStrings__DefaultConnection": "Server=eshopsql-data.marathon.l4lb.thisdcos.directory;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
"ASPNETCORE_ENVIRONMENT": "Development"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/identity.api",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/id"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "ordering",
"dependencies": [
"rabbitmq",
"sql-data"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80/ordering",
"ConnectionString": "Server=eshopsql-data.marathon.l4lb.thisdcos.directory;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
"EventBusConnection": "eshoprabbitmq.marathon.l4lb.thisdcos.directory",
"IdentityUrl": "http://AGENTS_FQDN/id"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/ordering.api",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/ordering"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "rabbitmq",
"container": {
"type": "DOCKER",
"docker": {
"image": "rabbitmq:3.6-alpine",
"network": "BRIDGE",
"portMappings": [
{
"hostPort": 5672,
"labels": {
"VIP_0": "eshoprabbitmq:5672"
}
}
]
}
},
"healthChecks": [
{
"protocol": "TCP",
"gracePeriodSeconds": 30,
"intervalSeconds": 60,
"timeoutSeconds": 30,
"maxConsecutiveFailures": 3,
"port": 5672
}
],
"cpus": 0.1,
"mem": 256,
"instances": 1
},
{
"id": "sql-data",
"container": {
"type": "DOCKER",
"docker": {
"image": "microsoft/mssql-server-linux:ctp1-4",
"network": "BRIDGE",
"portMappings": [
{
"hostPort": 1433,
"labels": {
"VIP_0": "eshopsql-data:1433"
}
}
]
}
},
"env": {
"ACCEPT_EULA": "Y",
"SA_PASSWORD": "Pass@word"
},
"healthChecks": [
{
"protocol": "TCP",
"gracePeriodSeconds": 30,
"intervalSeconds": 60,
"timeoutSeconds": 30,
"maxConsecutiveFailures": 3,
"port": 1433
}
],
"cpus": 0.1,
"mem": 1024,
"instances": 1
},
{
"id": "webmvc",
"dependencies": [
"basket-api",
"catalog",
"identity",
"ordering"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80/webmvc",
"BasketUrl": "http://AGENTS_FQDN/basket",
"CallBackUrl": "http://AGENTS_FQDN/webmvc",
"CatalogUrl": "http://AGENTS_FQDN/catalog",
"IdentityUrl": "http://AGENTS_FQDN/id",
"OrderingUrl": "http://AGENTS_FQDN/ordering"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/webmvc",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/webmvc"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "webspa",
"dependencies": [
"basket-api",
"catalog",
"identity",
"ordering"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80",
"BasketUrl": "http://AGENTS_FQDN/basket",
"CallBackUrl": "http://AGENTS_FQDN/webmvc",
"CatalogUrl": "http://AGENTS_FQDN/catalog",
"IdentityUrl": "http://AGENTS_FQDN/id",
"OrderingUrl": "http://AGENTS_FQDN/ordering"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/webspa",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"healthChecks": [
{
"path": "/hc",
"protocol": "HTTP",
"gracePeriodSeconds": 60,
"intervalSeconds": 60,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
},
{
"id": "webstatus",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://0.0.0.0:80/webstatus",
"BasketUrl": "http://AGENTS_FQDN/basket",
"CatalogUrl": "http://AGENTS_FQDN/catalog",
"IdentityUrl": "http://AGENTS_FQDN/id",
"OrderingUrl": "http://AGENTS_FQDN/ordering",
"mvc": "http://AGENTS_FQDN/webmvc",
"spa": "http://AGENTS_FQDN/webspa"
},
"instances": 1,
"cpus": 0.1,
"mem": 128,
"container": {
"docker": {
"image": "REGISTRY/eshop/webstatus",
"forcePullImage": true,
"portMappings": [
{
"containerPort": 80
}
],
"network": "BRIDGE"
}
},
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "AGENTS_FQDN",
"HAPROXY_0_MODE": "http",
"HAPROXY_0_PATH": "/webstatus"
},
"uris": [
"file:///mnt/share/docker.tar.gz"
]
}
]
}

Loading…
Cancel
Save