Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

9 Docker .NET App Templates: A Complete Guide

DZone's Guide to

9 Docker .NET App Templates: A Complete Guide

An in-depth guide to setting up nine full .NET application templates in docker with step-by-step instructions.

· Web Dev Zone
Free Resource

Get deep insight into Node.js applications with real-time metrics, CPU profiling, and heap snapshots with N|Solid from NodeSource. Learn more.

This is the second blog of a three part blog series that discusses the automated deployment of .NET applications on both Linux and Windows containers.

In the first blog, we covered the deployment of very basic ASP.NET and ASP.NET MVC applications on Linux containers using HyperForm, a deployment automation platform that simplifies the application journey to containers. The blog covered 6 application templates that include Nginx and Apache HTTP for reverse proxy.

In this blog, we will cover the detailed steps for Dockerizing a more advanced.NET application that can connect to multiple databases — including SQLite, PostgreSQL, and Microsoft SQL Server. The application covered in this blog is a simple Microsoft.NET application called "Names Directory" that allows users to view, add, and remove names stored on a connected database. The source code for this application along with the Dockerfile used to build the.NET Docker image is available on GitHub. (https://github.com/dchqinc/docker-dotnet)

This blog includes 9 Docker Multi-Tier.NET application templates that leverage Nginx or Apache HTTP for reverse proxy and SQLite, PostgreSQL, or Microsoft SQL Server as the underlying database. The unique thing about this application is that it enables users to leverage environment variables to specify the database connection details and to use "dotnet ef database update" to automatically initialize the connected database - even if it's initially empty.

To run and manage the simple Docker.NET "Names Directory” applications on 18 different clouds and virtualization platforms (including HyperGrid, Hyper-V, vSphere, OpenStack, AWS, Rackspace, Microsoft Azure, DigitalOcean, IBM SoftLayer, etc.), make sure that you either:

Picture

Background

Containerizing enterprise applications is still a challenge, mostly because existing application composition frameworks do not address complex dependencies, external integrations, or application life-cycle management tasks post-provision.

HyperForm, available in hosted and on-premise versions, addresses all of these challenges and simplifies the containerization of enterprise applications through an advanced application composition framework that extends Docker Compose supporting:

  • Advanced plug-ins that can be invoked at more than 20 different lifecycle stages to enable service discovery, on-the-fly containerization and application storage automation, and
  • Data injection to support complex application dependencies.

The plug-ins framework, which relies on custom scripts that can be written in BASH, PowerShell, Perl, Ruby, or Python, enables advanced application deployment and in the application templates in this blog, facilitates both service discovery for web servers (Nginx and Apache HTTP) and automatic database initialization for the .NET application.

Once an application is deployed, a user can access monitoring, alerts, and notifications, continuous delivery using Jenkins, application backups, scale in/out, in-browser terminal to access the containers, log viewing, and container updates using custom plug-ins.

Why Even Bother With Containers?

Containers have been the driving force behind efforts to accelerate software development, cloud migration, and the modernization of legacy applications. The main advantages of containers are:

  • Application Portability – Docker containers run exactly the same on any Linux host. This eliminates the challenge of deploying applications across different compute infrastructure (e.g. local developer machine, vSphere VM, or in the cloud).
  • Higher Server Density – The light-weight nature of containers allow developers to optimize server utilization for their application workloads by running more containers on the same host while achieving the same isolation and resource allocation benefits of virtual machines.

For developers who are still wondering what the exact differences are between virtual machines and containers, here’s a list of the key differences.

Application Storage Overhead

  • Virtual Machines: Each application workload runs on a separate virtual machine – which typically needs Gigabytes of OS overhead.
  • Containers: Containers can run in isolation on the same physical or virtual machine – in which one common OS is used for all containers. The Docker Engine overhead is pretty small – i.e. megabytes.

Instantiation

  • Virtual Machines: Boot up time of both the OS and the application
  • Containers: Application instantiation time only – i.e. time to spin up Linux processes

Resource Allocation

  • Virtual Machines: Generally rigid. Virtual CPU and Memory are typically pre-allocated to a VM and are hard to change post-provision – depending on the virtualization platform or cloud provider used.
  • Containers: Generally flexible. CPU and Memory maximum limits can be defined for containers if desired (using the cpu_shares and mem_limit parameters). By default, containers can continue to consume the resources available on the underlying machine. With HyperForm, the minimum limits for CPU and Memory can also be defined — allowing users to place application workloads on machines that have enough CPU and Memory resources. You can read more about this here: http://dchq.co/docker-compose.html#docker-nodejs.

Building The Docker Images Using Microsoft/Dotnet:latest

You can use HyperForm to automate the building of the Docker image as well as pushing the new images to one of the registered Docker registries.

Of course, if you're using Docker Hub, then you have the option to use the Automated Builds feature. However, if you're using a private registry, then HyperForm can provide the needed image build automation.

The .NET example used in this blog is available on GitHub: (https://github.com/dchqinc/docker-dotnet.git)

Once logged in to HyperForm (either the hosted DCHQ.io or on-premise version), a user can navigate to Automate > Image Build and then click on the + button to create a new Dockerfile (Git/GitHub/BitBucket) image build.

Provide the required values as follows:

  • Git URLhttps://github.com/dchqinc/docker-dotnet.git
  • Git Branch – This field is optional — but a user can specify a branch from a GitHub project. The default branch is master.
  • Git Credentials – A user can store the credentials to a private GitHub repository securely in HyperForm. This can be done by navigating to Cloud Providers and clicking on the + to select Credentials
  • Cluster – The building of Docker images is orchestrated through the HyperForm agent. As a result, a user needs to select a cluster on which an agent will be used to execute the building of Docker images. If a cluster has not been created yet, please refer to this section to either register already running hosts or automate the provisioning of new virtual infrastructure.
  • Push to Registry – A user can push the newly created image on either a public or private repository on Docker Hub, Nexus, Artifactory or Quay. To register a Docker registry account, a user should navigate to Cloud Providers and clicking on the + to select Docker Registries.
  • Repository – This is the name of the repository on which the image will be pushed. For example, our image was pushed to dchq/dotnet-names-directory:latest.
  • Tag – This is the tag name that you would like to give for the new image. The supported tag names in HyperForm include:
    • {{date}} — Formatted date
    • {{timestamp}} — The full time-stamp
  • Cron Expression – A user can schedule the building of Docker images using out-of-box cron expressions. This facilitates daily and nightly builds for users.
  • Pre Build Plugins and Post Build Plugins – A user can execute plug-ins on the machines used to run the image builds – e.g. installing Linux libraries or running post image build cleanup scripts.
  • Who can Manage - A user can mark this build as private or share it with other users or groups.

Once the required fields are completed, a user can click Save. Picture A user can then click on the Play Button to build the Docker image on-demand. Picture Here's the actual Dockerfile used to build the Docker image for the.NET Names Directory application.

https://github.com/dchqinc/docker-dotnet/blob/master/Dockerfile

Building The YAML-Based Application Templates That Can Re-Used On Any Linux Host Running Anywhere

HyperForm is fully compatible with Docker Compose: (https://docs.docker.com/compose/compose-file/).

The platform however provides core (optional) enhancements to Docker Compose supporting advanced plug-ins that can be invoked at more than 20 different lifecycle stages to enable service discovery, on-the-fly containerization, and application storage automation.

It also supports cross-image environment variable bindings, automatic container IP retrieval and injection, and additional parameters like mem_min, publish_all, cluster_size, and registry_id. The service discovery framework takes care of re-configuring the load balancers and other application components when a cluster is scaled in/out or when the containers are stopped/started.

To create an application template, a user can log into HyperForm (either the hosted DCHQ.io or on-premise version), navigate to Blueprints > App/Machine and then click on the + button to create a new Docker Compose template.

We have created 6 application templates for the basic ASP.NET "Hello MVC" and “Hello Web” applications but with different web servers for reverse proxy and load balancing. .NET with Embedded-SQLite:

dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: true
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=sqlight
    - database_url=Filename=.\\sqlight_db.db


nginx:
  image: nginx:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: 0H1Nk
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - servers=server {{dotnet | container_private_ip}}:5000;
        # Use container_hostname if you're using Weave networking
        #- servers=server {{dotnet | container_hostname}}:5000;
dotnet:
  image: dchq/dotnet-names-directory:latest
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=sqlight
    - database_url=Filename=.\\sqlight_db.db


http-lb:
  image: httpd:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: uazUi
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - BalancerMembers=BalancerMember http://{{dotnet | container_private_ip}}:5000
        # Use container_hostname if you're using Weave networking
        #- BalancerMembers=BalancerMember http://{{dotnet | container_hostname}}:5000
dotnet:
  image: dchq/dotnet-names-directory:latest
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=sqlight
    - database_url=Filename=.\\sqlight_db.db


dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: true
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=postgres
    - database_url=Host={{postgres | container_private_ip}};Database={{postgres | POSTGRES_DB}};Username={{postgres | POSTGRES_USER}};Password={{postgres | POSTGRES_PASSWORD}}
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false
postgres:
  image: postgres:latest
  host: host1
  mem_min: 300m
  environment:
    - POSTGRES_DB=NameDirectory
    - POSTGRES_USER=root
    - POSTGRES_PASSWORD={{alphanumeric | 8}}


nginx:
  image: nginx:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: 0H1Nk
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - servers=server {{dotnet | container_private_ip}}:5000;
        # Use container_hostname if you're using Weave networking
        #- servers=server {{dotnet | container_hostname}}:5000;
dotnet:
  image: dchq/dotnet-names-directory:latest
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=postgres
    - database_url=Host={{postgres | container_private_ip}};Database={{postgres | POSTGRES_DB}};Username={{postgres | POSTGRES_USER}};Password={{postgres | POSTGRES_PASSWORD}}
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false
postgres:
  image: postgres:latest
  host: host1
  mem_min: 300m
  environment:
    - POSTGRES_DB=NameDirectory
    - POSTGRES_USER=root
    - POSTGRES_PASSWORD={{alphanumeric | 8}}


http-lb:
  image: httpd:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: uazUi
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - BalancerMembers=BalancerMember http://{{dotnet | container_private_ip}}:5000
        # Use container_hostname if you're using Weave networking
        #- BalancerMembers=BalancerMember http://{{dotnet | container_hostname}}:5000
dotnet:
  image: dchq/dotnet-names-directory:latest
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=postgres
    - database_url=Host={{postgres | container_private_ip}};Database={{postgres | POSTGRES_DB}};Username={{postgres | POSTGRES_USER}};Password={{postgres | POSTGRES_PASSWORD}}
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false
postgres:
  image: postgres:latest
  host: host1
  mem_min: 300m
  environment:
    - POSTGRES_DB=NameDirectory
    - POSTGRES_USER=root
    - POSTGRES_PASSWORD={{alphanumeric | 8}}


dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: true
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=mssql
    - database_url=Server=tcp:dchq-sql-server.database.windows.net,1433;Initial Catalog=NameDirectory;Persist Security Info=False;User ID={your_username};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false


nginx:
  image: nginx:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: 0H1Nk
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - servers=server {{dotnet | container_private_ip}}:5000;
        # Use container_hostname if you're using Weave networking
        #- servers=server {{dotnet | container_hostname}}:5000;
dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: false
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=mssql
    - database_url=Server=tcp:dchq-sql-server.database.windows.net,1433;Initial Catalog=NameDirectory;Persist Security Info=False;User ID={your_username};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false


http-lb:
  image: httpd:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: uazUi
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - BalancerMembers=BalancerMember http://{{dotnet | container_private_ip}}:5000
        # Use container_hostname if you're using Weave networking
        #- BalancerMembers=BalancerMember http://{{dotnet | container_hostname}}:5000
dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: false
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=mssql
    - database_url=Server=tcp:dchq-sql-server.database.windows.net,1433;Initial Catalog=NameDirectory;Persist Security Info=False;User ID={your_username};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false


Environment Variable Bindings Across Images

A user can create cross-image environment variable bindings by making a reference to another image’s environment variable or container values. For example, the database_url environment variable in the.NET container is referencing the container private IP, database name, database username, and database password of the PostgreSQL container in order allow.NET to establish a connection with the database:

 database_url=Host={{postgres | container_private_ip}};Database={{postgres | POSTGRES_DB}};Username={{postgres | POSTGRES_USER}};Password={{postgres | POSTGRES_PASSWORD}} 

The main advantage here is that users do not have to hard-code these values, thus preventing container name or port conflicts. Moreover, users can randomize sensitive information (like passwords) using {{alphanumeric | 8}} closures and pass this information to other containers at run-time without worrying about visibility to passwords.

Here is a list of supported environment variable values:

  • {{alphanumeric | 8}} – Creates a random 8-character alphanumeric string. This is most useful for creating random passwords.
  • {{Image Name | ip}} – Allows you to enter the host IP address of a container as a value for an environment variable. This is most useful for allowing the middleware tier to establish a connection with the database.
  • {{Image Name | container_hostname}} or {{Image Name | container_ip}} – Allows you to enter the name of a container as a value for an environment variable. This is most useful for allowing the middleware tier to establish a secure connection with the database (without exposing the database port).
  • {{Image Name | container_private_ip}} – Allows you to enter the internal IP of a container as a value for an environment variable. This is most useful for allowing the middleware tier to establish a secure connection with the database (without exposing the database port).
  • {{Image Name | port_Port Number}} – Allows you to enter the Port number of a container as a value for an environment variable. This is most useful for allowing the middleware tier to establish a connection with the database. In this case, the port number specified needs to be the internal port number – i.e. not the external port that is allocated to the container. For example, {{PostgreSQL | port_5432}} will be translated to the actual external port that will allow the middleware tier to establish a connection with the database.
  • {{Image Name | Environment Variable Name}} – Allows you to enter the value an image’s environment variable into another image’s environment variable. The use cases here are endless – as most multi-tier applications will have cross-image dependencies.

Using the Host Parameter to Deploy a Highly-Available Docker.NET Application

When creating application templates in HyperForm, the host parameter allows you to specify the host you would like to use for container deployments. This is possible if you have selected Weave as the networking layer when creating your clusters. That way you can ensure high-availability for your application server clusters across different hosts (or regions) and you can comply with affinity rules to ensure that the database runs on a separate host for example. Here are the values supported for the host parameter:

  • host1, host2, host3, etc. — Selects a host randomly within a data-center (or cluster) for container deployments
  • IP Address 1, IP Address 2, etc. — Allows a user to specify the actual IP addresses to use for container deployments
  • Hostname 1, Hostname 2, etc. — Allows a user to specify the actual hostnames to use for container deployments
  • Wildcards (e.g. “db-”, or “app-srv-”) — To specify the wildcards to use within a hostname

Plug-Ins to Configure Web Servers and.NET Servers at Request Time and Post-Provision

HyperForm simplifies the containerization of enterprise applications through an advanced application composition framework that extends Docker Compose supporting

  • advanced plug-ins that can be invoked at more than 20 different lifecycle stages to enable service discovery, on-the-fly containerization and application storage automation, and
  • data injection to support complex application dependencies.

Across all these application templates, you will notice that some of the containers are invoking plug-ins at different life-cycle stages in order to configure the container.

The Plug-ins framework, which relies on custom scripts that can be written in BASH, PowerShell, Perl, Ruby or Python, enables advanced application deployment and in this case, facilitates both service discovery for the web servers (Nginx and Apache HTTP) and automatic database initialization for the.NET application.

These plug-ins can be created by navigating to Blueprints > Plug-ins. Once the BASH script is provided, the HyperForm agent will execute this script inside the container. A user can specify arguments that can be overridden at request time and post-provision. Anything preceded by the $ sign is considered an argument -- for example, $zip_url can be an argument that allows developers to specify the download URL for a ZIP file. This can be overridden at request time and post-provision.

The plug-in ID needs to be provided when defining the YAML-based application template. For example, to invoke a BASH script plug-in for Nginx, we would reference the plug-in ID as follows:

nginx:
  image: nginx:latest
  publish_all: true
  mem_min: 50m
  host: host1
  plugins:
    - !plugin
      id: 0H1Nk
      restart: true
      lifecycle: on_create, post_scale_out:dotnet, post_scale_in:dotnet
      arguments:
        # Use container_private_ip if you're using Docker networking
        - servers=server {{dotnet | container_private_ip}}:5000;


In the example templates, we are invoking 3 BASH script plug-ins.

  • Nginx plug-in ID is 0H1Nk
  • Apache HTTP Server (httpd) plug-in ID is uazUi
  • .NET Database Initialization plug-in ID is hHjF0

The service discovery framework in HyperForm provides event-driven life-cycle stages that executes custom scripts to re-configure application components. This is critical when scaling out clusters for which a load balancer may need to be re-configured or a replica set may need to be re-balanced.

You will notice that the Nginx and Apache HTTP plug-ins are getting executed during these different stages or events:

  • When the Nginx or the Apache HTTP container is created — In this case, the container IP's of the application servers are injected into the default configuration file to facilitate the load balancing to the right services.
  • When the.NET application server cluster is scaled in or scale out — In this case, the updated container IP's of the application servers are injected into the default configuration file to facilitate the load balancing to the right services.
  • When the.NET application servers are stopped or started — In this case, the updated container IP's of the application servers are injected into the default configuration file to facilitate the load balancing to the right services.

So the service discovery framework here is doing both service registration (by keeping track of the container IP's and environment variable values) and service discovery (by executing the right scripts during certain events or stages).

The lifecycle parameter in plug-ins allows you to specify the exact stage or event to execute the plug-in. If no lifecycle is specified, then by default, the plug-in will be execute on_create. Here are the supported lifecycle stages:

  • on_create — Executes the plug-in when creating the container
  • on_start — Executes the plug-in after a container starts
  • on_stop — Executes the plug-in before a container stops
  • on_destroy — Executes the plug-in before destroying a container
  • pre_create — Executes the plug-in before creating the container
  • post_create — Executes the plug-in after the container is created and running
  • post_start[:Node] — Executes the plug-in after another container starts
  • post_stop[:Node] — Executes the plug-in after another container stops
  • post_destroy[:Node] — Executes the plug-in after another container is destroyed
  • post_scale_out[:Node] — Executes the plug-in after another cluster of containers is scaled out
  • post_scale_in[:Node] — Executes the plug-in after another cluster of containers is scaled in
  • cron(0 1 1 * * ?) — Schedules the plug-in based on a specified cron expression. Here are someexamples for cron expressions.
  • exec_on_machine — Executes the plug-in on the underlying machine. This lifecycle can be used with other container life cycles. For example, exec_on_machine pre_create will execute the plug-in on the machine before creating the container.

In order to automatically initialize a connected database, the.NET container needs to run "dotnet ef database update" post-provision — as only then is the .NET container aware of the database connection details that are passed using environment variables. Of course this plug-in will not be needed if the database connection details are hard-coded in the appsettings.json file.

https://github.com/dchqinc/docker-dotnet/blob/master/appsettings.json

With the exception of the embedded SQLite application example, all other application templates that are connected to either PostgreSQL or Microsoft SQL Server are invoking the exact same BASH script plug-in (plug-in ID: hHjF0).

Here's an example of how this plug-in is being invoked:

dotnet:
  image: dchq/dotnet-names-directory:latest
  publish_all: true
  #ports:
  #  - 5000:5000
  host: host1
  mem_min: 200m
  environment:
    - database_driverClassName=mssql
    - database_url=Server=tcp:dchq-sql-server.database.windows.net,1433;Initial Catalog=NameDirectory;Persist Security Info=False;User ID={your_username};Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
  plugins:
    - !plugin
      id: hHjF0
      lifecycle: post_create
      restart: false


The BASH script plug-in was created by navigating to Blueprints > Plug-ins and looks something like this:

#!/bin/bash

dotnet restore
dotnet ef database update
dotnet run


Provisioning the Underlying Infrastructure on Any Cloud

Once an application is saved, a user can deploy the application to a cluster (or pool of servers) that is already available or provision infrastructure on 18 different cloud end-points including HyperGrid, VMware vSphere, OpenStack, CloudStack, Amazon Web Services, Rackspace, Microsoft Azure, DigitalOcean, IBM SoftLayer, and many others.

For detailed instructions on automating infrastructure provisioning, please refer to the detailed documentation here:

http://dchq.co/docker-infrastructure-as-a-service.html

The recorded demo in this blog uses a cluster of provisioned VM’s on Microsoft Azure Resource Manager. For instructions on automating the provisioning of VM’s on ARM using reusable YAML templates, please refer to the detailed documentation here.

http://dchq.co/docker-azure-resource-manager.html

Deploying the ASP.NET Application on the Azure Cluster

A user can deploy the.NET applications on any of the available clusters. On the HyperForm SaaS Platform (http://dchq.io) – a public cluster set up on HyperGrid infrastructure is available for free application deployment (up to 2GB of Memory). This cluster is meant for DEV/TEST deployments only and is refreshed every 2 to 3 months.

Alternatively users can register their own cloud providers and create their own clusters. To deploy the application on an already created Azure cluster, for example, a user can navigate to the Library page, click on Customize and then select the available HyperGrid cluster.

Picture

Accessing the In-Browser Terminal for the Running Containers

A command prompt icon should be available next to the containers’ names on the Apps page. This allows users to enter the container using a secure communication protocol through the agent message queue. A white list of commands can be defined by the Tenant Admin to ensure that users do not make any harmful changes on the running containers.

For the.NET deployment for example, we used the command prompt to make sure that the application code is indeed under the /app directory. Picture

Monitoring The CPU, Memory, and I/O Utilization Of The Running Containers

Once the application is up and running, users can monitor the CPU, Memory, and I/O of the running containers to get alerts when these metrics exceed a pre-defined threshold. This is especially when performing functional and load testing.

A user can perform historical monitoring analysis and correlate issues to container updates or build deployments. This can be done by clicking on the Stats link. A custom date range can be selected to view CPU, Memory, and I/O historically. Picture

Replacing (Redeploying) Containers When New Images Are Pushed Into A Registry

For developers wishing to follow the “immutable” containers model by rebuilding Docker images containing the application code and spinning up new containers with every application update, HyperForm provides an automated container replacement workflow that pulls that latest image in a registry and replaces the running container with the latest image.

To set up a container redeployment (or replacement) profile, a user can select Container Redeploy Profile from the Action menu. Picture A user can then select one of the stored Docker registries and enter the name of the image that should be used when replacing the running container. To register a Docker Hub, Nexus, Artifactory, or Quay account, a user should navigate to Cloud Providers and clicking on the + to select Docker Registries. Picture

Scaling Out the .NET Application

If the running application becomes resource constrained, a user can scale out the application to meet the increasing load. Moreover, a user can schedule the scale out during business hours and the scale in during weekends, for example.

To scale out the cluster of the.NET containers from 1 to 2, a user can click on the Actions menu of the running application and then select Scale Out. A user can then specify the new size for the cluster and then click on Run Now.

The service discovery plug-in configured for the load balancer (i.e. Nginx or Apache HTTP) will be automatically triggered to inject the container IP's of the new application servers into the default configuration file to facilitate the load balancing to the right services. Picture An application time-line is available to track every change made to the application for auditing and diagnostics. This can be accessed from the expandable menu at the bottom of the page of a running application. Picture Alerts and notifications are available for when containers or hosts are down or when the CPU and Memory Utilization of either the hosts or containers exceed a defined threshold.

Executing Plug-Ins Post-Provision to Update an Application

If a user would like to make simple changes to the.NET application then a custom script plug-in can be invoked to make such updates.

The plug-ins framework, which relies on custom scripts that can be written in BASH, PowerShell, Perl, Ruby, or Python, enables advanced application deployment and facilitates quick integration with any external service – including storage, networking or monitoring solutions.

To do this, a user must first create a plug-in by navigating to Blueprints > Plug-ins.

Then from the application’s page, a user can select Plug-ins Run from the Actions menu. Picture As user can then search for the plug-in and override the available arguments if needed (e.g. URL to fetch the latest.NET files). For ASP.NET Dynamic Compilation, a container restart may not be needed. However for other updates that require a quick restart of the container, then the Restart toggle can be selected. Picture

Conclusion

Containerizing enterprise applications is still a challenge mostly because existing application composition frameworks do not address complex dependencies, external integrations, or application life-cycle management tasks post-provision.

HyperForm, available in hosted and on-premise versions, addresses all of these challenges and simplifies the containerization of enterprise applications through an advanced application composition framework that extends Docker Compose supporting

  • Advanced plug-ins that can be invoked at more than 20 different lifecycle stages to enable service discovery, on-the-fly containerization and application storage automation, and
  • Data injection to support complex application dependencies.

To run and manage the simple Docker ASP.NET "Hello MVC" and “Hello Web” applications on 18 different clouds and virtualization platforms (including HyperGrid, vSphere, OpenStack, AWS, Rackspace, Microsoft Azure, Google Compute Engine, DigitalOcean, IBM SoftLayer, etc.), make sure that you either:

Node.js application metrics sent directly to any statsd-compliant system. Get N|Solid

Topics:
docker ,containers ,.net

Published at DZone with permission of Amjad Afanah, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}