Docker Orchestration and Continous Development

Michael Sudirman
Moodah POS
Published in
7 min readOct 17, 2019

What is Docker?

Docker is a container platform that is useful for creating and deploying applications. We are using docker for deploying our front-end service, unlike back-end service which uses AWS serverless for deployment.

Docker and Gitlab Interaction in short

In short, Docker has a registry that contains Docker image and receives the image from gitlab. Docker user can run the image via portainer, in which the image is then rendered to become one of more instances of a container.

Docker Image

Docker image is a compressed file used to execute code in a Docker Container. in this case, the Docker image is our project files and can be created according to the implementation of the Dockerfile. When the Docker user runs the Docker image, it will become one or more instances of that container, as mentioned earlier.

Dockerfile

This is what Dockerfile looks like. First, we use alpine, which is a lightweight, linux distribution. Currently, we are going to use Docker for front-end,which uses ReactJS, thus we are going to use npm install--silent and npm install react-scripts@3.0.1 -g--silent to install dependency. running the ENV PATH and COPY beforehand is essential so that the package.json can be accessed by the npm.We also need to run EXPOSE 80 to explicitly tell Docker which port we are going to assign(in this case, port:80).

Then, we are running npm run build to finally compile the front-end resources(.html, .css, .js). After building, we change our environment from node to nginx, since we dont need node environment for deployment. we are using COPY--from=build to copy to the correct folder. The next 2 command lines, rm and COPY is used to change the nginx configuration file. After calling EXPOSE 80 , we call CMD to tell docker to run the command when running the image

Calling docker via .gitlab-ci.yml

There are a lot of things that occur in .gitlab-ci.yml file, but we can split them into three: development, staging and production. These three can be seen as the stages of our project, which depends on how ready is our branch is. In the yml file, the difference is the endpoint of the docker build, which can be seen above. Some of the codes that is written there is the implementation on how to run Docker in fasilkom’s Docker.

The important portion of the codes is located on the script, which includes pull, build and push. docker pull pulls the latest image from the Docker platform, if exists (using ||true). docker build recreates the Docker image and docker push push the image back to the platform.

Our use of Nginx

Nginx is open source server, commonly used as a reverse proxy and load balancer to manage incoming traffic and distribute them to slower upstream server. With its goal to create the fastest web server around, it is an excellent choice for our front end deployment. After building using npm, these front end files become static files, in which we use Nginx to deploy them. In Moodah POS case, it is used to route request and response to or from the backend server(s).

DIND (Docker in Docker)

We implement Dicker with Docker so that the container(chuck of files), will not run on its own Docker daemon, but connects to the Docker daemon of the host system. This means that the Docker CLI in the container and host system will connect to the same, one Docker Daemon. The following codes are responsible for creating Docker in Docker service:

services:
- docker:19.03.0-dind

Continous Development: Pipeline Configuration with gitlab-ci.yml

source: https://medium.com/@brilvio/how-i-implemented-a-ci-build-of-delphi-binaries-using-gitlab-ci-d1123826698f

To create a continuous development, Git provides a way with a YAML file called gitlab-ci.yml . This file should be placed within each project on the root, and will defines the structure and order of the pipelines.

With gitlab-ci.yml, Git will know what to execute, and the steps that is needed before finally deploying to the main server. This includes having tests that can check whether the application met the criteria or not.

To illustrate, the image above shows three checklists, which indicates that the stages have passed. The two right checklists shows that the tests and release stage have passed, which also passes the pipeline as a whole. If there is an “x mark, the pipeline will not be accepted and your server will not deploy that specific branch, which saves your running application from crashing. With gitlab-ci.yml, you can modify these if you want to create more constraints before accepting certain pipelines.

full version of Moodah POS’ gitlab-ci.yml

Our gitlab-ci.yml file has stages that will seperate the other statements that s called jobs. These stages are test, deploy backend, release. From the YAML file, the 5 jobs below the stages have different stage category, in which will be used to differentiate on which should go first. Jobs that are in the same stage will run in parallel, and will the next jobs will wait until the test stage has finished.

Test

During the test stage, the test frontend and test backend will work in parallel. They will use alpine as their image node, for javascript application and lightweight images. The script will move to two different respective folders using cd and install the required packages that is inside each folder using npm install . After installing needed dependencies, the jobs run npm run test that runs the tests file in each folder that expects the codes to meet the given criteria. The coverage will then be extracted, checking for percentage of criteria met, using regex command coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/

For test frontend , npm run gql-gen will be executed before test so that the GraphQL can be executed from the frontend ReactJS. On the other npm run lint is executed on test backend because we established a styling check for the GraphQL functions.

test stage: test backend and test frontend

Deploy Backend

Specific to backend AWS lambda server, we are using serverless library. Thus, we need to install the additional dependencies via npm install -g serverless . STAGE inside the variables are used to be placed in the command $STAGE in serverless deploy --stage $STAGE --verbose , in which option --verbose is used to show all stack events during deployment, and display any stack output. This is also useful in catching errors when running the serverless deploy command.

backend functions deployment in 3 different stages

Above is an illustration of the environment key used to classify jobs in the Gitlab repository. This is shown under the Environment section. Below the environment key, there is only key that restricts the running process of this job under specific changes. In our case, the deploy prod backend job will only be run when there is a change in backend/serverless.yml under master branch. This specific YAML file is used for base server configuration in the GraphQL server, in which the end point of that server needs to be catch by the frontend. On normal terms, the GraphQL server tend to be configured manually at the serverless website, whenever needed changes are dealt separately from the frontend architecture.

Release

The last 2 jobs, release prod frontend and update prod backend functions are fallen into release stage, in which these 2 architecture will be deployed in two different containers. The frontend will have a docker image, which will be deployed in the Fasilkom’s docker registry. On the other hand, backend architecture will be released to AWS lambda server with serverless architecture.

For frontend release, the tags, services and variables key are configured to handle the DIND problems that stops working after the 12.1.0 update. All specified keys are added to choose which runners to run the job, defines another docker image that will be run on the job and is linked to the defined image in the image key. A set of commands from before_script are run before the script key to set the proxy server form Fasilkom docker side.

The script key in release prod frontend will be run afterwards. The first command form the script is docker pull,which pull the latest image from the docker platform and pulls the latest image from the Docker platform, if exists (using ||true). docker build recreates the Docker image, and can use the cache option, which can benefit cache made by the docker pull and specifications that’s inside Dockerfile. $CI_REGISTRY_IMAGE is a variable that is stored inside the Environment Variables under CI/CD Git Settings. Such useful features can be used to store important variables that are marked private, so that it will not be seen by unauthorized people. docker push will push the image to the specified address in the Fasilkom’s docker platform.

update prod backend functions from the backend server will add or update functions in the AWS lamba server. Similar to deploy prod backend , it uses serverless library and alpine image as well. However, update prod backend functions uses different deploy commands. Instead of using serverless deploy stage that changes the whole url endpoint, it uses serverless deploy function which will only change the function inside the endpoint. Thus, the stage will not change and frontend architecture will not need to check through new endpoints anymore.

There are 3 serverless deploy function that will serve functions under different url endpoints: graphql,playground,graphql-introspect . All of these 3 points are made for different uses. For example, playground url will be used for developers to check what functions are available, and their interactions with the backend Rest API endpoints. Other urls will also be used when developers want to use the GraphQL functions, under specified Secret Key.

--

--