How to deploy multi-container on Elastic Beanstalk (AWS)? - amazon-web-services

I tried to deploy this app, which consists of a Flask API and a MongoDB database, which is mounted to a volume.
What am I doing wrong? I tried to upload the Dockerrun.aws.json file to Beanstalk, but I keep getting this error:
[Instance: i-0f9dd8d8d30059929] Command failed on instance. An unexpected error has occurred [ErrorCode: 0000000001].
This is my Dockerrun.aws.json file:
"AWSEBDockerrunVersion": 2,
"containerDefinitions": [
{
"essential": true,
"image": "nielshoogeveen1990/image-classifier:latest",
"links": [
"db"
],
"name": "api",
"memory": 128,
"portMappings": [
{
"containerPort": 5000,
"hostPort": 5000
}
]
},
{
"essential": true,
"image": "mongo:3.6.4",
"mountPoints": [
{
"containerPath": "/var/lib/mysql/data",
"sourceVolume": "Db-Data"
}
],
"name": "db",
"memory": 128
}
],
"family": "",
"volumes": [
{
"host": {
"sourcePath": "db-data"
},
"name": "Db-Data"
}
]
}

Related

AWS ECS/EC2 task fails to deploy

I'm trying to deploy a small React app to an EC2 instance using ECS but I'm constantly getting the error message Resource handler returned message: "Error occurred during operation 'ECS Deployment Circuit Breaker was triggered'." (RequestToken: xxx-xxx-xxx-xxx, HandlerErrorCode: GeneralServiceException)
I have tried deploying the app to an EC2 instance manually (with docker run -p 80:3000 my-app) and this worked fine so I'm pretty sure the app and Dockerfile are ok. The Docker image is hosted in ECR.
I'm thinking that most likely this is an issue with my task definition. It looks like this:
{
"taskDefinitionArn": "arn:aws:ecs:eu-north-1:xxx:task-definition/my-task-definition:4",
"containerDefinitions": [
{
"name": "my-app",
"image": "xxx.dkr.ecr.eu-north-1.amazonaws.com/my-app:latest",
"cpu": 1024,
"memory": 1024,
"portMappings": [
{
"name": "my-app-3000-tcp",
"containerPort": 3000,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"environment": [],
"mountPoints": [],
"volumesFrom": [],
"disableNetworking": false,
"privileged": false,
"readonlyRootFilesystem": false,
"pseudoTerminal": false
}
],
"family": "my-app",
"taskRoleArn": "arn:aws:iam::xxx:role/EcsToEcrAccess",
"executionRoleArn": "arn:aws:iam::xxx:role/ecsTaskExecutionRole",
"networkMode": "bridge",
"revision": 4,
"volumes": [],
"status": "ACTIVE",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
},
{
"name": "ecs.capability.execution-role-ecr-pull"
}
],
"placementConstraints": [],
"compatibilities": [
"EC2"
],
"requiresCompatibilities": [
"EC2"
],
"registeredAt": "2023-01-31T15:30:16.919Z",
"registeredBy": "arn:aws:iam::xxx:user/me",
"tags": [
{
"key": "ecs:taskDefinition:createdFrom",
"value": "ecs-console-v2"
}
]
}

Prisma error when trying to run with elastic beanstalk

I have a prisma project that works fine locally when I run $ docker-compose up. I converted the docker-compose.yml file to Dockerrun.aws.json. But now when i try to run the project locally via $ eb local run I get an error
mysql_1 | Version: '5.7.24' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
prisma_1 | Exception in thread "main" java.sql.SQLTransientConnectionException: database - Connection is not available, request timed out after 5001ms.
Below is my Dockerrun.aws.json file:
{
"AWSEBDockerrunVersion": "2",
"containerDefinitions": [
{
"environment": [
{
"name": "MYSQL_ROOT_PASSWORD",
"value": "prisma"
}
],
"essential": true,
"memory": 128,
"image": "mysql:5.7",
"mountPoints": [
{
"containerPath": "/var/lib/mysql",
"sourceVolume": "Mysql"
}
],
"name": "mysql",
"portMappings": [
{
"containerPort": 3306,
"hostPort": 3306
}
]
},
{
"environment": [
{
"name": "PRISMA_CONFIG",
"value": "port: 4466\ndatabases:\n default:\n connector: mysql\n host: mysql\n port: 3306\n user: root\n password: prisma\n migrations: true\n"
}
],
"essential": true,
"memory": 128,
"image": "prismagraphql/prisma:1.21",
"name": "prisma",
"portMappings": [
{
"containerPort": 4466,
"hostPort": 4466
}
]
}
],
"family": "",
"volumes": [
{
"host": {
"sourcePath": "mysql"
},
"name": "Mysql"
}
]
}
The error message leads me to believe that there's an issue connecting the prisma container to the mysql instance. If i had to guess it's the PRISMA_CONFIG value but not I'm not 100% sure. Can someone tell me what I'm doing wrong here?
You can not have those /n in there. YAML cares about real carriage and spaces.

"Invalid configuration for registry" error when executing "eb local run"

I think this is a very easy to fix problem, but I just can't seem to solve it! I've spent a good amount of time looking for any leads on Google/SO but couldn't find a solution.
When executing eb local run, I'm getting this error:
Invalid configuration for registry
$ eb local run
ERROR: InvalidConfigFile :: Invalid configuration for registry 12345678.dkr.ecr.eu-west-1.amazonaws.com
The image lines in my Dockerrun.aws.json are as follows:
{
"AWSEBDockerrunVersion": 2,
"volumes": [
{
"name": "frontend",
"host": {
"sourcePath": "/var/app/current/frontend"
}
},
{
"name": "backend",
"host": {
"sourcePath": "/var/app/current/backend"
}
},
{
"name": "nginx-proxy-conf",
"host": {
"sourcePath": "/var/app/current/config/nginx"
}
},
{
"name": "nginx-proxy-content",
"host": {
"sourcePath": "/var/app/current/content/"
}
},
{
"name": "nginx-proxy-ssl",
"host": {
"sourcePath": "/var/app/current/config/ssl"
}
}
],
"containerDefinitions": [
{
"name": "backend",
"image": "123456.dkr.ecr.eu-west-1.amazonaws.com/backend:latest",
"Update": "true",
"essential": true,
"memory": 512,
"mountPoints": [
{
"containerPath": "/app/backend",
"sourceVolume": "backend"
}
],
"portMappings": [
{
"containerPort": 4000,
"hostPort": 4000
}
],
"environment": [
{
"name": "PORT",
"value": "4000"
},
{
"name": "MIX_ENV",
"value": "dev"
},
{
"name": "PG_PASSWORD",
"value": "xxsaxaax"
},
{
"name": "PG_USERNAME",
"value": "
},
{
"name": "PG_HOST",
"value": "123456.dsadsau89das.eu-west-1.rds.amazonaws.com"
},
{
"name": "FE_URL",
"value": "http://develop1.com"
}
]
},
{
"name": "frontend",
"image": "123456.dkr.ecr.eu-west-1.amazonaws.com/frontend:latest",
"Update": "true",
"essential": true,
"memory": 512,
"links": [
"backend"
],
"command": [
"npm",
"run",
"production"
],
"mountPoints": [
{
"containerPath": "/app/frontend",
"sourceVolume": "frontend"
}
],
"portMappings": [
{
"containerPort": 3000,
"hostPort": 3000
}
],
"environment": [
{
"name": "REDIS_HOST",
"value": "www.eample.com"
}
]
},
{
"name": "nginx-proxy",
"image": "nginx",
"essential": true,
"memory": 128,
"portMappings": [
{
"hostPort": 80,
"containerPort": 3000
}
],
"links": [
"backend",
"frontend"
],
"mountPoints": [
{
"sourceVolume": "nginx-proxy-content",
"containerPath": "/var/www/html"
},
{
"sourceVolume": "awseb-logs-nginx-proxy",
"containerPath": "/var/log/nginx"
},
{
"sourceVolume": "nginx-proxy-conf",
"containerPath": "/etc/nginx/conf.d",
"readOnly": true
},
{
"sourceVolume": "nginx-proxy-ssl",
"containerPath": "/etc/nginx/ssl",
"readOnly": true
}
]
}
],
"family": ""
}
It seems that you have a broken docker-registry auth config file. In your home, this file ~/.docker/config.json, should look something like:
{
"auths": {
"https://1234567890.dkr.ecr.us-east-1.amazonaws.com": {
"auth": "xxxxxx"
}
}
}
That is generated with the command docker login (related to aws ecr get-login)
Check that. I say this because you are entering in an exception here:
for registry, entry in six.iteritems(entries):
if not isinstance(entry, dict):
# (...)
if raise_on_error:
raise errors.InvalidConfigFile(
'Invalid configuration for registry {0}'.format(registry)
)
return {}
This is due to outdated dependencies in the current version of the awsebcli tool. They pinned version "docker-py (>=1.1.0,<=1.7.2)" which does not support the newer credential helper formats. The latest version of docker-py is the first one to properly support the latest credential helper format and until the AWS EB CLI developers update docker-py to use 2.4.0 (https://github.com/docker/docker-py/releases/tag/2.4.0) this will remain broken.
First is that it's not valid json, The PG_USERNAME field does not have the enclosing quote.
{
"name": "PG_USERNAME",
"value": "
},
Should be
{
"name": "PG_USERNAME",
"value": ""
},
Next thing to check is to see if your Beanstalk instance profile has access to the ecr registry.
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-instanceprofile.html
Specifies the Docker base image on an existing Docker repository from which you're building a Docker container. Specify the value of the Name key in the format / for images on Docker Hub, or // for other sites.
When you specify an image in the Dockerrun.aws.json file, each instance in your Elastic Beanstalk environment will run docker pull on that image and run it. Optionally include the Update key. The default value is "true" and instructs Elastic Beanstalk to check the repository, pull any updates to the image, and overwrite any cached images.
Do not specify the Image key in the Dockerrun.aws.json file when using a Dockerfile. .Elastic Beanstalk will always build and use the image described in the Dockerfile when one is present.
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker_image.html
Test to make sure you can access your ecr outside of Elasticbeanstalk as well.
$ docker pull aws_account_id.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest
latest: Pulling from amazonlinux
8e3fa21c4cc4: Pull complete
Digest: sha256:59895a93ba4345e238926c0f4f4a3969b1ec5aa0a291a182816a4630c62df769
Status: Downloaded newer image for aws_account_id.dkr.ecr.us-west-2.amazonaws.com/amazonlinux:latest
http://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-pull-ecr-image.html

Cross communication between docker containers in AWS Beanstalk

Is there any way to have bidirectional communication between docker containers on AWS Beanstalk?
The stack im trying to get working is pretty standard: Varnish -> Nginx -> PHP-FPM.
I am using the links specification to specify that nginx should find the hostname "php-app". Nginx finds the php-app hostname, so that works. However I also need the "php-app" to be able to resolve hostname "varnish" so the "php-app" can send PURGE requests for cache invalidation.
Basically now there is only this communication that works:
[varnish:80] -> [nginx:8080] -> [php-app]
However this should be working:
[varnish:80] -> [nginx:8080] -> [php-app] ---PURGE---> [varnish:80]
The php-app basically only needs to know about the IP of the varnish host, however that seems to be impossible.
I know that I can also get the varnish container ip from the HOST, but i want to do the same just from the php-app container:
VARNISH_HASH=`docker ps | grep varnish | sed 's/\|/ /' | awk '{print $1}'`
VARNISH_IP=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $VARNISH_HASH`
I also tried adding links to the php-app container, but that resulted in errors when deploying, I guess it's because there are then circular dependencies:
"links": [
"varnish"
]
My relevant Dockerrun.aws.json (container deifinition file) looks like this:
{
"AWSEBDockerrunVersion": 2,
"volumes": [
.....
],
"containerDefinitions": [
{
"name": "nginx-proxy",
"image": "nginx",
"essential": true,
"memory": 128,
"links": [
"php-app"
],
"portMappings": [
{
"hostPort": 8080,
"containerPort": 8080
}
],
"environment": [
{
"name": "NGINX_PORT",
"value": "8080"
}
],
"mountPoints": [ .... ]
},
{
"name": "varnish",
"hostname": "varnish",
"image": "newsdev/varnish:4.1.0",
"essential": true,
"memory": 128,
"portMappings": [
{
"hostPort": 80,
"containerPort": 80
}
],
"links": [
"nginx-proxy",
"php-app"
],
"mountPoints": [ .... ]
},
{
"name": "php-app",
"image": "peec/magento2-php-fpm-aws",
"essential": true,
"memory": 1024,
"environment": [
],
"mountPoints": [ .... ]
}
]
}

How to connect multiple Docker containers in AWS ElasticBeanstalk?

I have a Docker multicontainer configuration meant to run in a ElasticBeanstalk environment.
The EB environment runs in a VPC, in a public subnet, has a single load-balancer and a single instance bound.
It looks like all of the containers are running fine but they cannot communicate with each other even though i defined them as linked containers.
What do I need to do to get all of these containers talking to each other?
My Dockerrun.aws.json looks like this:
"containerDefinitions":
[
{
"name": "proxy",
"image": "nginx",
"essential": true,
"memory": 128,
"portMappings":
[
{
"hostPort": 80,
"containerPort": 80
}
],
"links":
[
"webapp"
],
"mountPoints":
[
{
"sourceVolume": "nginx-conf",
"containerPath": "/etc/nginx/conf.d",
"readOnly": true
},
{
"sourceVolume": "awseb-logs-proxy",
"containerPath": "/var/log/nginx"
}
]
},
{
"name": "webapp",
"image": "jetty",
"memory": 2048,
"essential": true,
"portMappings":
[
{
"hostPort": 8080,
"containerPort": 8080
}
],
"links":
[
"mongodb"
],
"mountPoints":
[
{
"sourceVolume": "jetty-webapp",
"containerPath": "/var/lib/jetty/webapps",
"readOnly": false
},
{
"sourceVolume": "awseb-logs-webapp",
"containerPath": "/var/log/jetty"
}
]
},
{
"name": "mongodb",
"image": "mongo",
"memory": 1024,
"essential": true,
"portMappings":
[
{
"hostPort": 27017,
"containerPort": 27017
}
],
"mountPoints":
[
{
"sourceVolume": "mongodb-data",
"containerPath": "/data/db",
"readOnly": false
}
]
}
]
In 2017, Use the container definition: links with the name of the Docker container you want to connect to. Docker's built-in network bridge will make the connections from there.
In my case, it had nothing to do with the security groups since all I am exposing publicly is 80 for the Nginx proxy.
It came down to using the names in my /etc/host (webapp, mongodb), instead of the IP, that were created for the containers.
This fixes my connection from Nginx to Jetty and Jetty to MongoDB.