Aprenda a crear e implementar sus aplicaciones distribuidas fácilmente en la nube con Docker-4
Composición acoplable
Hasta ahora hemos dedicado todo nuestro tiempo a explorar el cliente Docker. En el ecosistema Docker, sin embargo, hay muchas otras herramientas de código abierto que funcionan muy bien con Docker. Algunos de ellos son -
- Docker Machine : cree hosts Docker en su computadora, en proveedores de nube y dentro de su propio centro de datos
- Docker Compose : una herramienta para definir y ejecutar aplicaciones Docker de múltiples contenedores.
- Docker Swarm : una solución de agrupación en clústeres nativa para Docker
- Kubernetes : Kubernetes es un sistema de código abierto para automatizar la implementación, el escalado y la gestión de aplicaciones en contenedores.
En esta sección, veremos una de estas herramientas, Docker Compose, y veremos cómo puede facilitar el manejo de aplicaciones de múltiples contenedores.
La historia de fondo de Docker Compose es bastante interesante. Aproximadamente en enero de 2014, una empresa llamada OrchardUp lanzó una herramienta llamada Fig. La idea detrás de Fig era hacer que los entornos de desarrollo aislados funcionaran con Docker. El proyecto fue muy bien recibido en Hacker News ; curiosamente recuerdo haber leído sobre él, pero no lo entendí del todo.
El primer comentario en el foro realmente explica bien de qué se trata Fig.
Realmente, en este punto, de eso se trata Docker: ejecutar procesos. Ahora Docker ofrece una API bastante rica para ejecutar los procesos: volúmenes compartidos (directorios) entre contenedores (es decir, imágenes en ejecución), reenviar puerto desde el host al contenedor, mostrar registros, etc. Pero eso es todo: Docker por ahora permanece en el nivel de proceso.
Si bien proporciona opciones para organizar varios contenedores para crear una única "aplicación", no aborda la gestión de dicho grupo de contenedores como una sola entidad. Y ahí es donde entran herramientas como Fig: hablar de un grupo de contenedores como una sola entidad. Piense en "ejecutar una aplicación" (es decir, "ejecutar un grupo orquestado de contenedores") en lugar de "ejecutar un contenedor".
Resulta que mucha gente que usa Docker está de acuerdo con este sentimiento. Lenta y constantemente, a medida que Fig se hizo popular, Docker Inc. se dio cuenta, adquirió la empresa y cambió el nombre de Fig a Docker Compose.
Entonces, ¿para qué se utiliza Compose ? Compose es una herramienta que se utiliza para definir y ejecutar aplicaciones Docker de múltiples contenedores de una manera sencilla. Proporciona un archivo de configuración llamado docker-compose.ymlque se puede utilizar para abrir una aplicación y el conjunto de servicios del que depende con un solo comando. Compose funciona en todos los entornos: producción, puesta en escena, desarrollo, pruebas, así como flujos de trabajo de CI, aunque Compose es ideal para entornos de desarrollo y pruebas.
Veamos si podemos crear un docker-compose.ymlarchivo para nuestra aplicación SF-Foodtrucks y evaluar si Docker Compose cumple su promesa.
Sin embargo, el primer paso es instalar Docker Compose. Si está ejecutando Windows o Mac, Docker Compose ya está instalado tal como viene en Docker Toolbox. Los usuarios de Linux pueden obtener fácilmente Docker Compose siguiendo las instrucciones de los documentos. Dado que Compose está escrito en Python, también puedes simplemente hacerlo pip install docker-compose. Pruebe su instalación con -
$ docker-compose --version docker-compose version 1.21.2, build a133471
Ahora que lo tenemos instalado, podemos pasar al siguiente paso, es decir, el archivo Docker Compose docker-compose.yml. La sintaxis de YAML es bastante simple y el repositorio ya contiene el archivo docker-compose que usaremos.
version: "3"
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
container_name: es
environment:
- discovery.type=single-node
ports:
- 9200:9200
volumes:
- esdata1:/usr/share/elasticsearch/data
web:
image: yourusername/foodtrucks-web
command: python3 app.py
depends_on:
- es
ports:
- 5000:5000
volumes:
- ./flask-app:/opt/flask-app
volumes:
esdata1:
driver: local
Permítanme desglosar lo que significa el archivo anterior. En el nivel principal, definimos los nombres de nuestros servicios esy web. El imageparámetro siempre es obligatorio y para cada servicio que queramos que ejecute Docker, podemos agregar parámetros adicionales. Para es, simplemente nos referimos a la elasticsearchimagen disponible en el registro de Elastic. Para nuestra aplicación Flask, nos referimos a la imagen que creamos al principio de esta sección.
Otros parámetros como commandy portsproporcionan más información sobre el contenedor. El volumesparámetro especifica un punto de montaje en nuestro webcontenedor donde residirá el código. Esto es puramente opcional y es útil si necesita acceso a registros, etc. Más adelante veremos cómo esto puede ser útil durante el desarrollo. Consulte la referencia en línea para obtener más información sobre los parámetros que admite este archivo. También agregamos volúmenes para el escontenedor para que los datos que cargamos persistan entre reinicios. También especificamos depends_on, lo que le dice a Docker que inicie el escontenedor antes web. Puede leer más al respecto en Docker Compose Docs .
Nota: Debe estar dentro del directorio con el docker-compose.ymlarchivo para poder ejecutar la mayoría de los comandos de Redacción.¡Excelente! Ahora el archivo está listo, veámoslo docker-composeen acción. Pero antes de comenzar, debemos asegurarnos de que los puertos y nombres estén libres. Entonces, si tiene los contenedores Flask y ES en ejecución, apaguémoslos.
$ docker stop es foodtrucks-web es foodtrucks-web $ docker rm es foodtrucks-web es foodtrucks-web
Ahora podemos correr docker-compose. Navegue hasta el directorio de camiones de comida y ejecute docker-compose up.
$ docker-compose up
Creating network "foodtrucks_default" with the default driver
Creating foodtrucks_es_1
Creating foodtrucks_web_1
Attaching to foodtrucks_es_1, foodtrucks_web_1
es_1 | [2016-01-11 03:43:50,300][INFO ][node ] [Comet] version[2.1.1], pid[1], build[40e2c53/2015-12-15T13:05:55Z]
es_1 | [2016-01-11 03:43:50,307][INFO ][node ] [Comet] initializing ...
es_1 | [2016-01-11 03:43:50,366][INFO ][plugins ] [Comet] loaded [], sites []
es_1 | [2016-01-11 03:43:50,421][INFO ][env ] [Comet] using [1] data paths, mounts [[/usr/share/elasticsearch/data (/dev/sda1)]], net usable_space [16gb], net total_space [18.1gb], spins? [possibly], types [ext4]
es_1 | [2016-01-11 03:43:52,626][INFO ][node ] [Comet] initialized
es_1 | [2016-01-11 03:43:52,632][INFO ][node ] [Comet] starting ...
es_1 | [2016-01-11 03:43:52,703][WARN ][common.network ] [Comet] publish address: {0.0.0.0} is a wildcard address, falling back to first non-loopback: {172.17.0.2}
es_1 | [2016-01-11 03:43:52,704][INFO ][transport ] [Comet] publish_address {172.17.0.2:9300}, bound_addresses {[::]:9300}
es_1 | [2016-01-11 03:43:52,721][INFO ][discovery ] [Comet] elasticsearch/cEk4s7pdQ-evRc9MqS2wqw
es_1 | [2016-01-11 03:43:55,785][INFO ][cluster.service ] [Comet] new_master {Comet}{cEk4s7pdQ-evRc9MqS2wqw}{172.17.0.2}{172.17.0.2:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)
es_1 | [2016-01-11 03:43:55,818][WARN ][common.network ] [Comet] publish address: {0.0.0.0} is a wildcard address, falling back to first non-loopback: {172.17.0.2}
es_1 | [2016-01-11 03:43:55,819][INFO ][http ] [Comet] publish_address {172.17.0.2:9200}, bound_addresses {[::]:9200}
es_1 | [2016-01-11 03:43:55,819][INFO ][node ] [Comet] started
es_1 | [2016-01-11 03:43:55,826][INFO ][gateway ] [Comet] recovered [0] indices into cluster_state
es_1 | [2016-01-11 03:44:01,825][INFO ][cluster.metadata ] [Comet] [sfdata] creating index, cause [auto(index api)], templates [], shards [5]/[1], mappings [truck]
es_1 | [2016-01-11 03:44:02,373][INFO ][cluster.metadata ] [Comet] [sfdata] update_mapping [truck]
es_1 | [2016-01-11 03:44:02,510][INFO ][cluster.metadata ] [Comet] [sfdata] update_mapping [truck]
es_1 | [2016-01-11 03:44:02,593][INFO ][cluster.metadata ] [Comet] [sfdata] update_mapping [truck]
es_1 | [2016-01-11 03:44:02,708][INFO ][cluster.metadata ] [Comet] [sfdata] update_mapping [truck]
es_1 | [2016-01-11 03:44:03,047][INFO ][cluster.metadata ] [Comet] [sfdata] update_mapping [truck]
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Dirígete a la IP para ver tu aplicación en vivo. Eso fue increíble ¿no? Solo unas pocas líneas de configuración y tendremos dos contenedores Docker ejecutándose exitosamente al unísono. Detengamos los servicios y volvamos a ejecutarlos en modo independiente.
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Killing foodtrucks_web_1 ... done
Killing foodtrucks_es_1 ... done
$ docker-compose up -d
Creating es ... done
Creating foodtrucks_web_1 ... done
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------------
es /usr/local/bin/docker-entr ... Up 0.0.0.0:9200->9200/tcp, 9300/tcp
foodtrucks_web_1 python3 app.py Up 0.0.0.0:5000->5000/tcp
Como era de esperar, podemos ver que ambos contenedores se ejecutan correctamente. ¿De dónde vienen los nombres? Estos fueron creados automáticamente por Compose. ¿Pero Compose también crea la red automáticamente? ¡Buena pregunta! Vamos a averiguar.
En primer lugar, detengamos la ejecución de los servicios. Siempre podemos recuperarlos con un solo comando. Los volúmenes de datos persistirán, por lo que es posible iniciar el clúster nuevamente con los mismos datos usando Docker-Compose Up. Para destruir el clúster y los volúmenes de datos, simplemente escriba docker-compose down -v.
$ docker-compose down -v Stopping foodtrucks_web_1 ... done Stopping es ... done Removing foodtrucks_web_1 ... done Removing es ... done Removing network foodtrucks_default Removing volume foodtrucks_esdata1
Mientras estamos en eso, también eliminaremos la foodtrucksred que creamos la última vez.
$ docker network rm foodtrucks-net $ docker network ls NETWORK ID NAME DRIVER SCOPE c2c695315b3a bridge bridge local a875bec5d6fd host host local ead0e804a67b none null local
¡Excelente! Ahora que tenemos borrón y cuenta nueva, volvamos a ejecutar nuestros servicios y veamos si Compose hace su magia.
$ docker-compose up -d Recreating foodtrucks_es_1 Recreating foodtrucks_web_1 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f50bb33a3242 yourusername/foodtrucks-web "python3 app.py" 14 seconds ago Up 13 seconds 0.0.0.0:5000->5000/tcp foodtrucks_web_1 e299ceeb4caa elasticsearch "/docker-entrypoint.s" 14 seconds ago Up 14 seconds 9200/tcp, 9300/tcp foodtrucks_es_1
Hasta ahora, todo bien. Es hora de ver si se crearon redes.
$ docker network ls NETWORK ID NAME DRIVER c2c695315b3a bridge bridge local f3b80f381ed3 foodtrucks_default bridge local a875bec5d6fd host host local ead0e804a67b none null local
Puede ver que Compose siguió adelante y creó una nueva red llamada foodtrucks_defaulty adjuntó ambos nuevos servicios en esa red para que cada uno de ellos sea reconocible para el otro. Cada contenedor de un servicio se une a la red predeterminada y otros contenedores de esa red pueden acceder a él y descubrirlo en un nombre de host idéntico al nombre del contenedor.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c6bb7e818ec docker.elastic.co/elasticsearch/elasticsearch:6.3.2 "/usr/local/bin/dock…" About a minute ago Up About a minute 0.0.0.0:9200->9200/tcp, 9300/tcp es
7640cec7feb7 yourusername/foodtrucks-web "python3 app.py" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp foodtrucks_web_1
$ docker network inspect foodtrucks_default
[
{
"Name": "foodtrucks_default",
"Id": "f3b80f381ed3e03b3d5e605e42c4a576e32d38ba24399e963d7dad848b3b4fe7",
"Created": "2018-07-30T03:36:06.0384826Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7640cec7feb7f5615eaac376271a93fb8bab2ce54c7257256bf16716e05c65a5": {
"Name": "foodtrucks_web_1",
"EndpointID": "b1aa3e735402abafea3edfbba605eb4617f81d94f1b5f8fcc566a874660a0266",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
},
"8c6bb7e818ec1f88c37f375c18f00beb030b31f4b10aee5a0952aad753314b57": {
"Name": "es",
"EndpointID": "649b3567d38e5e6f03fa6c004a4302508c14a5f2ac086ee6dcf13ddef936de7b",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "foodtrucks",
"com.docker.compose.version": "1.21.2"
}
}
]
Flujo de trabajo de desarrollo
Antes de pasar a la siguiente sección, hay una última cosa que quería cubrir sobre Docker-Compose. Como se indicó anteriormente, Docker-compose es realmente excelente para el desarrollo y las pruebas. Entonces, veamos cómo podemos configurar Compose para hacernos la vida más fácil durante el desarrollo.
A lo largo de este tutorial, hemos trabajado con imágenes acoplables listas para usar. Si bien hemos creado imágenes desde cero, todavía no hemos tocado ningún código de aplicación y principalmente nos limitamos a editar Dockerfiles y configuraciones YAML. Una cosa que debes preguntarte es ¿cómo se ve el flujo de trabajo durante el desarrollo? ¿Se supone que uno debe seguir creando imágenes de Docker para cada cambio, luego publicarlas y luego ejecutarlas para ver si los cambios funcionan como se esperaba? Estoy seguro de que suena muy tedioso. Tiene que haber una mejor manera. En esta sección, eso es lo que vamos a explorar.
Veamos cómo podemos realizar un cambio en la aplicación Foodtrucks que acabamos de ejecutar. Asegúrate de tener la aplicación ejecutándose,
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5450ebedd03c yourusername/foodtrucks-web "python3 app.py" 9 seconds ago Up 6 seconds 0.0.0.0:5000->5000/tcp foodtrucks_web_1 05d408b25dfe docker.elastic.co/elasticsearch/elasticsearch:6.3.2 "/usr/local/bin/dock…" 10 hours ago Up 10 hours 0.0.0.0:9200->9200/tcp, 9300/tcp es
Ahora veamos si podemos cambiar esta aplicación para que muestre un Hello world!mensaje cuando se realiza una solicitud de /helloruta. Actualmente, la aplicación responde con un 404.
$ curl -I 0.0.0.0:5000/hello HTTP/1.0 404 NOT FOUND Content-Type: text/html Content-Length: 233 Server: Werkzeug/0.11.2 Python/2.7.15rc1 Date: Mon, 30 Jul 2018 15:34:38 GMT
¿Por qué pasó esto? Dado que la nuestra es una aplicación Flask, podemos ver app.py( enlace ) para obtener respuestas. En Flask, las rutas se definen con la sintaxis @app.route. En el archivo, verá que solo tenemos tres rutas definidas /: /debugy /search. La /ruta representa la aplicación principal, la debugruta se usa para devolver información de depuración y finalmente searchla aplicación la usa para consultar elasticsearch.
$ curl 0.0.0.0:5000/debug
{
"msg": "yellow open sfdata Ibkx7WYjSt-g8NZXOEtTMg 5 1 618 0 1.3mb 1.3mb\n",
"status": "success"
}
Dado ese contexto, ¿cómo agregaríamos una nueva ruta para hello? ¡Lo adivinaste! Abramos flask-app/app.pyen nuestro editor favorito y hagamos el siguiente cambio.
@app.route('/')
def index():
return render_template("index.html")
# add a new hello route
@app.route('/hello')
def hello():
return "hello world!"
Ahora intentemos hacer una solicitud nuevamente.
$ curl -I 0.0.0.0:5000/hello HTTP/1.0 404 NOT FOUND Content-Type: text/html Content-Length: 233 Server: Werkzeug/0.11.2 Python/2.7.15rc1 Date: Mon, 30 Jul 2018 15:34:38 GMT
¡Oh, no! ¡Eso no funcionó! que hicimos mal? Si bien hicimos el cambio en app.py, el archivo reside en nuestra máquina (o en la máquina host), pero como Docker ejecuta nuestros contenedores basándose en la yourusername/foodtrucks-webimagen, no conoce este cambio. Para validar esto, intentemos lo siguiente:
$ docker-compose run web bash Starting es ... done root@581e351c82b0:/opt/flask-app# ls app.py package-lock.json requirements.txt templates node_modules package.json static webpack.config.js root@581e351c82b0:/opt/flask-app# grep hello app.py root@581e351c82b0:/opt/flask-app# exit
Lo que intentamos hacer aquí es validar que nuestros cambios no estén en app.pyel contenedor que se está ejecutando. Hacemos esto ejecutando el comando docker-compose run, que es similar a su primo docker runpero toma argumentos adicionales para el servicio (que weben nuestro caso es ). Tan pronto como ejecutamos bash, el shell se abre /opt/flask-appcomo se especifica en nuestro Dockerfile . Desde el comando grep podemos ver que nuestros cambios no están en el archivo.
Veamos cómo podemos solucionarlo. En primer lugar, debemos indicarle a Docker Compose que no use la imagen y que en su lugar use los archivos localmente. También configuraremos el modo de depuración para trueque Flask sepa que debe recargar el servidor cuando app.pyhaya cambios. Reemplace la webparte del docker-compose.ymlarchivo así:
version: "3"
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
container_name: es
environment:
- discovery.type=single-node
ports:
- 9200:9200
volumes:
- esdata1:/usr/share/elasticsearch/data
web:
build: . # replaced image with build
command: python3 app.py
environment:
- DEBUG=True # set an env var for flask
depends_on:
- es
ports:
- "5000:5000"
volumes:
- ./flask-app:/opt/flask-app
volumes:
esdata1:
driver: local
Con ese cambio ( diff ), paremos y comencemos los contenedores.
$ docker-compose down -v Stopping foodtrucks_web_1 ... done Stopping es ... done Removing foodtrucks_web_1 ... done Removing es ... done Removing network foodtrucks_default Removing volume foodtrucks_esdata1 $ docker-compose up -d Creating network "foodtrucks_default" with the default driver Creating volume "foodtrucks_esdata1" with local driver Creating es ... done Creating foodtrucks_web_1 ... done
Como paso final, hagamos el cambio app.pyagregando una nueva ruta. Ahora intentamos rizar
$ curl 0.0.0.0:5000/hello hello world
¡Guau! ¡Recibimos una respuesta válida! Intente experimentar haciendo más cambios en la aplicación.
Con esto concluye nuestro recorrido por Docker Compose. Con Docker Compose, también puede pausar sus servicios, ejecutar un comando único en un contenedor e incluso escalar la cantidad de contenedores. También le recomiendo que consulte algunos otros casos de uso de Docker Compose. Con suerte, pude mostrarles lo fácil que es administrar entornos de múltiples contenedores con Compose. En la sección final, implementaremos nuestra aplicación en AWS.
Servicio de contenedor elástico de AWS
En la última sección solíamos docker-composeejecutar nuestra aplicación localmente con un solo comando: docker-compose up. Ahora que tenemos una aplicación que funciona, queremos compartirla con el mundo, conseguir algunos usuarios, ganar toneladas de dinero y comprar una casa grande en Miami. La ejecución de los últimos tres está más allá del alcance del tutorial, por lo que dedicaremos nuestro tiempo a descubrir cómo podemos implementar nuestras aplicaciones de contenedores múltiples en la nube con AWS.
Si ha leído hasta aquí, estará bastante convencido de que Docker es una tecnología genial. Y tu no estas solo. Al ver el meteórico ascenso de Docker, casi todos los proveedores de la nube comenzaron a trabajar para agregar soporte para implementar aplicaciones Docker en su plataforma. A partir de hoy, puede implementar contenedores en Google Cloud Platform , AWS , Azure y muchos otros. Ya tenemos una introducción a la implementación de aplicaciones de contenedor único con Elastic Beanstalk y en esta sección veremos Elastic Container Service (o ECS) de AWS.
AWS ECS es un servicio de administración de contenedores escalable y súper flexible que admite contenedores Docker. Le permite operar un clúster Docker sobre instancias EC2 a través de una API fácil de usar. Mientras que Beanstalk tenía valores predeterminados razonables, ECS le permite ajustar completamente su entorno según sus necesidades. Esto hace que ECS, en mi opinión, sea bastante complejo para empezar.
¡Afortunadamente para nosotros, ECS tiene una herramienta CLI amigable que comprende los archivos Docker Compose y aprovisiona automáticamente el clúster en ECS! Dado que ya tenemos un funcionamiento, docker-compose.ymlno debería requerir mucho esfuerzo ponerlo en funcionamiento en AWS. ¡Entonces empecemos!
El primer paso es instalar la CLI. Las instrucciones para instalar la CLI tanto en Mac como en Linux se explican muy claramente en los documentos oficiales . Continúe, instale la CLI y cuando haya terminado, verifique la instalación ejecutando
$ ecs-cli --version ecs-cli version 1.18.1 (7e9df84)
A continuación, trabajaremos en la configuración de la CLI para que podamos hablar con ECS. Seguiremos los pasos que se detallan en la guía oficial de los documentos de AWS ECS. En caso de cualquier confusión, no dude en consultar esa guía.
El primer paso implicará crear un perfil que usaremos durante el resto del tutorial. Para continuar, necesitarás tu AWS_ACCESS_KEY_IDy AWS_SECRET_ACCESS_KEY. Para obtenerlos, siga los pasos que se detallan en la sección titulada Clave de acceso y Clave de acceso secreta en esta página .
$ ecs-cli configure profile --profile-name ecs-foodtrucks --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY
A continuación, necesitamos obtener un par de claves que usaremos para iniciar sesión en las instancias. Dirígete a tu consola EC2 y crea un nuevo par de claves. Descargue el par de claves y guárdelo en un lugar seguro. Otra cosa a tener en cuenta antes de salir de esta pantalla es el nombre de la región. En mi caso, le puse un nombre a mi clave ecsy configuré mi región como us-east-1. Esto es lo que asumiré durante el resto de este tutorial.
El siguiente paso es configurar la CLI.
$ ecs-cli configure --region us-east-1 --cluster foodtrucks INFO[0000] Saved ECS CLI configuration for cluster (foodtrucks)
Proporcionamos el configurecomando con el nombre de la región en la que queremos que resida nuestro clúster y un nombre de clúster. Asegúrese de proporcionar el mismo nombre de región que utilizó al crear el par de claves. Si no ha configurado AWS CLI en su computadora antes, puede usar la guía oficial , que explica todo con gran detalle sobre cómo hacer que todo funcione.
El siguiente paso permite a la CLI crear una plantilla de CloudFormation .
$ ecs-cli up --keypair ecs --capability-iam --size 1 --instance-type t2.medium INFO[0000] Using recommended Amazon Linux 2 AMI with ECS Agent 1.39.0 and Docker version 18.09.9-ce INFO[0000] Created cluster cluster=foodtrucks INFO[0001] Waiting for your cluster resources to be created INFO[0001] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS INFO[0062] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS INFO[0122] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS INFO[0182] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS INFO[0242] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS VPC created: vpc-0bbed8536930053a6 Security Group created: sg-0cf767fb4d01a3f99 Subnet created: subnet-05de1db2cb1a50ab8 Subnet created: subnet-01e1e8bc95d49d0fd Cluster creation succeeded.
Aquí proporcionamos el nombre del par de claves que descargamos inicialmente ( ecsen mi caso), la cantidad de instancias que queremos usar ( --size) y el tipo de instancias en las que queremos que se ejecuten los contenedores. La --capability-iambandera le dice a la CLI que reconocemos que este comando puede crear recursos de IAM.
El último y último paso es donde usaremos nuestro docker-compose.ymlarchivo. Necesitaremos hacer algunos cambios menores, así que en lugar de modificar el original, hagamos una copia. El contenido de este archivo (después de realizar los cambios) se ve así (a continuación):
version: '2'
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
cpu_shares: 100
mem_limit: 3621440000
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
logging:
driver: awslogs
options:
awslogs-group: foodtrucks
awslogs-region: us-east-1
awslogs-stream-prefix: es
web:
image: yourusername/foodtrucks-web
cpu_shares: 100
mem_limit: 262144000
ports:
- "80:5000"
links:
- es
logging:
driver: awslogs
options:
awslogs-group: foodtrucks
awslogs-region: us-east-1
awslogs-stream-prefix: web
Los únicos cambios que hicimos con respecto al original docker-compose.ymlson proporcionar los valores mem_limit(en bytes) y cpu_sharespara cada contenedor y agregar alguna configuración de registro. Esto nos permite ver los registros generados por nuestros contenedores en AWS CloudWatch . Dirígete a CloudWatch para crear un grupo de registros llamado foodtrucks. Tenga en cuenta que, dado que ElasticSearch normalmente termina ocupando más memoria, hemos dado alrededor de 3,4 GB de límite de memoria. Otra cosa que debemos hacer antes de pasar al siguiente paso es publicar nuestra imagen en Docker Hub.
$ docker push yourusername/foodtrucks-web
¡Excelente! ¡Ahora ejecutemos el comando final que implementará nuestra aplicación en ECS!
$ cd aws-ecs $ ecs-cli compose up INFO[0000] Using ECS task definition TaskDefinition=ecscompose-foodtrucks:2 INFO[0000] Starting container... container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es INFO[0000] Starting container... container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web INFO[0000] Describe ECS container status container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2 INFO[0000] Describe ECS container status container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2 INFO[0036] Describe ECS container status container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2 INFO[0048] Describe ECS container status container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2 INFO[0048] Describe ECS container status container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2 INFO[0060] Started container... container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-foodtrucks:2 INFO[0060] Started container... container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-foodtrucks:2
No es una coincidencia que la invocación anterior sea similar a la que usamos con Docker Compose . Si todo salió bien, deberías ver a desiredStatus=RUNNING lastStatus=RUNNINGcomo última línea.
¡Impresionante! Nuestra aplicación está activa, pero ¿cómo podemos acceder a ella?
ecs-cli ps Name State Ports TaskDefinition 845e2368-170d-44a7-bf9f-84c7fcd9ae29/web RUNNING 54.86.14.14:80->5000/tcp ecscompose-foodtrucks:2 845e2368-170d-44a7-bf9f-84c7fcd9ae29/es RUNNING ecscompose-foodtrucks:2
¡Continúe y abra http://54.86.14.14 en su navegador y debería ver los Food Trucks en todo su esplendor negro y amarillo! Ya que estamos en el tema, veamos cómo se ve nuestra consola de AWS ECS .
Podemos ver arriba que nuestro clúster ECS llamado 'foodtrucks' se creó y ahora ejecuta 1 tarea con 2 instancias de contenedor. Dedica un tiempo a explorar esta consola para familiarizarte con todas las opciones que hay aquí.
Limpiar
Una vez que haya jugado con la aplicación implementada, recuerde apagar el clúster.
$ ecs-cli down --force INFO[0001] Waiting for your cluster resources to be deleted... INFO[0001] Cloudformation stack status stackStatus=DELETE_IN_PROGRESS INFO[0062] Cloudformation stack status stackStatus=DELETE_IN_PROGRESS INFO[0124] Cloudformation stack status stackStatus=DELETE_IN_PROGRESS INFO[0155] Deleted cluster cluster=foodtrucks
Ahí lo tienes. ¡Con solo unos pocos comandos pudimos implementar nuestra increíble aplicación en la nube de AWS!
CONCLUSIÓN
¡Y eso es una envoltura! Después de un tutorial largo, exhaustivo pero divertido, ¡ahora estás listo para conquistar el mundo de los contenedores! Si seguiste hasta el final, definitivamente deberías estar orgulloso de ti mismo. Aprendió a configurar Docker, ejecutar sus propios contenedores, jugar con sitios web estáticos y dinámicos y, lo más importante, adquirió experiencia práctica en la implementación de sus aplicaciones en la nube.
Espero que terminar este tutorial te haga tener más confianza en tus habilidades para manejar servidores. Cuando tenga la idea de crear su próxima aplicación, puede estar seguro de que podrá presentarla a la gente con un mínimo esfuerzo.
Próximos pasos
¡Tu viaje al mundo de los contenedores acaba de comenzar! Mi objetivo con este tutorial era abrirte el apetito y mostrarte el poder de Docker. En el mar de las nuevas tecnologías, puede resultar difícil navegar solo en las aguas y tutoriales como este pueden ser de ayuda. Este es el tutorial de Docker que desearía tener cuando comencé. Con suerte, cumplió su propósito de entusiasmarte con los contenedores para que ya no tengas que mirar la acción desde los lados.
A continuación se presentan algunos recursos adicionales que serán beneficiosos. Para su próximo proyecto, le recomiendo encarecidamente que utilice Docker. Recuerde: ¡la práctica hace la perfección!
Dar opinion
Ahora que el tutorial terminó, es mi turno de hacer preguntas. ¿Te gustó el tutorial? ¿El tutorial te pareció un completo desastre o te divertiste y aprendiste algo?
Envíame tus pensamientos directamente o simplemente crea un problema . También estoy en Twitter , así que si ese es tu trato, ¡no dudes en gritar allí!
Me encantaría conocer tu experiencia con este tutorial. Da sugerencias sobre cómo mejorar esto o déjame saber acerca de mis errores. Quiero que este tutorial sea uno de los mejores tutoriales introductorios de la web y no puedo hacerlo sin tu ayuda.