Assume that we work on AWS and we have built a Flask API and we want to deploy it. Let’s say that we work with the Cloud9 IDE and the structure of our project is the following and our goal is to work with Dockers:
The Dockerfile would look like:
FROM python:3.6 COPY . /appdir WORKDIR /appdir RUN pip install Flask==1.0.2 EXPOSE 5000 CMD ["python", "app.py"]
Build the Image
You can type on the terminal the docker build command with a tag of your preference.
docker build --tag flask-tutorial .
Now you can verify that the image exists by typing:
docker images
Run the Image
You can run the image by typing:
docker run -d --name flask-tutorial -p 5000:5000 flask-tutorial
Notice that the -d
flag means to run it into the background without holding your terminal hostage. We can check that the container is running by typing:
docker ps
Let’s provide some useful docker commands:
The ps
command
To re-iterate with the ps
command you can list the docker containers. Some of the more common flags are --no-trunc
which will not truncate the output. Another useful flag to keep in mind is -a
which will allow us to see all the containers running and stopped (which we mentioned above). The --filter
command is also helpful when searching for specific commands. So if we had our running flask-tutorial
container we could run the following to filter it out:
docker ps --filter "name=flask-tutorial"
The exec
command
Even though we don’t use the exec
command it’s important to note. The exec
command will allow us to run a command in a running container. So for example if we have our running flask-tutorial
container and we wanted to run a command inside it. The following command will create a new file test
located in the /tmp
directory, in the background:
docker exec -d flask-tutorial touch /tmp/test Verify: docker exec -it flask-tutorial /bin/ls -l /tmp total 0 -rw-r--r-- 1 root root 0 Aug 21 16:56 test
The stop
command
You show them how to stop our container by it’s name (hence the use the --name
flag earlier).
docker stop flask-tutorial
Verify it’s stopped:
docker ps
You should see the following:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Everything is stopped and we can now think about how we can store our fancy new flask image.
Store your docker images on ECR
The Amazon Elastic Container Registry (ECR) is a fully-managed Docker container registry service that makes it easy to store, manage and deploy Docker container images and it is integrated with Elastic Beanstalk and ECS which also simplifies the process when you deploy to production.
In order to be able to push our Docker image to ECR
first we will use the CLI. We first need to authorize our Cloud9 docker client with the AWS CLI’s ecr get-login
command:
aws ecr get-login --region us-west-2 --no-include-email
You should see something similar:
docker login -u AWS -p eyJwYXlsb2FkIjoiWnc4NUs2K3dkNVhySXJvQWVlZE8xZUpHOVhaUmNaTEdYTXBrU2U0Y1BYb3NLTit4a1B3c3RteXhwWkNXcDZ0TkxLLzNpRjdZV2JvckxHczZIQmhsSGFwNlh6ZEU2K0tQOGRIRk8vNTl2enZpNDIybGpBTnlHdURHYjdYNHdZczU4TTZSaDVLbEVrUW80VFZDaXFRTzdkS0hnY0YyaTVlZ1c1RjYweVozZllSSHlWdVQvQngrQ2FQV1ZQVlJ1RndMa3RPOThaajBOd3grMDRJdURUQ2pFMzY5dFAxdzVhYjgzOEpjR0JUWFJWVCs3MG1TYUIwTXY3WWJIMCt4VE9ETDhWTEVzaHNuQTh2M1JQLzlUd2gyMFpnalcyRjNKTmpTd2l6dnptbVpDblh3dDZxa2lwNEowM0ZCLzZ5MEtBTHlFYkk3WmlqSFYzem5oSFJRTmVWMVdBR1FoSjdmV1RucHZwSDRqUGNCdndLZWI4aWpKSGs5L2VaUzFSbUlLZU1HS0UzU3FmRks0a2lYbEY2bkNLVEtRRnNLeGpCYnllVDdWbTJHaXJLMENOT0ZQVksrWS9jSlZ3SDJTaFc4VjBEYjdjeG9vK3pXQjFiYlAvNS9XQ0pXeUM2ZHMrM3dSMW1tdnUwdUVEV2U3b0lNdklpVDIrVHMrRTZ6cmxibVVObFhJaTYzUXdXNTJmRGVHZjFEeDFGOTJqU0dCL3hFd3ZYTzVweVZzMEZPYUcrV054cndlc3ZTL293TFJKcElrOHBtOVlwUVBxRzl4NGd2bnNrdFh3QlJOQkZJc0lkbDVDanQzVmxGWXdJaklOZXR4Zlo4M2tzUGNFekxVbW9kOEJtdVNCaGttMU9zeWZhY0RCa1J2QWs3UkVJL21vbXZBdFlYOW03T3A1VHo2V3ExZ3ZSanh5NkQrT2lWUWVHYVJLSlZGK3dpWEp4eWpDM2FwYTYzaTkyRXJ2V2lwd1p4cUQ4QlkzWG40cEtpQzRQUU9ZTGo2WTdMM3l4STVuZDQ1Zm9kL2I4aFBMREszeFlIbHRkMkhFWGJGOFkyd05qcXdld2FzYWw3bXRPTUJ5VzdKOWJJWW5ORm96SVY4TDQ1WitJYUNxN29QRDhrV3crK0lZSU91bit3WExnZ3lMNjFiM3FhRUs3dW04VjRRRWdNZTdtWVd4TnZta1JtWUc3aGFJUHJjTlh3aHZxRjNaQmNNOWVZNlljeENQdnVyYUlSY3BoYjJoWjQrdjFYbDVOL0hUS3UzajNRb1ZQVGtCYnFVNENTTXIyYURtd052LytHRUNxQ2tkSHpFQlE0TlZqcXZtR2dZaFVEcGpSZktIWGp0ajdlQ1hnSHhpb0ZSajdCdnFVZmdtQXlGVWxwZXQ0MklxeXVSSDlTMWpBYzk4VkE3aC9UcEgwd3phOWI3QmNRSnVIbFZVQTJkZDZkM2hvM2RMOU1pQkRtaTF4NHdHUGVTazRweG8zZUhkSWFIZXZlYjROcTdFeEV0OWZwZ3lvajlPRHJNcWw5dzNLbURidG4wVXNDVjJHWHlGalZMSkZITk5RWlFES1VGU2VZQVNUcFNzUFJROHVhR0hJNi9XUTNxUnh1Qk4xWnA0ZSt3cU1oWVV0ME9SNGxBNFFzZExlcVdzMFJqcVFpMDRWdE1yZkhDTVpZd1FGd2diek1xTGdzU29zSnZRSnJVQWEyOWJiZU5TL0xQaUliOTlLbUFjaVRHTE11cXRDZHhkMlBzV3ZCN1k3NU1Wc1NXU2ZBckl1WWh1cjZHSE1TQk9mNTdDbG9ZV0NQVlV2bzNVNnFHUEIwOVAwSUNEczc4ajNGY0x4K1QvSHJpaGNBTjZhZzUwaFdEV0I1TU9nT2dHRDdrRW5VTGxMSkRBRnp4c3l2Q252N2pwcFo5R2RlSTBINWtiR1hIZFRwQXJEZzZYeUlLYXVMQVFMczdWcUF4TUNwU3djdmluQXNDR0dWQ3M4MUtGUjZjQTA5bmVrYWgvUVpxQkhhdHA0QW1scGNDQlJSMGEvTFVRPT0iLCJkYXRha2V5IjoiQVFFQkFIajZsYzRYSUp3LzdsbjBIYzAwRE1lazZHRXhIQ2JZNFJJcFRNQ0k1OEluVXdBQUFINHdmQVlKS29aSWh2Y05BUWNHb0c4d2JRSUJBREJvQmdrcWhraUc5dzBCQndFd0hnWUpZSVpJQVdVREJBRXVNQkVFRERJWDFaUm1YUmR5QmZtM1VBSUJFSUE3UldmRHhZSW1zdDhOejdVM01KREpjMlRVbSszSE13RXIyMWUzZ0lEOWI1QnhPZXptNnhRL3JNTjRMejV6UGxnM3RhTFRUMzNlWEEwS3d6MD0iLCJ2ZXJzaW9uIjoiMiIsInR5cGUiOiJEQVRBX0tFWSIsImV4cGlyYXRpb24iOjE1NzIwNzgxMTV9 https://323009296932.dkr.ecr.us-west-2.amazonaws.com
You copy and paste the entire output
from above. Paste it back in to the terminal and press enter. You should see the following. You can ignore the warnings:
WARNING! Using --password via the CLI is insecure. Use --password-stdin. WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
We will need to create an ECR repository to push our image.
aws ecr create-repository --repository-name flask-tutorial
You should see something similar to the output:
{ "repository": { "repositoryUri": "323009296932.dkr.ecr.us-west-2.amazonaws.com/flask-tutorial", "registryId": "323009296932", "imageTagMutability": "MUTABLE", "repositoryArn": "arn:aws:ecr:us-west-2:323009296932:repository/flask-tutorial", "repositoryName": "flask-tutorial", "createdAt": 1572035197.0 } }
This is the repositoryUri
that we need to use if we ever have to reference our image in future deployments.
The tag
command
We are going to re-tag
our image to include our registryId
. This makes it easier to manage if we have many accounts or work with other registry providers like docker hub etc.
docker tag flask-tutorial:latest 323009296932.dkr.ecr.us-west-2.amazonaws.com/flask-tutorial:latest
Note that your ECR’s repositoryUri
will be different.
And if we re-run the docker images we will get the see the new one.
docker images
The push
command
Now we can push the image:
docker push 323009296932.dkr.ecr.us-west-2.amazonaws.com/flask-tutorial:latest
Once you do this you should see something similar to the following:
The push refers to repository [323009296932.dkr.ecr.us-west-2.amazonaws.com/flask-tutorial] ff4ff4b2b471: Pushed cd1f247135f6: Pushed dcea7e243648: Pushed d431d6bc3307: Pushed ff19fb54200e: Pushed 69168fb9b7b0: Pushed 31f78d833a92: Pushed 2ea751c0f96c: Pushed 7a435d49206f: Pushed 9674e3075904: Pushed 831b66a484dc: Pushed latest: digest: sha256:8e9ab6d360fb225cde3d5f4adad29c4d0bee5097a951d32aa15ccbe8560200d2 size: 2636
Now the flask image is stored in ECR. Using the aws ecr list-images
command you will get something similar to this on your screen:
{ "imageIds": [ { "imageTag": "latest", "imageDigest": "sha256:8e9ab6d360fb225cde3d5f4adad29c4d0bee5097a951d32aa15ccbe8560200d2" } ] }
Deploy to the cloud using the Elastic Beanstalk console
Now, we will deploy the Flask application to Elastic Beanstalk. We will do the so-called ZIP deployment. We go into the working directory and we type:
zip flask_application.zip app.py Dockerfile
On the left panel expand the flask
folder and right click on the flask_application.zip
and choose Download
- Choose AWS Cloud9 and choose Go To Your Dashboard. Choose Services and choose Elastic Beanstalk..
- At the top right choose Create Application.
- Paste in
flask-app
for Application name. - For Platform choose Docker. Leave the docker settings as is.
- For Application code choose Upload your code. Leave Local file selected. Choose Choose File and browse to where the
flask_application.zip
was downloaded. - Choose Create application.
- Eventually you should see the Health go to Ok with a green circle and a check mark to indicate everything is healthy.
- At the top you should see your application as well with the URL. Click that and at the top you should see the Environment ID and URL. Copy the URL.
- Choose the URL (which should open in a new browser tab) and you should see your example Flask Application.
Voilà, your application is up!