Scenario Overview
In my project, I have two primary servers: one for the development team and another for the Quality Control (QC) team. Each time a developer commits code, they need to build the project and commit the build files as a new commit on their branch. The build command used varies depending on the target environment, affecting the endpoints within the project.
To streamline this process, I set up a CI/CD pipeline using GitLab CI/CD, which automates the build and deployment steps and pushes the new commit to a dedicated deploy repository. Here's a step-by-step breakdown of the implemented workflow:
- Developer Commits Code: Developers commit their changes to the repository.
- Add Tag to Trigger CI/CD: To run the CI/CD pipeline, developers add a specific tag to their commit.
- CI/CD Pipeline Execution: The pipeline runs, building the project based on the tag.
- Push Build Artifact: The built artifacts are committed yo the deploy repository as a new commit.
- Slack Notification: A notification is sent to Slack upon successful deployment.
Prerequisites
- ReactJS project
- Define two build types in package.json:
build-dev
andbuild-qc
- Two repositories: develop and deploy
- Two branches in the deploy repo:
feature/develop_deploy
andfeature/testing_develop
- Slack channel webhook URL
Let's dive into it!
CI/CD Configuration
1. Install Stage
install_dependencies:
stage: install
image: node:latest
script:
- npm install --legacy-peer-deps
rules:
- if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*$/'
Purpose: This stage installs all the necessary dependencies required for the project.
- image: node: Specifies the Docker image to be used for this stage. Here, I use the latest Node.js image.
-
script: Contains the commands to be executed in this stage. In this case, it runs
npm install --legacy-peer-deps
to install the Node.js dependencies, allowing for compatibility with older peer dependencies. -
rules: This specifies when the job should run. It uses a regular expression to check if the commit tag matches the pattern
build-dev-
orbuild-qc-
, meaning this job runs only if such tags are present.
2. Build Stage
build_project:
stage: build
image: node:latest
script:
- echo "CI_COMMIT_TAG=$CI_COMMIT_TAG"
- >
if [[ "$CI_COMMIT_TAG" == "build-dev"* ]]; then
npm run build:dev
elif [[ "$CI_COMMIT_TAG" == "build-qc"* ]]; then
npm run build:qc
else
echo "No specific build command for this tag."
fi
artifacts:
paths:
- build/
expire_in: 1 hour
rules:
- if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*$/'
Purpose: This stage builds the project based on the environment specified by the tag.
- image: node: Uses the latest Node.js image.
-
script: Executes the following commands:
-
echo "CI_COMMIT_TAG=$CI_COMMIT_TAG"
: Prints the commit tag to verify the tag. - The conditional block checks the tag:
- If the tag starts with
build-dev
, it runsnpm run build:dev
. - If the tag starts with
build-qc
, it runsnpm run build:qc
. - Otherwise, it prints a message saying no specific build command is found for the tag.
- If the tag starts with
-
-
artifacts: Specifies the files to be preserved after the job is done. Here, it keeps the
build/
directory for 1 hour. -
rules: Similar to the
install
stage, this job runs only if the commit tag matches the patternbuild-dev-
orbuild-qc-
.
3: Deploy Stage
deploy_project:
stage: deploy
image: alpine:latest
before_script:
- apk update && apk add git openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > private_key
- chmod 600 private_key
- ls -l private_key # Verify the permissions
- echo "$SSH_PRIVATE_KEY" | wc -c # Check the length of the SSH_PRIVATE_KEY
- ssh-add private_key
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
- git config --global user.email "your email"
- git config --global user.name "your username"
script:
- apk add --no-cache curl # Install curl
- echo "Deploying the project... $CI_COMMIT_TAG"
- BRANCH_NAME="feature/develop_deploy" # Default branch name
- 'if [[ "$CI_COMMIT_TAG" == *qc* ]]; then BRANCH_NAME="feature/testing_deploy"; fi'
- mkdir tmp_repo && cd tmp_repo
- git clone deploy-repo .
- echo "Checking out to $BRANCH_NAME"
- git checkout $BRANCH_NAME # Corrected to use the variable
- cp -r ../build/* .
- git add .
- git diff --quiet --exit-code || git commit -m "Deploying artifacts from CI - $CI_COMMIT_TAG"
- git push || echo "No changes to push."
- >
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"Deployment of $CI_COMMIT_TAG completed successfully.\"}" "YOUR WEBHOOK URL"
rules:
- if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*/'
Purpose: This stage deploys the built project to a remote repository and notifies the team via Slack.
- image: alpine: Uses a lightweight Alpine Linux image.
-
before_script: Prepares the environment for deployment:
- Installs necessary packages:
git
andopenssh-client
. - Sets up SSH for secure communication.
- Adds the SSH private key.
- Configures Git with user email and name.
- Installs necessary packages:
-
script: Executes the deployment commands:
- Installs
curl
. - Clones the deploy repository.
- Checks out the branch
feature/develop_deploy
orfeature/testing_deploy
. - Copies the build artifacts to the repository.
- Commits and pushes the changes.
- Sends a Slack notification upon successful deployment.
- Installs
-
rules: This job runs only if the commit tag matches the pattern
build-dev-
orbuild-qc-
.
Pipeline 🚀🚀🚀
Slack notification 🔈🔈🔈
Note
If you face the following error:
Agent pid 23
$ echo "$SSH_PRIVATE_KEY" | tr -d '\r' > private_key
$ cat private_key
$ ssh-add private_key
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'private_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Cleaning up project directory and file based variables
- Go to the setting of Gitlab -> CICD -> Variables -> Uncheck [Protect variable]
Final thought
This is just a simple idea for CI/CD. It can be improved further, so please leave your comments if you have any suggestions for improvement. Thanks for reading!
Top comments (0)