Deployment and Integration

Maintain your app, please

Johanes Jason
8 min readMay 6, 2022

“In software, when something is painful, the way to reduce the pain is to do it more frequently, not less.”― David Farley, Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation

Deployment illustration

Imagine that you have created a perfect application running in your local environment. Your product is ready to be made, but users can’t access your application because they don’t have the source code. Then how can you make your application usable by many people? Deployment is the answer.

What Is Deployment?

Deployment or Software Deployment includes all of the steps, processes, and activities that are required to make a software system or update available to its intended users. Some of the most common activities of deployment are software release, installation, testing, deployment, and performance monitoring. So more or less the point is that software deployment is useful so that the applications we create can be used publicly.

Deployment Strategies

A deployment strategy is a technique to change, update, upgrade, or re-create your application. The purpose of deployment strategy is to make your changes to apply without any downtime in a way that the user barely notices the improvement or changes. There are some thing to consider when you choose a deployment strategy, such as :

  • Long running connections need to be handled carefully and beautifully.
  • Database conversion need to be done and rolled back along with the application.
  • Downtime may be needed if you use a hybrid architecture like microservices and monolith, because we need time to complete the transition.
  • You need the infrastructure to do this.
  • If you don’t carefully manage your environment, you can crash your new and old version of application.

Many deployment strategies are supported through the deployment configuration and some additional strategies are supported through router features. Some examples of deployment strategies include:

Rolling Strategy

A rolling deployment slowly replaces instances of the previous version of an application with instances of the new version of the application. A rolling deployment typically waits for new pods to become ready via a readiness check before scaling down the old components. If a significant issue occurs, the rolling deployment can be aborted.

Canary Deployment

A new version (the canary) is tested before all of the old instances are replaced. If the readiness check never succeeds, the canary instance is removed and the deployment configuration will be automatically rolled back. The readiness check is part of the application code, and may be as sophisticated as necessary to ensure the new instance is ready to be used.

Blue-Green Deployment

Blue-Green deployments use two deployment configurations. Both are running, and the one in production depends on the service the route specifies, with each deployment configuration exposed to a different service. You can create a new route to the new version and test it. When ready, change the service in the production route to point to the new service and the new, blue, version is live. If necessary, you can roll back to the older, green, version by switching service back to the previous version.

A/B Deployment

The A/B deployment strategy lets you try a new version of the application in a limited way in the production environment. You can specify that the production version gets most of the user requests while a limited fraction of requests go to the new version. Since you control the portion of requests to each version, as testing progresses you can increase the fraction of requests to the new version and ultimately stop using the previous version. As you adjust the request load on each version, the number of pods in each service may need to be scaled as well to provide the expected performance.

Recreate Strategy

The Recreate strategy has basic rollout behavior and supports lifecycle hooks for injecting code into the deployment process. This strategy more or less overwrites the old version of the app with the newer version. This strategy is very easy to use and implement, although it is quite dangerous because it can cause the application to crash if there is an error.

Deployment Best Practices

Your goal is a smooth, secure rollout. Using automation eliminates the chance of human error creeping into the process. And the more expansive the deployment, the higher the chance of something going wrong. Here are some other best practices to consider for deployment:

  • Use continuous integration (CI): As suggested by its namesake, continuous integration servers (also known as “build servers”) pull code from your dev team and test it — continuously. This helps ensure apps will work in your environment, not just in the dev’s personal sandbox.
  • Adopt continuous delivery (CD): Continuous delivery helps ensure your code changes are ready for primetime by automatically preparing them to move from deployment to production through rigorous testing. This should allow you more time to troubleshoot.
  • Formulate a backup plan: What will you do if things go wrong? Watching a failed deployment go down the tubes is not the time to scramble for an answer. Proactively plan ahead for contingencies with a good rollback strategy in place.

Deployment Implementation in PPL Project

In my team’s PPL project, we were asked to make an application according to our client’s request. Therefore, we definitely need deployment so that our application can be used by our clients.

What strategies do we use?

We use Canary Deployment strategy in our deployment process. We do this so that our main application does not experience problems when we are doing maintenance or updating. In our application, we use 3 main branches in our project work, namely development, staging, and production. We use development to collect code from all team members to check for conflicts.

After all the code is assembled and there are no problems, then we will move the code from the development branch to the staging branch. Staging is a temporary deployment place that has the exact same environment as production. In staging, we still allow errors to occur, because staging is indeed a place to test our application, whether it is running well or not. This is tested by usability testing that we do every sprint, that I already made a blog about that and you can read in here. This is done to check whether the latest version of our application is ready to be released or not. If it is not ready, it will be canceled and repaired again.

Implementing best practices

CI/CD and Backup Plan
Continuous integration (CI) is integrating code into a code repository and then running tests automatically, quickly, and frequently. You can do this CI by using the commit command. While continuous delivery or continuous deployment (CD) is a practice that is carried out after the CI process is complete and all code has been successfully integrated, so that applications can be built and released automatically.
To implement this, we use GitLab CI/CD in our application. This is an example of the CI/CD that we use in our project, on the backend :

stages:
- test
- sonar
- deploy

# Untuk unit testing
Test:
image: python:3.7.3
stage: test
before_script:
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
- echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list
- pip install -r requirements.txt
- python manage.py makemigrations
- python manage.py migrate
- apt-get update -qq && apt-get install -y -qq unzip
- python manage.py collectstatic --no-input
- python manage.py runserver 8000 &
when: on_success
script:
- coverage run --omit='manage.py' --include="homepage/*","authentication/*","profileCRU/*","kelas/*","mata_kuliah/*","kurikulum/*","riwayat_mata_kuliah/*","riwayatSemester/*","rencana/*" manage.py test
- coverage report -m
- coverage xml -i
artifacts:
paths:
- htmlcov/
- coverage.xml

Staging:
image: ruby:2.7
stage: deploy
before_script:
- gem install dpl
- wget -qO- https://cli-assets.heroku.com/install-ubuntu.sh | sh
script:
- dpl --provider=heroku --app=$HEROKU_APPNAME_STAGING --api-key=$HEROKU_APIKEY
- export HEROKU_API_KEY=$HEROKU_APIKEY
- heroku run --app $HEROKU_APPNAME_STAGING python manage.py migrate
environment:
name: production
url: $HEROKU_APP_HOST_STAGING
only:
- staging

SonarScanner:
image:
name: sonarsource/sonar-scanner-cli:4.6
entrypoint: [""]
stage: sonar
script:
- sonar-scanner
-Dsonar.sources=.
-Dsonar.host.url=https://sonarqube.cs.ui.ac.id
-Dsonar.login=$SONARQUBE_TOKEN
-Dsonar.projectKey=$SONARQUBE_PROJECT_KEY
-Dsonar.python.coverage.reportPaths=coverage.xml
-Dsonar.exclusions=manage.py,rencanaco_backend/*,**/static/**,static/*,oauth_app/*,**/tests.py,**/migrations/**
-Dsonar.branch.target=staging
only:
- staging


Production:
image: ruby:2.7
stage: deploy
before_script:
- gem install dpl
- wget -qO- https://cli-assets.heroku.com/install-ubuntu.sh | sh
script:
- dpl --provider=heroku --app=$HEROKU_APPNAME --api-key=$HEROKU_APIKEY
- export HEROKU_API_KEY=$HEROKU_APIKEY
- heroku run --app $HEROKU_APPNAME python manage.py migrate
environment:
name: production
url: $HEROKU_APP_HOST
only:
- master

Here’s some explanation. First, as you can see we have 3 stages that will run every time I push my code into a certain branch in GitLab.

The first one is Test, which is used for testing. This section is more or less useful for running unit tests on the GitLab runner we’re using. This testing is done to keep our application running perfectly and all code has been covered with 100% coverage.

The second is Staging, which if you pay attention it only runs on the staging branch. In this staging, we deploy the application to Heroku, which is a web hosting service. We do this to anticipate errors that may appear when the application is released, because staging uses the exact same environment as production.

The third is SonarScanner. This is our process of implementing software quality assurance, so that the applications we make are free from bugs, security issues, code smells, and the like. We do this to maintain the quality of our software in order to provide the best service for users.

The last one is Production. In this production process, we also deploy to Heroku using a different domain. The entire environment in production is exactly the same as staging, so if the application we make is safe in staging, then we just update the application that is in production with the one in staging. This production part is a deployment process whose results can be enjoyed by users publicly.

Docker usage

Docker is an open source containerization platform. It enables developers to package applications into containers — standardized executable components combining application source code with the operating system (OS) libraries and dependencies required to run that code in any environment.

We don't implement docker directly, but we use docker while the CI/CD process is running. If you notice in CI/CD staging and production section, we call the ruby ​​image with version 2.7, so when GitLab runner is running, it will call the docker executor to call the ruby ​​image with the version we requested. You can see the example here:

Using docker executor to call ruby image

Application Maintenance

To keep the applications that we make do not produce errors or errors, we use a logging system for every service we make, so that we will know when an error occurs in our application. Because we use Heroku as a web hosting service, we are provided with our own logging system from Heroku that can be used to monitor the services we create.

Heroku logging example

As you can see, we can watch our CRUD service when called by the user. That way, we can find out if an error occurs if our application is damaged.

--

--

Johanes Jason

A normal college student from Faculty of Computer Science, University of Indonesia