Docker Multi Container GitHub Action Deployment Pipeline using AWS Elastic Beanstalk
Published: 2022-08-30 17:54:05

In this article, we want to build multiple containers using GitHub actions and deploy them to Amazon Elastic Beanstalk. Containers are the new de facto method used in the industry to avoid the most used complaint during the QA phase which is “It Works on my Machine”. It needs some engine such as docker to run. We can describe our container on a simple file that has information about the operating system to use, runtimes, and the artifacts that need to execute on the virtual machine. 

Let’s get started. You can find the code in the GitHub link below
[GitHub Link](https://github.com/poudeldipak/container_blog/tree/main/multi-docker-main)
After you have downloaded you can see the files below

![Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpeagv354sfw2t1mz68u.png)

Clone the project or download as zip. to run the project locally, you can use docker-compose-dev.yml file with the command in the project’s directory. 
This project has a separate docker-compose-dev.yml file because our docker-compose.yml has production version which downloads container from a repository (Docker hub for now). By default, the repository used in docker hub. The repository could be hosted in AWS Elastic Container Repository as well. To do so all we need to do is generate docker config file by logging in and generating AWS credentials file and changing the tag from docker username to awsurl/imagename. And update the repository url in the production docker-compose.yml.
`docker-compose -f docker-compose-dev.yml up`

It then starts downloading the dependencies and running the command in Dockerfile such as copy, add npm install etc. in a series of containers one after another and build images of those containers.
you can see the containers and images with the command not necessarily in the project’s directory i.e anywhere
We now have a project that has redis and postgres specified as external container dependencies and a react client, nodejs server and an nginx that exposes http port 80. 

`docker ps –all`


![Docker Images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdofhcy4k5jff6ukemgv.png)
`docker images`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rj3rmbye6x2pu94kg2d.png)

The architecture

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31ccdmhvawfr8pq6gfck.png)
Networking between the containers
Networking is a pretty vast topic to discuss. For now, we don’t have to worry about inter container networking at this level because all containers are a part of default bridge network driver. Because of the bridge, and specified hostname, containers can pinpoint other containers and communicate over a virtual network. We have leveraged the use of hostnames in our dockerfile.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lay1p1wz2vyqmlm30iki.png)

The Solution
The solution offered by the project is calculate Fibonacci value for nth position. It uses react for frontend website, redis for cache so that n-1 values can be retrieved if already calculated. Calculated values are stored in a postgres database. Nginx container to serve load balanced http traffic.

Client
The client is a react project that queries the API for previously calculated values and requests the worker container to evaluate Fibonacci value via API. The Container is built in two stages. The first stage is called builder which uses node:16-alpine to install dependencies and build the react bundle. After the bundle is build, HTML, CSS and JavaScript chunks are copied to another container using nginx as image which exposes port 80 internally

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mr68zyvzo75stibd2aii.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5yj3hfvnv31hf9bblhv9.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njr2olup7tb8fsvtbmoi.png)

Dockerfile.dev is also included so that we could stop pushing to Elastic Beanstalk if the tests fail.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y4iaj54rc4wyynjlt8qi.png)



The client nginx listens on port 3000. Here’s a catch; “container Nginx and Nginx inside the client are different entities”. Container nginx listens on port 80 whereas nginx inside the client is a secondary client that is served by container nginx:80. Confusing? I bet it is. Repeat reading the statement.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wcpb05j2l1s7i2v6jd1c.png)

Nginx
Nginx is a container that serves as the server handler to send and receive http traffic to the services. It exposes port 80.  Two Upstreams api with port 5000 and client with port 3000 are attached to the listener at port 80

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1y9d0xr65hdqszxmputn.png)
Server
The server is a container that communicates with postgres and redis via environment provided in the docker-compose.yml file. It contains endoints to fetch values that are calculated and post values to be calculated. It also has a caching logic.
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/omavzwh75hie3ziwzz6t.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hofp7waq90wqjdd0lsmt.png)


 
It creates a subscription on the redis client for the given index and then add the index to the postgres. So instead of making query to the postgres, which is definitely more resource intensive than querying from redis, the server can fetch value via the redis used as a cache.
Worker
The worker is a nodejs application that recursively calculates Fibonacci values when a message is received in a subscription topic and publishes it to the redis cache.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgziiji4o7ijxxjdglps.png)


 
Github Action


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af9dxn3tooqn6xc5afvp.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elslq7umeuparcudd1xo.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kkeo0gelydm66jdrr3rk.png)

  
 
Login to docker and generate an access token and copy it in the clipboard so that we can use it as docker password in the github actions secret.
Docker username, password, AWS access and secret keys should be added to action secrets in the github repository.
The github workflow is triggered when push is made on the main branch as defined in the workflow file.  It logs in to the docker hub, builds the container from the artifact and pushes it to the docker repository.


Create and Elastic Beanstalk Application and add the application name, environment name  and the region to github workflow file. Create an IAM that can access the bucket and Elastic Beanstalk with programmatic access and also add it to the github workflow file. Check s3 for bucket created by Elastic Beanstalk and add the bucket name to the github workflow file.
The docker engine expects docker-compose.yml file to configure which containers to run. Since our docker file contains the list of services (i.e. containers). Our application should be live. Try accessing URL which is automatically generated by elastic Beanstalk.

#awscommunity #awscommunitybuilders #aws #awssolutionarchitect #awscloud #awscertified #cloudcomputing #awscertification #awstraining  #amazonwebservices #cloud #container #eks #ecs #ebs