Introduction
For this workflow, we are going to use docker to build the images, which later are going to be used to deploy the service. In order to update it automatically we are going to use Gitlab CI/CD that updates the docker image whenever a merge request completes on the specified branches (keep in mind we are going to use Gitflow). Lastly Watchtower is going to check if there is a new image on the registry, if so it’s going to update it automatically.
Here is a small image to showcase the workflow:
st=>start: Create git repository
sdev=>operation: Develop the base app
dck=>operation: Create docker configuration
dep=>operation: Deploy the app
runwt=>subroutine: Execute watchtower
devft=>operation: Develop new feature
mrg=>operation: Merge to develop
accept=>condition: Passes all tests?
bddck=>subroutine: Build new docker image
fixerr=>subroutine: Fix errors
bddck=>subroutine: Build new docker image
st->sdev->dck->dep->runwt->devft->mrg->accept
bddck->devft
accept(yes)->bddck
accept(no)->fixerr->mrg
Git
Before anything else let’s setup the git repository. Start by creating a git repository on gitlab and clone it.
We can initialize the project by creating a README:
echo "Automatic deploy project" > README.md
git add .
git commit -m "Initialized the repository"
git push --set-upstream origin main
Now we can switch to develop branch based on main and push it to origin:
git checkout -b develop
git push --set-upstream origin develop
Sample app
In order to be more ilustrative I’m going to create a pretty sample API using Node.js.
Start by creating a feature branch:
git checkout -b feature/api
Create the node repository:
mkdir src
cd src
npm init -y
npm i express
Now create a file named index.js
in the src
folder with the following content:
|
|
At this point we have an already functional web api. However to make it more realistic, let’s create some tests. Create a folder named src/test
, inside of it add the file index.js
with the following tests:
|
|
Remember to install dependencies with
npm i -D mocha chai chai-http
while being onsrc
Finally modify package.json
to add a couple custom scripts:
|
|
The app is fully finished, before pushing it to the origin let’s add node_modules
to gitignore:
echo "src/node_modules/" > .gitignore
git add .
git commit -m "Created sample api"
git push --set-upstream origin feature/api
Don’t forget to merge the feature to develop within GitLab
Docker
The next step is to configure how the Docker image should be build, to do so we create a Dockerfile
in the root of the repository:
|
|
Let’s also create a file called .dockerignore
:
src/node_modules/
We should be able to build and run the docker image locally:
docker build . -t automaticdeploy
docker run --rm -it automaticdeploy
Gitlab
Now we are going to set up Gitlab CI/CD, so let’s create a file named .gitlab-ci.yml
in the root of the repository:
|
|
Additionally create the following variables in Gitlab repo (Remember to change the values):
We can now merge develop
to main
.
Deployment
Once both starting images have been deployed to the registry (dockerhub in this case), we can run the service in our server:
docker run -d -p 3000:3000 itasahobby/automaticdeploy:latest
docker run -d -p 3333:3000 itasahobby/automaticdeploy:develop
docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --schedule "0 * * * * *"
Finally we have on port 3000 main
version running, and develop
on port 3333. Whenever we update our repository (and passes all tests) the image will be updated by Watchtower, relaunching the container.
So we can keep adding features to the app without taking care of updating the running service.
You can also check the source code of the original repository or a similar one using Github Actions