Desplegando contenedores de Docker en AWS EC2 a través de un botón
Tags: docker, aws, mern, react
Published: 2020-06-03 18:07:32

Este artículo es una continuación de este [anterior](https://dev.to/gaabgonca/utilizando-el-poder-de-docker-para-construir-aplicaciones-mern-usando-mern-docker-1gip), en el que se desplegó una aplicación MERN sobre contenedores usando docker-compose.

Algunos de los pasos llevados a cabo en el presente artículo son inspirados en los seguidos por Umair Nadeem en este [artículo](https://medium.com/@umairnadeem/deploy-to-aws-using-docker-compose-simple-210d71f43e67).

Los pasos a desarrollar son los siguientes:

1. Desarrollar un boilerplate de aplicación MERN. (Artículo anterior)

2. Configurar docker-compose. (Artículo anterior)

[3. Crear una instancia de EC2.] (#chapter3)

[4. Copiar los archivos de proyecto a la instancia de EC2 y configurar instancia para docker-compose.] (#chapter4)

[5. Crear una imagen (AMI) de la instancia para replicarla.](#chapter5)

[6. Desarrollar interfaz (botón) para automatizar despliegue de instancia basada en imagen.](#chapter6)



<a name="chapter3"/>
<br/>

### 3 Crear una instancia de EC2.

Para crear una instancia de EC2 se debe ingresar primero a la consola de AWS. Allí, en EC2 se pueden crear instancias: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qmh75jrl0hzadxazdv5y.png)

Se escoge como imagen base Amazon Linux 2 AMI (HVM), SSD Volume Type

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8wytg9b7q9cqp6qksp43.png)

Se escoge el tipo de instancia, en este artículo solo se utilizarán instancias dentro de la capa gratuita de AWS:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7s2hqmbh1b1rubk1597n.png)

Se dejan los detalles de instancias predeterminados y el almacenamiento predeterminado, las etiquetas son opcionales.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n3zy3mxx3lcas1raj3vy.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n3zy3mxx3lcas1raj3vy.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wx57wi3w1w2a6wmqyfq9.png)

Ahora se configura el grupo de seguridad de la instancia. El grupo de seguridad de la instancia permite tráfico de entrada (inbound) y de salida (outbount) en los puertos especificados. En tanto que se está desarrollando un entorno de desarrollo MERN en la nube se necesitan configurar los siguientes puertos de entrada:

* 80 para HTTP.
* 8080 para el servidor de express del MERN app.
* 22 para acceder via SSH a la instancia
* 3000 para el cliente react del MERN app

En esta guía se llamará **dev0** el grupo de seguridad:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ozkbragos1zv1k2njd5b.png)

Finalmente se lanza la instancia:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wcqts490skwzt2i82sfu.png)

Se crea una nueva llave de seguridad, esta es la que permite el acceso a la instancia.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cp9glcq4j1fd0jiulqef.png)

Finalmente, vemos la instancia **mern_app_boilerplate0** corriendo en Instancias de EC2: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ufzga7t7lfyuq2ubddjx.png)

Para utilizar la llave de seguridad **MyLinuxKP.pem** se deben configurar su propietario con:

```
chown 400 MyLinuxKP.pem
```

<a name="chapter4"/>
<br/>
### 4 Copiar los archivos de proyecto a la instancia de EC2 y configurar instancia para docker-compose.

Luego, se copian los archivos del boilerplate del app MERN del disco local a la instancia de EC2, usando su dirección IP pública:

```
scp -r -i MyLinuxKP.pem ~/path/to/your/project/folder/from/root ec2-user@54.89.125.233:~/
```

Luego de copiar los archivos a la instancia, se accede a ella a través de ssh con el siguiente comando:

```
ssh ec2-user@54.89.125.233 -i MyLinuxKP.pem
```

Ahora dentro de la instancia de EC2 se corren los siguientes 5 comandos: 

```
sudo yum update

sudo yum install docker

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

```

Los comandos anteriores actualizan dependencias en la instancia, instalan docker y docker-compose.

Para iniciar el servicio de docker en la instancia se usa:

```
sudo service docker start
```

Para desplegar los contenedores se usa:

```
sudo docker-compose up --build
```

Se puede verificar el funcionamiento correcto del boilerplate al acceder a la instancia a través de los puertos de desarrollo (3000 y 8080)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zmxkqshkwhp7guv7my0t.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gzi22zs83hhhoz6ff4ka.png)

<a name="chapter5"/>
<br/>
### 5 Crear una imagen (AMI) de la instancia para replicarla.

En esta sección se creará una imagen de máquina de amazon (AMI) con base en la instancia anterior para automatizar su replicación. Para ello se accede al dashboard de instancias de EC2 y se crea una imagen a partir de la instancia en cuestión:

Instancia > Acciones > Imagen > Crear Imagen

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vczgnmakv0ajasklo8q6.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vczgnmakv0ajasklo8q6.png)

Ahora se tiene una imagen de la instancia que se creó como boilerplate. Con base en esta imagen se pueden generar instancias identicas a la original en el momento de captura de la imagen.

Para lanzar una instancia a partir de la imagen desde la consola de AWS se selecciona la imagen como imagen base de la instancia:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fg0dt48k3c6lf4pl6t1u.png)

Esto último, esto es, la creación de la instancia boilerplate a partir de la imágen es lo que se busca automatizar con un botón.

<a name="chapter6"/>
<br/>

### 6 Desarrollar interfaz (botón) para automatizar despliegue de instancia basada en imagen.

Para desarrollar un botón en JavaScript para automatizar el despliegue de una instancia basada en una imagen de boilerplate, el primer paso es instalar el SDK de AWS para JavaScript:

```
npm install -save aws-sdk
```

Segundo, se tiene el siguiente script (provisto por Amazon [aquí](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/ec2-example-creating-an-instance.html)) para crear instancias de EC2 usando el SDK de AWS para JavaScript:

```javascript
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Load credentials and set region from JSON file
AWS.config.update({region: 'REGION'});

// Create EC2 service object
var ec2 = new AWS.EC2({apiVersion: '2016-11-15'});

// AMI is amzn-ami-2011.09.1.x86_64-ebs
var instanceParams = {
   ImageId: 'AMI_ID', 
   InstanceType: 't2.micro',
   KeyName: 'KEY_PAIR_NAME',
   MinCount: 1,
   MaxCount: 1
};

// Create a promise on an EC2 service object
var instancePromise = new AWS.EC2({apiVersion: '2016-11-15'}).runInstances(instanceParams).promise();

// Handle promise's fulfilled/rejected states
instancePromise.then(
  function(data) {
    console.log(data);
    var instanceId = data.Instances[0].InstanceId;
    console.log("Created instance", instanceId);
    // Add tags to the instance
    tagParams = {Resources: [instanceId], Tags: [
       {
          Key: 'Name',
          Value: 'SDK Sample'
       }
    ]};
    // Create a promise on an EC2 service object
    var tagPromise = new AWS.EC2({apiVersion: '2016-11-15'}).createTags(tagParams).promise();
    // Handle promise's fulfilled/rejected states
    tagPromise.then(
      function(data) {
        console.log("Instance tagged");
      }).catch(
        function(err) {
        console.error(err, err.stack);
      });
  }).catch(
    function(err) {
    console.error(err, err.stack);
  });
```

En esta función se cambian las constantes: 'AMI_ID', 'KEY_PAIR_NAME' y 'SDK Sample'.

El id del ami se obtiene en la consola de AWS navegando EC2 > IMAGES (AMIs) > Seleccionar AMI deseada > AMI ID

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7qbcsxgs8lvfzottyd34.png)

El 'KEY_PAIR_NAME' es el nombre de las credenciales que se usaran para acceder a la instancia, en este caso se tiene MyLinuxKP.pem

El 'SDK Sample' se cambia por el nombre que se le quiera poner a la instancia.

Finalmente, se añade la función al onClick de un botón en React:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wfvoautp0awwifgwozli.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sl5qnlsgq5pj8sni6djz.png)

## Conclusiones

En este post se pudo ver como automatizar con un botón el despliegue de instancias de EC2 con el código base y la configuración (boilerplate) para desarrollar aplicaciones MERN y ejecutarlas usando docker-compose.