{"id":2567,"date":"2024-09-06T08:22:46","date_gmt":"2024-09-06T08:22:46","guid":{"rendered":"https:\/\/www.aviator.co\/blog\/?p=2567"},"modified":"2025-09-25T13:02:24","modified_gmt":"2025-09-25T13:02:24","slug":"choosing-between-pull-vs-push-based-gitops","status":"publish","type":"post","link":"https:\/\/www.aviator.co\/blog\/choosing-between-pull-vs-push-based-gitops\/","title":{"rendered":"Choosing Between Pull vs. Push-Based GitOps"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107167.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>GitOps has become essential in cloud-native deployments, particularly with Kubernetes. This article dives into the two primary GitOps approaches\u2014push and pull\u2014exploring their architectures, tools, and best use cases.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is GitOps?<\/h2>\n\n\n\n<p>At its core, GitOps leverages Git as a single source of truth for defining and managing your infrastructure and application deployment. It bridges the gap between development and operations using Git repositories as the primary deployment control mechanism. Changes to your system are made by updating your Git repository, with automation tools applying these updates to your environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How does GitOps Work?<\/h2>\n\n\n\n<p>GitOps can be implemented using two main approaches: push and pull. In the push approach, CI\/CD tools directly send changes from the Git repository to the environment. On the other hand, the pull approach uses GitOps operators to fetch changes from the repository and apply them to the environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Push-Based GitOps<\/h2>\n\n\n\n<p>The push-based approach in GitOps is akin to the traditional <a href=\"https:\/\/www.aviator.co\/blog\/how-to-create-a-ci-cd-pipeline\/\" target=\"_blank\" rel=\"noopener\" title=\"CI\/CD pipelines\">CI\/CD pipelines<\/a>. In this model, a CI\/CD tool actively pushes changes from the Git repository to the target environment. This method gives you more control over the deployment process but requires more setup and maintenance.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107216.png\" alt=\"push-architecture\"\/><\/figure>\n\n\n\n<p>Popular tools for push-based GitOps include <a href=\"https:\/\/www.jenkins.io\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Jenkins<\/a>, <a href=\"https:\/\/github.com\/features\/actions\" target=\"_blank\" rel=\"noopener\" title=\"\">GitHub Actions<\/a>, <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/\" target=\"_blank\" rel=\"noopener\" title=\"\">GitLab CI\/CD<\/a>, <a href=\"https:\/\/circleci.com\/\" target=\"_blank\" rel=\"noopener\" title=\"\">CircleCI<\/a>, and <a href=\"https:\/\/buildkite.com\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Buildkite<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Jenkins vs. GitHub Actions<\/h3>\n\n\n\n<p>Jenkins offers extensive customization and complex pipeline support but requires dedicated infrastructure. GitHub Actions provides easy setup, a better UI, and a seamless GitHub repository integration, making it ideal for GitHub users, though with less deep customization.<\/p>\n\n\n\n<p>Below is a comparison table highlighting the key differences between the two tools:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107188.png\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Implementation with GitHub Actions<\/h3>\n\n\n\n<p>Consider a microservices architecture with multiple applications. You can set up a GitHub Actions workflow that triggers on every push to the main branch. For example, this workflow can:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Run <a href=\"https:\/\/www.aviator.co\/blog\/integration-testing-and-unit-testing-in-the-age-of-ai\/\" target=\"_blank\" rel=\"noopener\" title=\"unit and integration tests\">unit and integration tests<\/a>.<\/li>\n\n\n\n<li>Build <a href=\"https:\/\/www.docker.com\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Docker<\/a> images for your services.<\/li>\n\n\n\n<li>Push the images to a container registry.<\/li>\n\n\n\n<li>Deploy the updated images to your Kubernetes cluster using <em>kubectl<\/em> commands.<\/li>\n<\/ol>\n\n\n\n<p>This straightforward approach works well for teams already using GitHub for source control.<\/p>\n\n\n\n<p>This tutorial will use Azure AKS as the managed Kubernetes cluster. Let us start by creating a repository in GitHub.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-114103-1.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Add the Azure and Docker secrets required for the pipeline to access the platforms.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-115128.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now, create an application server locally. We are using an <a href=\"https:\/\/expressjs.com\/en\/starter\/hello-world.html\" target=\"_blank\" rel=\"noopener\" title=\"\">Express server<\/a> in <b>app.js<\/b> for this tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>const express = require('express')\nconst app = express()\nconst port = 3000app.get('\/', (req, res) =&gt; {\n&nbsp; res.send('This is an app for Push-based GitOps!')\n})app.listen(port, () =&gt; {\n&nbsp; console.log(`Example app listening on port ${port}`)\n})<\/p><\/code><\/pre>\n\n\n\n<p>Create a Dockerfile to containerize the application.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>FROM node:latest\nWORKDIR \/usr\/src\/app\nCOPY package*.json .\/\nRUN npm install\nCOPY . .\nEXPOSE 3000\nCMD &#91;\"node\", \"app.js\"]<\/p><\/code><\/pre>\n\n\n\n<p>Add the following pipeline code in<b> .github\/workflows\/pipeline.yaml<\/b>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>name: CI\/CD Pipelineon:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - mainjobs:\n&nbsp; build:\n&nbsp; &nbsp; runs-on: ubuntu-latest&nbsp; &nbsp; steps:\n&nbsp; &nbsp; - name: Checkout code\n&nbsp; &nbsp; &nbsp; uses: actions\/checkout@v3&nbsp; &nbsp; - name: Set up Docker Buildx\n&nbsp; &nbsp; &nbsp; uses: docker\/setup-buildx-action@v3&nbsp; &nbsp; - name: Log in to Docker Hub\n&nbsp; &nbsp; &nbsp; uses: docker\/login-action@v3\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; username: ${{ secrets.DOCKER_USERNAME }}\n&nbsp; &nbsp; &nbsp; &nbsp; password: ${{ secrets.DOCKER_PASSWORD }}&nbsp; &nbsp; - name: Build and push Docker image\n&nbsp; &nbsp; &nbsp; uses: docker\/build-push-action@v5\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; context: .\n&nbsp; &nbsp; &nbsp; &nbsp; push: true\n&nbsp; &nbsp; &nbsp; &nbsp; tags: ${{ secrets.DOCKER_USERNAME }}\/push-gitops:latest&nbsp; deploy:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n&nbsp; &nbsp; needs: build&nbsp; &nbsp; steps:\n&nbsp; &nbsp; - name: Checkout code\n&nbsp; &nbsp; &nbsp; uses: actions\/checkout@v3&nbsp; &nbsp; - name: Set up Kubectl\n&nbsp; &nbsp; &nbsp; uses: azure\/setup-kubectl@v3\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; version: 'latest'&nbsp; &nbsp; - name: Azure Login\n&nbsp; &nbsp; &nbsp; uses: azure\/login@v1\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; creds: ${{ secrets.AZURE_CREDENTIALS }}&nbsp; &nbsp; - name: Set up AKS context\n&nbsp; &nbsp; &nbsp; run: az aks get-credentials --resource-group ${{ secrets.AZURE_RESOURCE_GROUP }} --name ${{ secrets.AKS_CLUSTER_NAME }}&nbsp; &nbsp; - name: Deploy to AKS\n&nbsp; &nbsp; &nbsp; run: kubectl apply -f k8s<\/p><\/code><\/pre>\n\n\n\n<p>The above pipeline creates a docker image of the code, pushes it to DockerHub, and finally deploys the kubernetes manifest files in the cluster on every code push to the main branch.<\/p>\n\n\n\n<p>Create a Kubernetes manifest file in<b> k8s\/deploy.yaml<\/b> to deploy the containerized application in the Kubernetes cluster.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: push-svc\nspec:\n  selector:\n    name: push-pod\n  type: LoadBalancer\n  ports:\n    - protocol: TCP\n      port: 3000\n      targetPort: 3000\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: push-deploy\n  labels:\n    name: push-deploy\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      name: push-pod\n  template:\n    metadata:\n      labels:\n        name: push-pod\n    spec:\n      containers:\n        - name: push-container\n          image: &lt;your-docker-username&gt;\/push-gitops:latest\n          ports:\n            - containerPort: 3000<\/code><\/pre>\n\n\n\n<p>Finally, create <b>.gitignore <\/b>and <b>.dockerignore <\/b>files and add the <b>node_modules<\/b> directory to avoid large file transfers to the repository and the container.<\/p>\n\n\n\n<p>After completing all the above steps, initialize a local git repository for the project, commit the changes, create the \u201cmain\u201d branch locally, and push the code on your remote repository.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git init\ngit commit -m \"push-gitops\"\ngit branch -M main\ngit remote add origin &lt;your-remote-repository-url&gt;\ngit push -u origin main<\/code><\/pre>\n\n\n\n<p>Verify the pipelines are successfully executed in the actions tab in GitHub.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-223757-1.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Get the external IP of the \u201cpush-svc\u201d service created on the cluster to verify the application deployment.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-224312.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Enter the external IP of the service in the browser with the port to verify the application.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-225828.png\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Pull-Based GitOps<\/h2>\n\n\n\n<p>In a pull-based GitOps model, a GitOps operator (e.g., <a href=\"https:\/\/fluxcd.io\/\" target=\"_blank\" rel=\"noopener\" title=\"\">FluxCD<\/a> or <a href=\"https:\/\/argo-cd.readthedocs.io\/en\/stable\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ArgoCD<\/a>) running within your environment that continuously checks the Git repository for changes. When a change is detected, the operator pulls these changes and applies them to the environment.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107217.png\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">FluxCD vs ArgoCD<\/h3>\n\n\n\n<p>FluxCD and ArgoCD differ mainly in user experience, customization, and integration. ArgoCD provides a polished UI and features like ApplicationSets and automated rollbacks, which are ideal for ease of use. FluxCD, though more complex, is a more flexible and modular approach, making it suited for teams needing advanced customization.<\/p>\n\n\n\n<p>Here&#8217;s a table summarizing these differences:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107187.png\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Implementation with ArgoCD<\/h3>\n\n\n\n<p>After setting up ArgoCD in your Kubernetes cluster, you can connect it to your Git repository. ArgoCD monitors the repository for any changes to the manifest files, and synchronizes the application with the desired state defined in Git.<\/p>\n\n\n\n<p>Let us create a new repository on GitHub.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-163448.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Set up ArgoCD on your Kubernetes Cluster using their <a href=\"https:\/\/argo-cd.readthedocs.io\/en\/stable\/getting_started\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Getting Started<\/a> guide and create an ArgcoCD deployment pipeline.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>apiVersion: argoproj.io\/v1alpha1\nkind: Application\nmetadata:\n&nbsp; name: argo-pipeline\n&nbsp; namespace: argocdspec:\n&nbsp; project: default\n&nbsp; source:\n&nbsp; &nbsp; repoURL: &lt;your-git-repository&gt;\n&nbsp; &nbsp; targetRevision: HEAD\n&nbsp; &nbsp; path: k8s\n&nbsp; destination:\n&nbsp; &nbsp; server: https:\/\/kubernetes.default.svc\n&nbsp; &nbsp; namespace: pull-gitops\n&nbsp; syncPolicy:\n&nbsp; &nbsp; syncOptions:\n&nbsp; &nbsp; - CreateNamespace=true\n&nbsp; &nbsp; automated:\n&nbsp; &nbsp; &nbsp; prune: true<\/p><\/code><\/pre>\n\n\n\n<p>This pipeline gets triggered whenever there is a difference between the manifest files in the <b>k8s <\/b>directory of the remote repository and the actual state of the cluster. It brings the actual state of the cluster as configured in the manifest files of the <b>k8s <\/b>directory. Apply this pipeline in the Kubernetes cluster.<\/p>\n\n\n\n<p>Copy all the files except <b>node_modules <\/b>&nbsp;we made in the push-based approach to the pull-based approach.<\/p>\n\n\n\n<p>Change the<b> .github\/workflows\/pipeline.yaml<\/b> with the following code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>name: CI Pipelineon:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; &nbsp; paths-ignore:\n&nbsp; &nbsp; &nbsp; - 'k8s'jobs:\n&nbsp; build:\n&nbsp; &nbsp; runs-on: ubuntu-latest&nbsp; &nbsp; steps:\n&nbsp; &nbsp; - name: Checkout code\n&nbsp; &nbsp; &nbsp; uses: actions\/checkout@v3&nbsp; &nbsp; - name: Set up Docker Buildx\n&nbsp; &nbsp; &nbsp; uses: docker\/setup-buildx-action@v3&nbsp; &nbsp; - name: Log in to Docker Hub\n&nbsp; &nbsp; &nbsp; uses: docker\/login-action@v3\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; username: ${{ secrets.DOCKER_USERNAME }}\n&nbsp; &nbsp; &nbsp; &nbsp; password: ${{ secrets.DOCKER_PASSWORD }}&nbsp; &nbsp; - name: Build and push Docker image\n&nbsp; &nbsp; &nbsp; uses: docker\/build-push-action@v5\n&nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; context: .\n&nbsp; &nbsp; &nbsp; &nbsp; push: true\n&nbsp; &nbsp; &nbsp; &nbsp; tags: ${{ secrets.DOCKER_USERNAME }}\/pull-gitops:${{ github.sha }}&nbsp; deploy:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n&nbsp; &nbsp; needs: build&nbsp; &nbsp; steps:\n&nbsp; &nbsp; &nbsp; - name: Checkout repository\n&nbsp; &nbsp; &nbsp; &nbsp; uses: actions\/checkout@v4\n&nbsp; &nbsp; &nbsp; - name: Update deployment.yaml\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sed -E -i \"s\/&lt;your-github-username&gt;\/pull-git&#91;a-zA-Z0-9:\/-]+\/&lt;your-github-username&gt;\/pull-gitops:${{ github.sha }}\/g\" k8s\/deploy.yaml&nbsp; &nbsp; &nbsp; - name: Stage changes\n&nbsp; &nbsp; &nbsp; &nbsp; run: git add k8s\/deploy.yaml&nbsp; &nbsp; &nbsp; - name: Set Git user identity\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git config --global user.email \"&lt;your-github-email&gt;\"\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git config --global user.name \"&lt;your-github-username&gt;\"&nbsp; &nbsp; &nbsp; - name: Commit changes\n&nbsp; &nbsp; &nbsp; &nbsp; run: git commit -m \"Update k8s manifest\" k8s\/deploy.yaml&nbsp; &nbsp; &nbsp; - name: Push changes\n&nbsp; &nbsp; &nbsp; &nbsp; uses: ad-m\/github-push-action@master\n&nbsp; &nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; github_token: ${{ secrets.GIT_TOKEN }}\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; branch: main<\/p><\/code><\/pre>\n\n\n\n<p>The above yaml is just for continuous integration, which builds a docker image with a unique image tag and updates the k8s directory with a new docker image for the ArgoCD pipeline to get triggered.<\/p>\n\n\n\n<p>Change the<b> app.js<\/b> response to identify the server deployed using the pull-based approach.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><p>const express = require('express')\nconst app = express()\nconst port = 3000app.get('\/', (req, res) =&gt; {\n&nbsp; res.send('This is an app for Pull-based GitOps!')\n})app.listen(port, () =&gt; {\n&nbsp; console.log(`Example app listening on port ${port}`)\n})<\/p><\/code><\/pre>\n\n\n\n<p>Leave the remaining files similar to the push-based approach.&nbsp;<\/p>\n\n\n\n<p>We don\u2019t need the credentials of the Kubernetes cluster in GitHub for this approach. Just create a personal access token with the repository level access and add it as a secret.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-170143.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>After completing all the above steps, initialize a local git repository for the project, commit the changes, create the \u201cmain\u201d branch locally, and push the code on your remote repository.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git init\ngit commit -m \"pull-gitops\"\ngit branch -M main\ngit remote add origin &lt;your-remote-repository-url&gt;\ngit push -u origin main<\/code><\/pre>\n\n\n\n<p>Verify that the pipeline is successfully executed.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-231809.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Go to the ArgoCD Web UI and verify that that pipeline is in sync with the latest commits.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-232100.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Get the external IP of the \u201cpull-svc\u201d service created on the cluster to verify the application deployment.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-232644.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Enter the external IP of the service in the browser with the port to verify the application.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-08-23-232952.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now that we have implemented both the GitOps approaches, let us summarize how they differ, when to use the pull approach, and when to use the push approach.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Push vs. Pull-based GitOps<\/h2>\n\n\n\n<p>The push and pull approaches in GitOps differ in control, setup complexity, and deployment speed. The push approach offers centralized control through CI\/CD tools, allowing for high flexibility with customizable pipelines but requiring a more complex setup. In contrast, the pull approach uses GitOps tools for decentralized automation, providing a more straightforward setup and automated rollbacks but with moderate deployment speed due to polling intervals.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107186.png\" alt=\"\" width=\"4972\" height=\"3890\"><\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">When to Use the Push Approach<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><b>Greater Control<\/b>: Ideal if you need complex build and test processes or have specific requirements for deployment order.<\/li>\n\n\n\n<li><b>Existing CI\/CD Investments<\/b>: If your team already uses CI\/CD tools like Jenkins or GitHub Actions, leveraging these tools for GitOps can streamline the process.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">When to Use the Pull Approach<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><b>Hands-off approach<\/b>: Pull-based is a more hands-off approach where the deployment is automated and managed by GitOps tools.<\/li>\n\n\n\n<li><b>Kubernetes-native environments<\/b>: Pull-based tools like ArgoCD are explicitly designed for Kubernetes and can easily handle complex multi-cluster setups.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Both push and pull approaches in GitOps offer unique benefits. The push approach provides granular control, while the pull approach simplifies deployment management. Your choice between these approaches and tools\u2014whether it&#8217;s Jenkins vs. GitHub Actions or FluxCD vs. ArgoCD\u2014should align with your team\u2019s workflow and long-term goals.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\" https:\/\/www.aviator.co\/merge-queue\" target=\"_blank\" rel=\" noreferrer noopener\"><img decoding=\"async\" width=\"1940\" height=\"500\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1.png\" alt=\"Mergequeue CTA\" class=\"wp-image-4920\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1.png 1940w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1-300x77.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1-1024x264.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1-768x198.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/04\/aviator-mergequeue-blog-service-page-cta-photo-min-1-1536x396.png 1536w\" sizes=\"(max-width: 1940px) 100vw, 1940px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently Asked Questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is GitOps vs DevOps?<\/h3>\n\n\n\n<p>DevOps is a broad practice that integrates development and operations for faster, more reliable software delivery. GitOps is a specific implementation of DevOps that uses Git as the single source of truth for infrastructure and application deployments, automating and managing everything via Git.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why Should I Use GitOps?<\/h3>\n\n\n\n<p>GitOps ensures consistency, automates deployments, improves security, and simplifies collaboration by using Git as the source of truth for all changes, making your infrastructure management more reliable and scalable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the Difference Between Push and Pull Model of GitOps?<\/h3>\n\n\n\n<p>The difference between the push and pull models in GitOps lies in how deployments are handled. In the push model, CI\/CD tools like Jenkins or GitHub Actions actively push changes from the Git repository to the environment. In the pull model, an operator within the environment, such as ArgoCD or FluxCD, continuously monitors the Git repository and pulls changes as they are detected, automatically applying them to the environment.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Is ArgoCD Push or Pull?<\/h3>\n\n\n\n<p>ArgoCD is a pull-based GitOps tool that continuously pulls changes from a Git repository and applies them to your Kubernetes environment.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn about the two approaches to GitOps &#8211; push and pull &#8211; and how to implement them, their differences, benefits, and commonly used tools for each approach.<\/p>\n","protected":false},"author":38,"featured_media":2587,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[58],"tags":[113,115,116,114],"class_list":["post-2567","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ci-cd-deployment"],"blocksy_meta":[],"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/09\/Frame-1430107167.png","post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2567","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/comments?post=2567"}],"version-history":[{"count":23,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2567\/revisions"}],"predecessor-version":[{"id":4925,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2567\/revisions\/4925"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media\/2587"}],"wp:attachment":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media?parent=2567"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/categories?post=2567"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/tags?post=2567"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}