OpenTofu is now part of the Linux Foundation 🎉

Read more here →

General

What Is ArgoCD? A Practical Tutorial With Kubernetes

What Is Argo CD? Practical Tutorial With Kubernetes

In this article, we’ll explore Argo‘s features and use it to run a simple demo application.

Argo CD is “a declarative, GitOps continuous delivery tool for Kubernetes.” It can monitor your source repositories and automatically deploy changes to your cluster.

Kubernetes orchestrates container deployment and management tasks. It starts your containers, replaces them when they fail, and scales your service across the compute nodes in your cluster.

Kubernetes is best used as part of a continuous delivery workflow. Running automated deployments when new code is merged ensures changes reach your cluster quickly after passing through a consistent pipeline.

What Is ArgoCD?

ArgoCD is a popular tool for setting up continuous delivery with Kubernetes. It automates application deployment into Kubernetes clusters by continually reconciling your repository’s state against your live workloads.

The GitOps model is integral to Argo’s design. It makes the repository the single source of truth for your application’s desired state. All the Kubernetes manifests, Kustomize templates, Helm charts, and config files your app needs should be committed to your repository. These resources “declare” what a successful deployment of your app looks like.

Argo compares the declared state to what’s actually running in your cluster, then applies the correct changes to resolve any discrepancies. This process can be configured to run automatically, preventing your cluster from drifting away from your repository. Argo resynchronizes the state whenever differences occur, such as after you manually run Kubectl commands.

Argo comes with both a CLI and web UI. It supports multi-tenant and multi-cluster environments, integrates with SSO providers, produces an audit trail, and can implement complex rollout strategies such as canary deployments and blue/green upgrades. It also offers integrated rollbacks so you can quickly recover from deployment failures.

Push vs. Pull-based CI/CD

Historically, most CI/CD implementations have relied on push-driven behavior. This requires you to connect your cluster to your CI/CD platform, then use tools like Kubectl and Helm within your pipeline to apply Kubernetes changes.

Argo is a pull-based CI/CD system. It runs inside your Kubernetes cluster and pulls source from your repositories. Argo then applies the changes for you without a manually configured pipeline.

This model is more secure than push-based workflows. You don’t have to expose your cluster’s API server or store Kubernetes credentials in your CI/CD platform. Compromising a source repository only gives an attacker access to your code instead of the code and a route to your live deployments.

Argo CD Concepts

Argo is easy to learn once you understand its basic concepts. Here are some terms to get familiar with.

  • Argo controller – Argo’s Application Controller is the component you install in your cluster. It implements the Kubernetes controller pattern to monitor your applications and compare their state against their repositories.
  • Application – An Argo application is a group of Kubernetes resources which collectively deploy your workload. Argo stores the details of applications in your cluster as instances of an included Custom Resource Definition (CRD).
  • Live state – The live state is the current state of your application inside the cluster, such as the number of Pods created and the image they’re running.
  • Target state – The target state is the version of the state that’s declared by your Git repository. When the repository changes, Argo will apply actions that evolve the live state into the target state.
  • Refresh – A refresh occurs when Argo fetches the target state from your repository. It will compare the changes against the live state but doesn’t necessarily apply them at this stage.
  • Sync – A Sync is the process of applying the changes discovered by a Refresh. Each Sync moves the cluster back towards the target state.

Now we’ve covered the core concepts, we can use Argo to deploy an example app to Kubernetes. You can read more about Argo’s terminology and the  tool’s architecture in the official docs.

Practical Example: Using Argo CD to Deploy to Kubernetes

Let’s use Argo to run a basic NGINX web server instance in Kubernetes. We’ll assume you’ve already got access to a Kubernetes cluster, and you’ve got the  Kubectl and Helm CLIs available on your machine.

Create Your App’s GitHub Repository

First, head to GitHub and create a new repository for your app. Afterward, clone your repo to your machine, ready to commit your Kubernetes manifests:

$ git clone https://github.com/<username>/<repo>.git

Copy the following YAML and save it as deployment.yaml inside your repository:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: argo-demo
  labels:
    app.kubernetes.io/name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
          - name: http
            containerPort: 80

It defines a basic Kubernetes Deployment object that runs three NGINX replicas.

Next, copy this second YAML file and save it to service.yaml. It sets up a LoadBalancer service to expose your Deployment outside your cluster:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: argo-demo
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: http

Finally, add a manifest that will create your application’s namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: argo-demo

Commit your changes to your repository, then push them up to GitHub:

$ git add .
$ git commit -m "Added initial Kubernetes YAML files"
$ git push

You’re ready to install Argo and start deploying your app.

install argo cd

Get the Argo CLI

Argo’s CLI lets you interact with your applications from your terminal. You’ll need it later to register your app with your Argo instance.

You can download the latest CLI release from GitHub. Select the right binary for your platform, then make it executable and move it to a location in your path. The following steps work for most Linux systems – substitute the latest version number instead of 2.6.1 below, first:

$ wget https://github.com/argoproj/argo-cd/releases/download/v2.6.1/argocd-linux-amd64
$ chmod +x argocd-linux-amd64
$ mv argocd-linux-amd64 /usr/bin/argocd

Check you can now run argocd commands:

$ argocd version
argocd: v2.6.1+3f143c9
  BuildDate: 2023-02-08T19:18:18Z
  ...

The CLI’s also distributed in Homebrew’s package list. Use the brew install command to add argocd to your system using this method:

$ brew install argocd

Install Argo In Your Cluster

Next, install Argo in your Kubernetes cluster. This will add the Argo CD API, controller, and Custom Resource Definitions (CRDs).

Begin by creating a namespace for Argo:

$ kubectl create namespace argocd
namespace/argocd created

Next, use Kubectl to apply Argo CD’s YAML manifest to your cluster. You can  inspect the manifest before you use it to see the resources that’ll be created.

$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

It can take several seconds for all of Argo’s components to be running in your cluster. Monitor progress by using Kubectl to list the deployments in the argocd namespace.

You can continue once the deployments are ready:

$ kubectl get deployments -n argocd
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
argocd-applicationset-controller   1/1     1            1           67s
argocd-dex-server                  1/1     1            1           67s
argocd-notifications-controller    1/1     1            1           67s
argocd-redis                       1/1     1            1           67s
argocd-repo-server                 1/1     1            1           67s
argocd-server                      1/1     1            1           67s

Connecting to Argo

Argo CD doesn’t automatically expose its API server on an external IP. You can connect to it by starting a new Kubectl port-forwarding session instead. Open another terminal window and run the following command:

$ kubectl port-forward svc/argocd-server -n argocd 8080:443

This redirects your local port 8080 to port 443 of Argo’s service. Visit localhost:8080 in your browser to access the Argo UI. You’ll be warned that the page is insecure because it uses a self-signed certificate.

You can continue with this setup while you’re experimenting, but you should follow the detailed steps in the Argo docs to configure TLS with an Ingress route before you move to production.

argo cd login

Before you can login, you need to retrieve the password for the default admin user. This is generated automatically during Argo’s installation process. You can access it by running the following argocd command:

$ argocd admin initial-password -n argocd
zHKv74zvDNtVMaOB

Use these credentials to login to Argo.

Once you’re in, head straight to the User Info item in the left sidebar, then click the “Update Password” button at the top of the screen. Follow the prompts to change your password to something unique.

argo cd Update Password

Now you can delete the Kubernetes secret that contains the original password for the admin account:

$ kubectl delete secret argocd-initial-admin-secret -n argocd
secret "argocd-initial-admin-secret" deleted

Login to the CLI

To login to the Argo CLI, run argocd login and supply the API server’s URL as an argument:

$ argocd login localhost:8080

Similarly to the browser warning encountered above, you’ll be prompted to accept Argo’s built-in self-signed certificate if you haven’t configured your own TLS:

WARNING: server certificate had error: x509: certificate signed by unknown authority. Proceed insecurely (y/n)?

Accept the prompt by typing y and pressing return. You’ll then be asked to enter your username and password. The CLI should successfully authenticate to your Argo instance:

'admin:login' logged in successfully
Context 'localhost:8080' updated

Deploying Your App With Argo

Everything’s ready to start deploying apps to Argo! First, run the following CLI command to register your app:

$ argocd app create argo-demo \
  --repo https://github.com/<username>/<repo>.git \
  --path . \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace argo-demo
application 'argo-demo' created

Let’s unpack what’s happening here:

  • The --repo flag specifies the URL of your Git repository.
  • The --path flag instructs Argo to search for Kubernetes manifests, Helm charts, and other deployable assets inside this path within your repo. . is used here because the example manifests are stored in the repo’s root.
  • The --dest-server flag specifies the URL of the Kubernetes cluster to deploy to. You can use kubernetes.default.svc when you’re deploying to the same cluster that Argo’s running in.
  • --dest-namespace sets the Kubernetes namespace that your app will be deployed into. This should match the metadata.namespace fields set on your resources.

Your app will now be registered with Argo. You can retrieve its details with the argocd app list command:

NAME              CLUSTER                         NAMESPACE   PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                   PATH  TARGET
argocd/argo-demo  https://kubernetes.default.svc  argo-demo   default  OutOfSync  Missing  <none>      <none>      https://github.com/ilmiont/spacelift-argo-cd-demo.git

The app also shows up in the Argo UI:

argo cd ui

Your First Sync

The app shows as “missing” and “out of sync.” Creating the app doesn’t automatically sync it into your cluster. Perform a sync now to have Argo apply the target state currently defined by your repo’s content:

$ argocd app sync argo-demo
...
GROUP  KIND        NAMESPACE  NAME       STATUS   HEALTH       HOOK  MESSAGE
       Namespace   argo-demo  argo-demo  Running  Synced             namespace/argo-demo created
       Service     argo-demo  nginx      Synced   Progressing        service/nginx created
apps   Deployment  argo-demo  nginx      Synced   Progressing        deployment.apps/nginx created
       Namespace              argo-demo  Synced                      

The sync results display in your terminal. You should see the Namespace, Service, and Deployment objects all get synced into your cluster, as in the command output above. The messages for all three objects confirm they were created successfully.

Repeat the apps list command to check the app’s new status:

$ argocd app list
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                   PATH  TARGET
argocd/argo-demo  https://kubernetes.default.svc  argo-demo  default  Synced  Healthy  <none>      <none>      https://github.com/ilmiont/spacelift-argo-cd-demo.git  .   

Now the app is Synced and Healthy! It’s also green in the Argo UI:

argo cd synced app

As a final proof, use Kubectl to inspect the deployments in the app’s namespace. This should confirm that nginx is up and running three replicas:

$ kubectl get deployment -n argo-demo
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           7m56s

Syncing App Updates

Now let’s make a change to our app. Modify the spec.replicas field in your deployment.yaml so there’s now five Pods in the Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: argo-demo
  labels:
    app.kubernetes.io/name: nginx
spec:
  replicas: 5
  ...

Commit and push your changes:

$ git add .
$ git commit -m "Run 5 replicas"
$ git push

Next, repeat the argocd app sync command to apply your changes to your cluster.

Alternatively, you can click the “Sync” button within the user interface.

$ argocd app sync argo-demo
GROUP  KIND        NAMESPACE  NAME       STATUS   HEALTH       HOOK  MESSAGE
       Namespace   argo-demo  argo-demo  Running  Synced             namespace/argo-demo unchanged
       Service     argo-demo  nginx      Synced   Healthy            service/nginx unchanged
apps   Deployment  argo-demo  nginx      Synced   Progressing        deployment.apps/nginx configured
       Namespace              argo-demo  Synced

Argo refreshes your app’s target state from the repo, then takes action to transition the live state. The Deployment is reconfigured and now runs five Pods:

$ kubectl get deployment -n argo-demo
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   5/5     5            5           12m

Enabling Auto-Sync

The change to five replicas didn’t apply until you repeated the sync command. Argo can automatically sync changes from your repo though, eliminating the need to issue the command each time. This fully automates your delivery workflow.

You can activate auto-sync for an app by clicking the “App Details” button within the user interface and scrolling down to the “Sync Policy” section. Click the “Enable Auto-Sync” button.

argo cd Enabling Auto-Sync

Auto-sync can also be enabled using the CLI by running the following command:

$ argocd app set argo-demo --sync-policy automated

To test auto-sync out, revert the spec.replicas field back to three replicas:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: argo-demo
  labels:
    app.kubernetes.io/name: nginx
spec:
  replicas: 3
  ...

Commit and push the change:

$ git add .
$ git commit -m "Back to 3 replicas"
$ git push

This time Argo will automatically detect the repository’s state change. You should see your Deployment scale back to 3 replicas within a few minutes of pushing the commit:

$ kubectl get deployment -n argo-demo
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           23m

Auto-sync runs every three minutes by default. You can change this value by modifying Argo’s config map, if you need more frequent deployments.

Managing Your App

Argo’s CLI and web app offer extensive options for managing and monitoring your deployments. While these are outside the scope of this beginner’s tutorial, you can start exploring the CLI commands and UI panels to take control of your app. Most features are implemented in both interfaces.

argo cd Managing Your App

Clicking your app’s tile from the homescreen displays an overview that visualizes its components with their current sync and health states. You can view the app’s details, edit its config, and view events that describe Argo’s activity by clicking the “App Details” button in the top-left.

You can access previous deployments via the “History and Rollback” button. This lists all the syncs that Argo has performed, including an option to restore an older version. If a deployment introduces a bug, you can use this screen to rollback before you push a fix to your repo.

Key Points

Argo CD is a continuous delivery tool for Kubernetes. It provides a pull-based GitOps workflow for automatically synchronizing source repositories with in-cluster deployments. While this article has only covered the basics, Argo gives you a complete toolkit for deploying your apps, inspecting their health, and quickly rolling back any failed changes.

Argo CD is an ideal solution for managing your Kubernetes workloads. It doesn’t handle how you provision and change your cluster infrastructure, though.

Try Spacelift’s CI/CD platform to collaborate on infrastructure using multiple IaC providers, including Kubernetes, Ansible, and Terraform. Spacelift lets you visualize your resources, prevent drift, and help developers ship fast within precise policy-driven guardrails.

The Most Flexible CI/CD Automation Tool

Spacelift is an alternative to using homegrown solutions on top of a generic CI. It helps overcome common state management issues and adds several must-have capabilities for infrastructure management.

Start free trial