Continuous Integration Deployment with Docker Container
Some of the points in this article referenced heavily from https://medium.com/learnfazz/deployment-dengan-docker-d23249895a0b
According to Docker’s website, Docker is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries, and settings. Docker allows you to build, test, and deploy applications quickly.
Docker is important because it helps us to ease the creation, deploy and the delivery of an application using the so-called Containers. The Docker Containers allow the developer/sysadmin to bundle an application with all needed components (libraries and other resources) and to deliver it as an independent and single package.
Thanks to the Container, the system administrator is sure 100% that the application will run on every Linux machine (or on other docker supported platforms) regardless of any customization, server settings or other customization that may be present on the target server.
LearnFazz’s software architecture consists of four main components (Mobile app/front-end, back-end, DBMS server, and an image server), three connectors (HTTP TCP/IP) and this such of topology that you can see in the picture below.
For Mobile App and Storage & Messaging Server, we don’t need deployment with docker. The ones that need to be deployed with docker are the Back-end Server and Database Server. Deployment using docker is done using https://portainer.docker.ppl.cs.ui.ac.id which has been provided by the Faculty of Computer Science. These are the steps to deploy an app with Portainer (this is referenced heavily from https://medium.com/learnfazz/deployment-dengan-docker-d23249895a0b):
- Prepare the Image
Image is an executable package consists of the application, runtime, library, the environment variables, and configuration file.
For the database, the image can be gotten from https://hub.docker.com/_/postgres.
For the back-end server, the image can be made by writing this line of codes:
docker build -t registry.docker.ppl.cs.ui.ac.id/pplb4/back-end:${ENVIRONMENT} .
${ENVIRONMENT} is a variable that states the environment of the image being made. Our team has 2 environments: development and staging.
This command will make an image after following these other several steps:
- In Dockerfile
# 1
FROM golang# 2
ENV GOPKG $GOPATH/src/gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2019/PPLB4/back-end
ENV GO111MODULE on# 3
RUN mkdir -p $GOPKG
COPY . $GOPKG/
WORKDIR $GOPKG# 4
RUN GOBIN=`pwd`/output go install infrastructure/cmd/main.go
RUN ./dependency.sh# 5
ENTRYPOINT ["./docker-entrypoint.sh"]
#1 → declaration of dependency image (image golang)
#2 → environment variables needed when building the image
#3 → prepare the directory to save the image
#4 → make an executable from our app and installing the dependencies (asides from docker image)
#5 → the command when docker is executed, this line is used for database migration and executing server
- In dependency.sh
#!/bin/shcurl -s https://packagecloud.io/install/repositories/golang-migrate/migrate/script.deb.sh | bashapt-get install -y migrate
- In docker-entrypoint.sh
#!/bin/shmigrate -path infrastructure/migrations/ -database ${DB_SOURCE} up
./output/main
- Push image (with the tag used when building)
docker push registry.docker.ppl.cs.ui.ac.id/pplb4/back-end:${ENVIRONMENT}
2. Prepare the Volume
Docker default setting stores storage in the container. However, for the database, we don’t want to lose data when the database is changed. That is why we need to make a volume. Here is an example to make the volume:
3. Prepare the Network
The network is needed for enabling communication between containers. Here is how to make network:
The driver used is Bridge. A driver network bridge is a default network driver. The bridge enables containers that are located in a different network to communicate.
The other driver is the driver network Host. We don’t use host driver because of its behavior that eliminates networks between containers and their host.
4. Make the Container
A container is an instance from the working image. One image can be made into a bunch of containers. In our project, we as many containers as the environments. To make it easier, we made the container using Docker compose. This is the example of the docker-compose.yml file:
version: '2'services:
postgres:
image: postgres:latest
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- learnfazz-development-postgres_data:/var/lib/postgresql/data
networks:
private:
ipv4_address: ${DB_PRIVATE_IP}
backend:
depends_on:
- "postgres"
image: registry.docker.ppl.cs.ui.ac.id/pplb4/back-end:${ENVIRONMENT}
ports:
- ${BACKEND_PUBLIC_PORT}:8080
environment:
DB_SOURCE: postgres://${DB_USER}:${DB_PASSWORD}@${DB_PRIVATE_IP}:5432/${DB_NAME}?sslmode=disable
networks:
private:
ipv4_address: ${BACKEND_PRIVATE_IP}volumes:
learnfazz-development-postgres_data:
name: learnfazz-${ENVIRONMENT}-postgres_data
external: truenetworks:
private:
external:
name: learnfazz-${ENVIRONMENT}-private
This particular lines of codes contain 2 services: Postgres and back-end server. Both of them are connected to the same private network. The volume of docker-compose is mandatory for the Postgres database because of the reusability consideration.
References: