Deploying Denodo in Amazon Elastic Container Service (ECS) using EC2

Applies to: Denodo 8.0
Last modified on: 04 Mar 2021
Tags: Administration Amazon EC2 Amazon ECS Docker

Download document

You can translate the document:

Amazon Elastic Container Service (Amazon ECS) is a container management service that makes it easy to run, stop, and manage Docker containers on a cluster, letting you launch and stop container-based applications with simple API calls.

To use Amazon ECS you need a cluster that can be created within a new or an existing VPC. Then, after a cluster is up and running, the task definitions and services created will specify which Docker images run across the clusters. The container images are stored in and pulled from container registries, which may exist within the AWS infrastructure (Amazon ECR) or outside.

The services and tasks launched can use one of the following Amazon ECS launch types:

  • AWS Fargate: The Fargate launch type allows running containerized applications without the need for provisioning or managing the backend infrastructure (Amazon EC2 instances). Just registering the task definition will make AWS Fargate launch the container.
  • Amazon EC2: The EC2 launch type allows running containerized applications on a cluster of custom Amazon EC2 instances.

In this article, we will show how to run Docker images of Denodo on an Amazon ECS cluster using EC2 instance, for images stored in Amazon ECR.

AWS Command Line Interface

The AWS Command Line Interface (AWS CLI) is an open-source tool that can be used for administering the AWS resources and we will use it extensively in the article, we will assume that it is installed and up to date as a prerequisite for executing the commands presented below.

In addition to using the AWS CLI to access Amazon ECS resources, you can use the Amazon ECS CLI, which provides high-level commands to simplify creating, updating, and monitoring clusters and tasks from a local development environment using Docker Compose.

Although it is also possible to launch our first cluster using the Amazon ECS first-run wizard, in this article we have chosen to use the AWS CLI because usually, the commands are self-explanatory and also because it is possible to use them and test them easily in any custom AWS deployment.

Amazon ECS using EC2

The Amazon ECS EC2 launch type allows you to run your containerized applications on a cluster of Amazon EC2 instances that you manage.

List of Prerequisites

This article assumes that there is an environment already configured with the tools required to deploy a Docker image of Denodo in AWS, in other cases, it might be needed to install or configure something else before continuing with the next section. In summary, you need:

  • A valid AWS account with enough privileges to build all the AWS elements involved in the deployment of the Denodo image.
  • An IAM entity, to avoid accessing AWS directly with the credentials of our AWS account. With the AWS Identity and Access Management (IAM) service, we can have restricted permissions and policies over the AWS resources. In This case, we need to set IAM permissions to allow for Amazon EC2 access. For more information about IAM permissions for Amazon EC2, see IAM policies for Amazon EC2 in the Amazon EC2 User Guide for Linux Instances.
  • To execute tasks, you will need a Task Role, choose an IAM role that provides permissions for containers in your task to make calls to AWS APIs on your behalf. For tasks that use the EC2 launch type, these permissions are usually granted by the Amazon ECS Container Instance IAM role. For more information, see Amazon ECS Container Instance IAM Role.
  • A Virtual Private Cloud (Amazon VPC) with public and private subnets (a list of subnet ids separated by commas - subnetIdList) for our clusters and a dedicated security group (securityGroupId). We want to expose the Denodo Server to the internet so in this guide we will be using a public subnet and assign a public IP to the ECS task, but you could use a private subnet configured with a NAT waterway with an elastic IP address.
  • You must specify an Amazon Machine Image (AMI) when you launch an EC2 instance and note the AMI ID. The AMI provides the information required to launch an instance. For more information, see the section Launch an EC2 Instance with the Amazon ECS AMI explained below in this article. 
  • The latest version of the AWS CLI, because although the AWS Management Console can be used to manage Amazon ECS, the AWS CLI allows you to build scripts that can automate common management tasks in Amazon ECS.
  • A locally accessible Docker image of Denodo. If you don’t have one you can check how to create your own Docker images for Denodo Platform Containers

AWS Permissions

An IAM entity (user, group, or role) must be set up with the privileges required by the AWS CLI for running the statements in this guide.

In this article, we have configured an IAM Role (roleARN) to use ECS and Fargate/EC2 services.

This IAM role must be able to list, push, and pull images in the ECR repository, which is granted with the following AWS managed policy:

  •  AmazonEC2ContainerRegistryPowerUser.

To grant someone permission to create an Amazon ECR repository with the Amazon ECR CreateRepository API operation, we must include the following action in their policy:

  • ecr:CreateRepository 

This IAM role must be able to list, push, and pull images in the ECR repository, which is granted with the following AWS managed policy:

  • ecsTaskExecutionRole

In addition, although this works automatically with the cluster creation, notice that Amazon ECS uses the service-linked role named AWSServiceRoleForECS to enable Amazon ECS to call AWS APIs on your behalf.

Configure the AWS CLI

To start with the AWS configuration, open a new console and execute the below AWS commands that will do the basic configuration of the AWS CLI.

Configure the AWS access keys for the AWS account by using the following command:

$ aws configure

When entering this command, the AWS CLI prompts for the following information:

  • AWS Access Key ID
  • AWS Secret Access Key
  • Default region name
  • Default output format

To read more about the AWS CLI configuration check the AWS CLI user guide.

At this point, you need to decide if you will configure the default AWS CLI profile or if you want to create a custom profile. If you create a custom profile some of the commands in the rest of the guide will require an additional parameter to specify the profile to use (--profile profilename) so for simplicity, we will just configure the default profile in this guide. You can read more about named profiles in the  AWS Command Line Interface documentation.

Use these commands to configure the IAM role in the default profile:

$ aws configure set role_arn <roleARN>

$ aws configure set source_profile default

The role_arn parameter specifies the Amazon Resource Name (ARN) of an IAM role that you want to use to perform operations with the default profile. It will have this format: arn:aws:iam::<accountNumber>:role/<roleName>

The source_profile parameter identifies what profile to use to find credentials that have permission to assume the IAM role.

Create the Container Registry

Create a new Elastic Container Registry by providing a custom name for the repository:

$ aws ecr create-repository --repository-name <denodo-ecr>

Check that the denodo-ecr repository has been created successfully and obtain its repositoryUri from the output of the create-repository statement. The field repositoryUri will be used later to authenticate the local Docker client.

To obtain the repositoryUri value the following command can be used:

$ aws ecr describe-repositories --repository-name <denodo-ecr> --query "repositories[].repositoryUri"

Authenticate the Docker client to the new registry to push the Denodo image to the repository using the repositoryUri:

$ aws ecr get-login-password | docker login --username AWS --password-stdin <repositoryUri>

Finally, tag the Denodo image and push it to the Elastic Container Registry

$ docker tag denodo-platform:latest <repositoryUri>

$ docker push <repositoryUri>

$ aws ecr list-images --repository-name <denodo-ecr>

Create the ECS Cluster

To deploy the Denodo image on ECS it is necessary to create a cluster. By default, the AWS accounts have a default cluster. The benefit of using this default cluster is that you don't have to specify the --cluster <cluster-name> option in the subsequent commands. But if you do create your own cluster, then you must specify --cluster <cluster-name> for each command that you intend to use with that cluster.

$ aws ecs create-cluster --cluster-name <denodo-ecs-cluster>

It can take some time for the cluster to be available, but it is possible to check its status with the following command:

$ aws ecs describe-clusters --cluster <denodo-ecs-cluster>

Add EC2 Instances to the ECS Cluster

You must register an Amazon ECS container instance in your cluster before you can run tasks on it, for this the ECS Container instance must be running the Amazon ECS container agent. When you run tasks using the EC2 launch type, your tasks are placed on your active container instances to register into one of your clusters.

 

You can use the AWS CLI to launch Amazon EC2 instances. See Launching, listing, and terminating Amazon EC2 instances for more information.

First, you have to choose an Amazon Machine Image (AMI). If you are using an Amazon ECS-optimized AMI, the agent is already installed, but if you want to use a different operating system you can also install the ECS agent. You can use the describe-images command to list only the Linux AMIs that meet your needs. We will use the --owners parameter to display public AMIs owned by Amazon.

$ aws ec2 describe-images --owners self amazon

To launch an Amazon EC2 instance using the AMI you selected, use the run-instances command. We will launch the instance into our own virtual private cloud (VPC) with this command:

$ aws ec2 run-instances \

    --image-id <amiId> \

    --instance-type <t2.small> \

    --subnet-id <subnetId> \

    --security-group-ids <securityGroupId> \

    --iam-instance-profile Name=<ecsInstanceRole> \

    --user-data file://<userdata.txt>

  • Image-id: AMI Id of the AMI chosen. We will use <ami-0e4035ae3f70c400f> for this tutorial. For more information, see Finding a Suitable AMI in the Amazon EC2 User Guide.
  • Instance-type: Determines the hardware of the host computer used for your instance. We have selected t2.small since it is a low-cost general purpose instance type. For more information see Amazon EC2 Instance Types.
  • Subnet-id: The ID of the subnet to launch the instance into.
  • Security-group-ids: The id of our Security Group.
  • Iam-instance-profile: EC2 instance profiles allow you to attach an IAM role to your  EC2 instance. This allows any application running on the instance to access certain resources defined in the role policies, in our case our instance will need to access the cluster. See more information about this in Managing instance profiles (AWS CLI).
  • User-data: When you launch an instance in Amazon EC2, you have the option of passing user data to the instance. User data shell scripts are the easiest way to send instructions to an instance at launch. In our case, we will use this parameter to send to our instance the name of the cluster where we want it to be available, otherwise, the ECS agent will register the instance on the default ECS cluster. The steps to configure the EC2 instance to use our custom ECS cluster are these:
  1. Firstly create a userdata.txt shell script which uses echo to copy the cluster name variable to the configuration file  ecs.config. The ecs agent expects the cluster name inside this file, if this value is undefined, then the default cluster is assumed):

#!/bin/bash

echo ECS_CLUSTER=<denodo-ecs-cluster> >> /etc/ecs/ecs.config

  1. Pass the script file to the  --user-data parameter. With run-instances, the AWS CLI performs base64 encoding of the user data for you:

--user-data file://<userdata.txt>

For more information about instance user data, see User data with AWS CLI.

Initially, your instance appears in the pending status, but changes to the running state after a few minutes and it will be ready for use. You can check the status of your instance using describe-instances:

$ aws ec2 describe-instances \

    --filters Name=instance-type,Values=<t2.micro> Name=availability-zone,Values=<myregion>

Within a few minutes of launching your container instance, the Amazon ECS agent registers the instance with your cluster. You can list the container instances in a cluster by running the following command:

$ aws ecs list-container-instances --cluster <denodo-ecs-cluster>

Output:

{

    "containerInstanceArns": [

  "arn:aws:ecs:<region>:aws_account_id:container-instance/container_instance_Id"

    ]

}

After you have the ARN or ID of a container instance, you can use the following command to get valuable information on the instance, such as InstanceId, remaining and registered CPU, and memory resources.

$ aws ecs describe-container-instances \

    --cluster <denodo-ecs-cluster> \

    --container-instances <container_instance_Id>

Register an ECS Task

When the Amazon ECS container agent registers an instance into your cluster, the container instance reports its status as ACTIVE and its agent connection status as TRUE. This container instance can accept run task requests.

This example uses a simple task definition named denodo-task-definition that makes use of the Denodo container image hosted on the new repository denodo-ecr.

Also, notice that the Denodo Platform requires a valid license to run,  which can be obtained from a Denodo License Manager server or in some scenarios, like evaluation or Denodo Express, as a standalone license file:

  • If you intend to use a license managed by the License Manager you need an appropriate SolutionManager.properties configuration file that points to the License Manager server.

  • Alternatively, you can use a Denodo standalone license, if available.

In both scenarios, the Denodo server will expect a file in the <DENODO_HOME>/conf directory, either SolutionManager.properties or denodo.lic. The files could be added to the image, but in order to make this configuration dynamic, we will load the files from the task definition.

Hence, the solution proposed is based on the ability of the task definitions to specify environment variables, which can be used later to create files. Therefore, we can define an environment variable, for instance with the content of the SolutionManager.properties in base64 (which is more convenient than working with real text in the task definition) and materialize that variable value with the following command before starting the server:

echo $SOLUTION_MANAGER_CONF_B64 | base64 -d > /opt/denodo/conf/SolutionManager.properties;

Also, the task definition can be specified in a JSON file, which improves the readability and the management of the tasks because these definitions can be very large. Below you will find two examples of very simple task definitions, one per each type of license scenario.

Solution Manager

If there is a Denodo License Manager server running and accessible by the cluster then its connection details can be configured in the Solution Manager Configuration file.

As explained above, the task definition includes the content of the SolutionManager.properties configuration file encoded using base64. It is necessary to replace the SOLUTION_MANAGER_CONF_B64 placeholder in the task definition with the base64 encoding of the file. Note that you can get the base64 value with a command available in your OS or using an online service. So for instance, if you have the following SolutionManager.properties file:

# License Manager Configuration

com.denodo.license.host=solution-manager

com.denodo.license.port=10091

com.denodo.license.maxRetries=3

com.denodo.license.millisecondsBetweenRetries=5000

SolutionManager.properties

The equivalent base64 encoding would be:

IyBMaWNlbnNlIE1hbmFnZXIgQ29uZmlndXJhdGlvbgpjb20uZGVub2RvLmxpY2Vuc2Uua

G9zdD1zb2x1dGlvbi1tYW5hZ2VyCmNvbS5kZW5vZG8ubGljZW5zZS5wb3J0PTEwMDkxCm

NvbS5kZW5vZG8ubGljZW5zZS5tYXhSZXRyaWVzPTMKY29tLmRlbm9kby5saWNlbnNlLm1

pbGxpc2Vjb25kc0JldHdlZW5SZXRyaWVzPTUwMDAK

SolutionManager.properties in base64

At this point, you are ready to register the task definition, so take the following template and replace the placeholders SOLUTION_MANAGER_CONF_B64, repositoryUri, and ecsTaskExecutionRoleARN to start a Denodo container in the ECS cluster:

{

   "containerDefinitions": [

      {

         "environment": [

           {

             "name": "<SOLUTION_MANAGER_CONF_B64>",

             "value": "%SOLUTION_MANAGER_CONF_B64%"

           }

         ],

         "entryPoint": [

           "sh",

           "-c",

           "echo $SOLUTION_MANAGER_CONF_B64 | base64 -d > /opt/denodo/conf/SolutionManager.properties; ./denodo-container-start.sh --vdpserver"

         ],

         "essential": true,

         "image": "<repositoryUri>:latest",

         "name": "denodo",

         "portMappings": [

            {

               "containerPort": 9999,

               "hostPort": 9999,

               "protocol": "tcp"

            },

            {

               "containerPort": 9996,

               "hostPort": 9996,

               "protocol": "tcp"

            }

         ]

      }

   ],

   "executionRoleArn": "<ecsTaskExecutionRoleARN>",

   "family": "denodo-task-definition",

   "memory": "1024",

   "cpu": "256"

}

denodo-task-definition.json with Solution Manager

Once the task definition is saved to the JSON file denodo-task-definition.json you can create the task definition with the following command:

$ aws ecs register-task-definition --cli-input-json file://denodo-task-definition.json

Then, you can list the task definitions created with the following command:

$ aws ecs list-task-definitions

You can also check the details of a task definition:

$ aws ecs describe-task-definition --task-definition <taskDefinitionArn>

Standalone Licenses

To use a standalone license file, we are going to use the same solution as with the SolutionManager.properties file, but instead of defining an environment variable for the Solution Manager configuration file, it will be created for the license file.

The following template uses the environment variable LICENSE_B64 to create the license file in /opt/denodo/conf/denodo.lic. You just need to get the base64 encoding for your license file and replace <LICENSE_B64> with it:

{

   "containerDefinitions": [

      {

         "environment": [

           {

             "name": "<LICENSE_B64>",

             "value": "%LICENSE_B64%"

           }

         ],

         "entryPoint": [

           "sh",

           "-c",

           "echo $LICENSE_B64 | base64 -d > /opt/denodo/conf/denodo.lic; ./denodo-container-start.sh --vdpserver"

         ],

         "essential": true,

         "image": "<repositoryUri>:latest",

         "name": "denodo",

         "portMappings": [

            {

               "containerPort": 9999,

               "hostPort": 9999,

               "protocol": "tcp"

            },

            {

               "containerPort": 9996,

               "hostPort": 9996,

               "protocol": "tcp"

            }

         ]

      }

   ],

   "executionRoleArn": "<ecsTaskExecutionRoleARN>",

   "family": "denodo-task-definition",

   "memory": "1024",

   "cpu": "256"

}

denodo-task-definition.json with standalone licenses

Creating the Network Load Balancer

Create the load balancer

After you have registered your task and have launched a EC2 instance that is registered to your cluster, you can create the Network Load Balancer that will be used to distribute the requests to the Virtual DataPort server from the Internet. Since the cluster may have several instances, this step is mandatory to decouple the access to the task from the instances pool. In a Fargate ECS cluster, this is not required because the task gets assigned to a public IP address automatically.

$ aws elbv2 create-load-balancer \

    --name <network-load-balancer>\

    --type network \

    --subnets <subnetIdList> 

Output:

{

    "LoadBalancers": [

        {

            "LoadBalancerArn": "<nlbARN>",

            "DNSName": "<nlbDNS>",

            ...

        }

    ]

}

Create the target group

The load balancer needs a target group to redirect the requests from the load balancer to the registered instances. However, we do not need to register any instance in the target group because the ECS service that will be created later will do that for us, registering the EC2 instances from the cluster in the target group automatically.

$ aws elbv2 create-target-group \

    --name <target-group-name> \

    --protocol TCP \

    --port 9999 \

    --vpc-id <vpc-id>

Output:

{

    "TargetGroups": [

        {

            "TargetGroupArn": "<targetGroupARN>",

            "TargetGroupName": "<target-group-name>",

            "Protocol": "TCP",

            "Port": 9999,

            ...

        }

    ]

}

Create the listener

The load balancer needs a listener in order to listen for new requests and to redirect them to the right target group.

$ aws elbv2 create-listener \

    --load-balancer-arn <nlbARN> \

    --protocol TCP \

    --port 9999 \

    --default-actions Type=forward,TargetGroupArn=<targetGroupARN>

Create an ECS Service

After registering the task and the load balancer, the next step is creating the service that will run the task on our container instance. Note that the task requires a route to the internet, as we want the Denodo server to be accessed from outside AWS.

$ aws ecs create-service \

        --service-name <denodo-service> \

        --cluster <denodo-ecs-cluster> \

        --task-definition denodo-task-definition \

        --desired-count 1 \

        --launch-type "EC2" \

        --load-balancers "targetGroupArn=<targetGroupARN>,containerName=denodo,containerPort=9999"

The create-service command returns a description of the task definition after it completes its registration. The following command gets a list of services created in the cluster:

$ aws ecs list-services --cluster <denodo-ecs-cluster>

You can get the description of the service running using the service name retrieved earlier to get more information about the task:

$ aws ecs describe-services --cluster <denodo-ecs-cluster> --services <denodo-service>

Connecting to the Denodo Platform

Finally, in order to connect to the server from a VDP client, you will need to ensure that the VDP client is able to resolve this hostname to the public IP address of the load balancer, and you can do that by adding an entry in the local hosts configuration file to map that hostname with the public IP address.

You can obtain the public IP address of the load balancer from its public DNS Name, which can be retrieved with the following AWS CLI statement:

$ aws elbv2 describe-load-balancers --names <network-load-balancer> --query "LoadBalancers[0].DNSName"

Then, add the entry with the AWS Public IP address in the local hosts file:

# Denodo ECS service

<public-ip>        <denodo-hostname>

Now you can open a new Virtual DataPort Administration Tool and connect to the server using the following Denodo Server URI:

//<denodo-hostname>:9999/admin

Virtual DataPort Administration Tool

References

AWS Command Line Interface

How to create your own Docker images for Denodo Platform Containers

Questions

Ask a question
You must sign in to ask a question. If you do not have an account, you can register here

Featured content

DENODO TRAINING

Ready for more? Great! We offer a comprehensive set of training courses, taught by our technical instructors in small, private groups for getting a full, in-depth guided training in the usage of the Denodo Platform. Check out our training courses.

Training