Under the Hood of AWS Elastic Beanstalk Part 2
This a continuation of the last post: Under the Hood of Elastic Beanstalk Part 1
We’ll go over the EB nginx setup for the docker container in this post.
EB Docker on Upstart
First, the docker container is always kept running via the upstart config /etc/init/eb-docker.conf. If you kill the process, it’ll just come back up.
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 163ebbeedede aws_beanstalk/current-app:latest "/bin/sh -c docker/b 19 hours ago Up 19 hours 3000/tcp hopeful_brattain # docker stop 163ebbeedede 163ebbeedede # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 163ebbeedede aws_beanstalk/current-app:latest "/bin/sh -c docker/b 19 hours ago Up 1 seconds 3000/tcp hopeful_brattain #
If you really want to stop it you’ll need to do so via upstart:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 163ebbeedede aws_beanstalk/current-app:latest "/bin/sh -c docker/b 19 hours ago Up 34 seconds 3000/tcp hopeful_brattain # stop eb-docker eb-docker stop/waiting # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # start eb-docker eb-docker start/running, process 11090 # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 163ebbeedede aws_beanstalk/current-app:latest "/bin/sh -c docker/b 19 hours ago Up 1 seconds 3000/tcp hopeful_brattain #
Nginx Proxies to Docker Container
You can see that the normally running container listens to the port 3000 in this case. The container will expose the port that is configured in your Dockerfile or the Dockerrun.aws.json according to the AWS documentation. The script with that logic that selects the port to expose is actually located at
/opt/elasticbeanstalk/hooks/appdeploy/enact/00run.sh. EB configures nginx to proxy port 80 to this exposed container port with this config file: /etc/nginx/conf.d/elasticbeanstalk-nginx-docker-upstream.conf
We can curl the docker port directly.
# curl -s -v -o /dev/null 172.17.0.9:3000 2>&1 | grep '< HTTP' < HTTP/1.1 200 OK #
We can also curl nginx port 80 to make sure the proxy is working all the way from nginx to the container.
# curl -s -v -o /dev/null localhost:80 2>&1 | grep '< HTTP' < HTTP/1.1 200 OK #
Configure Docker Container Server Concurrency
Configuring nginx to proxy to another webserver is pretty typically. Unicorn and puma are commonly use and they are configured so that they have multiple processes or threads to handle concurrency. In the EB case, nginx proxies to the server within the docker container itself. Knowing this, it is important for scaling reasons that the docker container server is configured for concurrency properly. You’ll want to configure your container to have the right number of workers or threads to maximize the RAM and CPU on the instance efficiently. EB is usually used to run only docker container on each AWS instance. So it is crucial that we configure that docker container’s server to run more than 1 process or thread or else we’ll be likely wasting resources and worse not scale.
Each application is different in how it consumes CPU and uses RAM so you’ll have to play with it. Here are simple examples for unicorn and puma.
Lastly, EB sets up and ELB so traffic gets load balanced to port 80 on each instances in the environment. So the overall routing goes: client -> ELB > nginx -> docker.
Curl the ELB endpoint to make sure that it’s working all the way from the ELB to nginx to docker.
$ curl -s -v -o /dev/null "http://your-custom-endpoint.elasticbeanstalk.com" 2>&1 | grep '< HTTP' < HTTP/1.1 200 OK $
Thanks for reading this far. If you found this article useful, I'd really appreciate it if you share this article so others can find it too! Thanks 😁 Also follow me on Twitter.
Got questions? Check out BoltOps.
You might also like
Kubes: Kubernetes Deployment Tool
Kubes is a Kubernetes Deployment Tool. It builds the docker image, creates the Kubernetes YAML, and runs kubectl apply. It automates the deployment process and saves you precious finger-typing energy.
Jets: The Ruby Serverless Framework
Ruby on Jets allows you to create and deploy serverless services with ease, and to seamlessly glue AWS services together with the most beautiful dynamic language: Ruby. It includes everything you need to build an API and deploy it to AWS Lambda. Jets leverages the power of Ruby to make serverless joyful for everyone.
Lono: The CloudFormation Framework
Building infrastructure-as-code is challenging. Lono makes it much easier and fun. It includes everything you need to manage and deploy infrastructure-as-code.