Effortless Container Deployments: How Argo CD, Azure Container Registry and Simplify DevOps

Effortless Container Deployments: How Argo CD, Azure Container Registry and  Simplify DevOps

Introduction

Argo CD is a powerful tool that simplifies the deployment of Docker images to Kubernetes clusters, making it easier to manage and update applications. In this documentation, we will explain the process of using Argo CD in conjunction with Azure Container Registry and Jenkins to streamline the deployment workflow.

Requirements

  • A separate repository should be present to store manifest files.

  • Argo CD should be reachable to the bit bucket repository API.

  • Argo CD portal should be reachable from the user endpoint.

  • Developers should update the deployment file to perform seamless CI/CD

Argo CD Workflow

Workflow overview

A developer pushes code to Bit bucket, triggering Jenkins via a webhook. Jenkins does two main tasks:

  1. It builds Docker images and stores them in an Azure Container Registry.

  2. It runs a custom bash script to update a YAML file with the new image ID and pushes this change to the ArgoCD repository.

A new application is created in Argo CD, which then synchronizes with the Argo CD repository. This synchronization process deploys a new pod utilizing the updated image tag specified in the deployment file.

Configuration

  1. Repository.

    Set up a manifest repository at bit bucket or any other repository.

  2. Argo CD installation.

    Requirements

    • Installed kubectl command-line tool.

    • Have a kubeconfig file (default location is ~/.kube/config).

Installation of argocd

kubectl create ns argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.8.2/manifests/install.yaml
# inorder to get the initial password of the UI
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
  1. Configuration in Jenkins.

    Use the custom script that is present in the Argo CD manifest. To change the image and push the manifest file to the repository. And this script should be run via Jenkins.

#!/bin/bash

# author: Milan Dangol
# email: milan.dangol57@gmail.com

#-----------------
# How to run this ?
# chmod +x argocdscript
# ./argocdscript <deploy path > <bitbucket folder>
#./argocdscript ${WORKSPACE}/k8s/app.yaml <parent_dir>/<child_dir>
#--------------------
# Function to display an error message and exit
script_pid=$$
function die() {
    echo "Error: $1"
    kill -9 $script_pid  # Kill the script on error
    exit 1
}

# Check the number of arguments
if [ "$#" -ne 2 ]; then
    die "Usage: $0 <file_path> <bitbucket_folder> "
fi

# Assign the arguments to variables
file_path="$1"
bitbucket_folder="$2"

# Extract the branch name from the directory parameter
branch_name=$(echo "$bitbucket_folder" | cut -d'/' -f1 | cut -d'-' -f2-)

echo "Using branch $branch_name ...."

# Bitbucket SSH URL (replace with your repository's SSH URL)
bitbucket_ssh_url="git@bitbucket.org:<repositoryname>"

# Check if the file exists
if [ ! -f "$file_path" ]; then
    die "The specified file does not exist."
fi

# Clone the Bitbucket repository to a temporary directory
temp_dir=$(mktemp -d)
git clone -b "$branch_name" "$bitbucket_ssh_url" "$temp_dir" || die "Failed to clone the Bitbucket repository."

# Change Directory
cd "$temp_dir"

# Check if the directory $temp_dir/$bitbucket_folder/ exists, and create it if not along with deploy.yaml
if [ ! -d "$temp_dir/$bitbucket_folder" ]; then
    mkdir -p "$temp_dir/$bitbucket_folder" || die "Failed to create directory $temp_dir/$bitbucket_folder."
    touch "$temp_dir/$bitbucket_folder/deploy.yaml" || die "Failed to create deploy.yaml file."
fi

# Copy the file to the destination folder
cp "$file_path" "$temp_dir/$bitbucket_folder/deploy.yaml" || die "Failed to copy the file to the Bitbucket repository folder."


# Copy the file to a specific filename (e.g., deploy.yaml) in the Bitbucket repository folder
cp "$file_path" "$temp_dir/$bitbucket_folder/deploy.yaml" || die "Failed to copy the file to the Bitbucket repository folder."

# Use the Jenkins build number as the image tag
jenkins_build_number="$BUILD_NUMBER"
if [ -z "$jenkins_build_number" ]; then
    die "Jenkins build number is not set. Make sure you're running this script in a Jenkins build environment."
fi

# Define the image prefix
image_prefix="<azure-container-registery>/"

# Combine the prefix, image name, and Jenkins build number to create the new image URL
new_image_url="${image_prefix}${bitbucket_folder}:${jenkins_build_number}"

# Modify the deployment file (deploy.yaml) to set the new image URL
deployment_file="$temp_dir/$bitbucket_folder/deploy.yaml"
if [ ! -f "$deployment_file" ]; then
    die "The deployment file $deployment_file does not exist."
fi

# Use sed to replace the image URL in the deployment file
sed -i "s|image:.*|image: $new_image_url|g" "$deployment_file" || die "Failed to update the image URL in $deployment_file."

# Commit the changes to Bitbucket
git add . --all
git commit -m "Updated Manifest file $jenkins_build_number" || die "Failed to commit changes."

# Push the changes to Bitbucket
git push origin "$branch_name" || die "Failed to push changes to Bitbucket."

# Clean up the temporary directory
rm -rf "$temp_dir"

echo "File successfully pushed to Bitbucket with updated image tag on branch $branch_name."

exit 0
  1. Configuration of Argo CD application.

    1. Use argoappcreate to create applications for all the deployments and don't forget to apply all of them using kubectl command.
#!/bin/bash

# author: Milan Dangol
# email: milandangl57@gmail.com


# Prompt the user for the Bitbucket folder_name
read -p "Enter the root Bitbucket folder name (e.g., <parent dir>): " bitbucket_folder

# Define the temporary directory for cloning repositories
temp_dir=$(mktemp -d)

# Ensure the temporary directory exists

branch_name=$(echo "$bitbucket_folder" | cut -d'-' -f2 )

# Create a temporary directory for manifest files
manifest_dir=/tmp/argomanifest
mkdir $manifest_dir
# Clone the repository from Bitbucket using SSH
bitbucket_url="git@bitbucket.org:<reponame>"
git clone -b $branch_name "$bitbucket_url" "$temp_dir"

# Change to the temporary directory
cd "$temp_dir"
pattern="^([^-]+)-(.+)$"
# Check if the specified folder exists
if [ -d "$bitbucket_folder" ]; then
    # Loop through the directories and generate manifests
    for dir in "$bitbucket_folder"/*; do
        if [ -d "$dir" ]; then
            dir_name=$(basename "$dir")
            if [[ $dir_name =~ $pattern ]]; then
                new_text="${BASH_REMATCH[1]}-$branch_name-${BASH_REMATCH[2]}"
                echo "$new_text"
            else
                echo "Input does not match the pattern."
            fi
            # Define the template for the manifest
            template="apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: $new_text
  namespace: argocd
spec:
  destination:
    name: ''
    namespace: $bitbucket_folder  
    server: 'https://kubernetes.default.svc'
  source:
    path: "$bitbucket_folder/$dir_name"
    repoURL: '$bitbucket_url'
    targetRevision: $branch_name
  sources: []
  project: finpos
  syncPolicy:
    automated:
      prune: false
      selfHeal: false"

            # Save the template to a file in the manifest directory
            echo "$template" > "$manifest_dir/${dir_name}_manifest.yaml"

            echo "Manifest for $dir_name has been generated in $manifest_dir/${dir_name}_manifest.yaml"
        fi
    done
else
    echo "Folder '$bitbucket_folder' not found in Bitbucket repository."
fi

# Cleanup: Remove only the temporary clone directory
rm -rf "$temp_dir"

Conclusion

In conclusion, Argo CD has proven to be a valuable addition to our organization, simplifying and enhancing our container deployment processes. Its efficiency, centralized control, and adaptability to microservices management have made it an integral part of our workflow. With Argo CD, we've achieved seamless integration with Azure Container Registry and future-proofed our deployment strategies.