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
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
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-httpwhile being on
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
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
We should be able to build and run the docker image locally:
docker build . -t automaticdeploy docker run --rm -it automaticdeploy
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
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.