4

I have deployed the application via ArgoCD successfully, and I can access it via its ingress url

The applicaiton uses the image name with latest tag, such as

image: <private_registry>/app_1_service:latest

I also manage other tags on same of tag latest, such as image:<commit_id> or image:<1.0.xxx>

Now, developers will update the codes, after commit changes, a gitlab pipeline autoamtically runs and build a new image and override to tag latest with other tags and push to private docker registry

So what's the next step in ArgoCD?

How argocd know the application is changed, and need be redeployed, and the image:latest need be pull again?

Bill
  • 2,494
  • 5
  • 26
  • 61

3 Answers3

8

You can use ArgoCD image-updater

But before using the the image-updater, you need to install and set appropriate permission

helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd-image-updater argo/argocd-image-updater

Once image-updator is up and running, then you need to set a few annotations in the Argocd application, as the update workers on different strategies

semver - Update to the latest version of an image considering semantic versioning constraints latest - Update to the most recently built image found in a registry
digest - Update to the latest version of a given version (tag), using the tag's SHA digest
name - Sorts tags alphabetically and update to the one with the highest cardinality

latest strategies working awesome with tagging under some regex and digest more suited for testing environment.

update-strategies

You can also pull the private image from gitlab as well.

Here is the working example with helm-release

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-alias.allow-tags: 'regexp:^1.3.0-SNAPSHOT.[0-9]+$'
    argocd-image-updater.argoproj.io/image-alias.force-update: 'true'
    argocd-image-updater.argoproj.io/image-alias.pull-secret: 'pullsecret:develop-namespace/develop-app-gitlab-secrets'
    argocd-image-updater.argoproj.io/image-alias.update-strategy: latest
    argocd-image-updater.argoproj.io/image-list: >-
      image-alias=registry.gitlab.com/myorg/my-test-image
  finalizers:
    - resources-finalizer.argocd.argoproj.io
  labels:
    app.kubernetes.io/instance: develop-platform
  name: develop-app
  namespace: argocd
spec:
  destination:
    namespace: develop-app
    server: 'https://kubernetes.default.svc'
  project: develop-app-west6-b
  source:
    helm:
      releaseName: develop-app
      valueFiles:
        - develop-platform/values.yaml
    path: helm-chart/helm-chart
    repoURL: 'https://gitlab.com/my-org/develop-app.git'
    targetRevision: staging
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

If you need digest or just a latest then remove this

  argocd-image-updater.argoproj.io/image-alias.allow-tags: 'regexp:^1.3.0-SNAPSHOT.[0-9]+$'

this is working base on regex. so in your case <1.0.xxx>

it can be 'regexp:^1.0.[0-9]+$'

If everything configured properly and image updater working fine then you should be able to see logs image updater logs like this

time="2022-04-27T15:18:36Z" level=info msg="Successfully updated image 'registry.gitlab.com/test-image:0.3.0-SNAPSHOT.115' to 'registry.gitlab.com/test-image:0.3.0-SNAPSHOT.118'

Adiii
  • 54,482
  • 7
  • 145
  • 148
  • 1
    image update and app sync are two different thing, you need image update,r not the sync which mentioned in the other comment. sync will sync the helm-chart manifest not the image. – Adiii Sep 06 '22 at 07:27
3

If you are using latest tag, the most simple way is this

  • set your k8s yaml imagePullPolicy to Always
  • add below step in gitlab-ci.yml to restart application by calling argocd api
argocd-restart:
    image: argoproj/argocd
    stage: deploy
    variables:
      GIT_STRATEGY: none
      ARGOCD_SERVER: "192.111.111.111:30000"
      # gitlab admin panel variable
      # ARGOCD_USERNAME: "admin"
      # ARGOCD_PASSWORD: "XXXXXX"
    before_script:
      - echo "ARGOCD_SERVER:$ARGOCD_SERVER"
      - echo "ARGOCD_APP_NAME:$ARGOCD_APP_NAME"
      - echo "ARGOCD_USERNAME:$ARGOCD_USERNAME"
    script:
      - argocd login "${ARGOCD_SERVER}" --insecure --username "${ARGOCD_USERNAME}" --password "${ARGOCD_PASSWORD}"
      - argocd app actions run "$ARGOCD_APP_NAME" restart --kind Deployment |& tee response.txt
      - cat response.txt
      # if response.txt have content, exit with error, empty response means success
      - if [ -s response.txt ]; then exit 1; fi
    only:
      - master
      - dev

argocd cli doc: https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_actions_run/

Above solution is not suit for production, because

  • imagePullPolicy: Always means k8s always need to connect registry
  • download image everytime when restart is waste of resource
  • don't have version control

so for stg and prod, i do this. Create a helm value file only for image tag such as stg-image-tag.yaml.

image:
  tag: "stg-v0.0.1"

Add this file to argocd app config enter image description here

Modify gitlab-ci.yml, build image with new image tag, and commit the image tag to stg-image-tag.yaml

  • i use $CI_PIPELINE_IID as version number in image tag.
  • i have branch name for each env
docker-build:
  image: docker
  stage: build
  variables:
    # REGISTRY_SERVER: 192.168.111.111
    # REGISTRY_USER: xxx
    # REGISTRY_PASSWORD: xxx
  before_script:
    - IMAGE_TAG="$CI_COMMIT_REF_SLUG-v0.0.$CI_PIPELINE_IID"
  script:
    - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_SERVER
    - docker build .
      -t "$NEW_IMAGE_REPO:latest"
      -t "$NEW_IMAGE_REPO:$IMAGE_TAG"
    - docker push "$NEW_IMAGE_REPO" --all-tags
    - echo IMAGE_TAG=$IMAGE_TAG >> IMAGE_TAG.env
    - cat IMAGE_TAG.env
  artifacts:
    reports:
      # add IMAGE_TAG to other jobs as env var
      dotenv: IMAGE_TAG.env
    expire_in: "86400" # 1 day

commit-image-tag:
  image: curlimages/curl
  stage: deploy
  needs:
    - job: docker-build
      artifacts: true
  variables:
    GIT_STRATEGY: none
    GITLAB_PROJECT_ID: "111"
    GITLAB_PROJECT_TOKEN: "xxxxxxxxxxx"
  before_script:
    - echo "IMAGE_TAG:$IMAGE_TAG"
  script:
    - |
      cat <<EOF > body.txt
      {
        "branch":"master",
        "commit_message":"update image tag ${IMAGE_TAG}",
        "actions":[
          {
            "action":"update",
            "file_path":"helm-charts/${CI_COMMIT_REF_SLUG}-image-tag.yaml",
            "content":"image:\n  tag: $IMAGE_TAG"
          }
        ]
      }
      EOF
    - |
      cat <<EOF > header.txt
      Authorization: Bearer ${GITLAB_PROJECT_TOKEN}
      Content-Type: application/json
      EOF
    - curl --insecure "${CI_SERVER_URL}/api/v4/projects/${GITLAB_PROJECT_ID}/repository/commits" 
      -i --output response.txt
      --header @header.txt --data @body.txt
      --silent --write-out "%{response_code}" > response_code.txt
    - cat response.txt
    # error if response code is not 201
    - if [ "$(cat response_code.txt)" != "201" ]; then exit 1; fi
  only:
    - stg
    - prod

Then you setup a webhook so argocd will refresh image tag immediately. otherwise argocd will refresh every 3 min. enter image description here

yip102011
  • 751
  • 4
  • 11
  • that's cood, so if I want to do rolling update `kubectl rollout restart`, can I run with `argocd app` as well? any command for me to reference? and it supports to update image with `latest`? – Bill Sep 06 '22 at 06:36
  • 1
    basically this command `argocd app actions run "$ARGOCD_APP_NAME" restart --kind Deployment` is running `kubectl rollout restart deployment xxx`. if you set `imagePullPolicy` to `Always`, k8s will download image from registry every time. it dosen't have to be `latest`, could be any tag. – yip102011 Sep 06 '22 at 06:40
  • one more question. This is suitable if the application has been deployed by argocd, right? If I run the first time, it is failed. Any suggestion? – Bill Sep 06 '22 at 07:07
  • 1
    yes, you need to manually add app to argocd first. – yip102011 Sep 06 '22 at 07:11
  • thanks for the codes. Regarding the build stage, take a look about [kaniko](https://github.com/GoogleContainerTools/kaniko), it does "docker login, build, tags, and push" together with one command. simplify a lot for your pipeline – Bill Sep 06 '22 at 07:56
  • thanks for your suggestion, but looks like it will take a lot of effort to handle cache combine with gitlab runner. No, thank you. Currently i just use docker daemon in my gitlab server. Simple and easy. – yip102011 Sep 06 '22 at 08:18
  • well, actually the most important part of using argocd is pull mechanism. So if somehow if I need to reach CD server that should not be the best practice. If I can reach ArgoCD then I can run my terraform infrastructure scripts as well. – Fırat Küçük Oct 19 '22 at 17:53
2

ArgoCD supports 2 types of application syncing policies:

  1. manual: a user will login into the dashboard and update the image/chart version
  2. automatic: ArgoCD will poll the container registry at fixed interval (e.g 3 min) and check if a new image's/chart's version is available based on a pattern. You can use regex to specify the image pattern. Argo will compare the current version with the new one.

Auto sync option in ArgoCD dashboard

Here's an example of deploying helm from Jfrog artifact registry automatically:

project: default
source:
  repoURL: 'https://abc.jfrog.io/artifactory/helm'
  targetRevision: '*.*.*' # set your regex pattern here
  helm:
    parameters:
      - name: image.tag
        env: dev
  chart: frontend-chart
destination:
  server: 'https://kubernetes.default.svc'
  namespace: default
syncPolicy:
  automated: {} # enables auto syncing
Taimoor Mirza
  • 1,093
  • 7
  • 19
  • regarding `ArgoCD will poll the container registry at fixed interval (e.g 3 min) and check if a new image's/chart's version is available based on a pattern`, will it apply to tag `latest` as well? if it found the SHA is changed and do the update automatically? – Bill Sep 06 '22 at 06:34
  • 1
    In my example it won't work since Jfrog (at least the way i use it) stores the name and version of the artifact (chart, image) only so ArgoCD will only detect change if the version or name is changed. If you set your Git repo as source instead of some 3rd party registry, then I believe the SHA based change will be detected. Check the last section of this [official doc](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/#:~:text=Argo%20CD%20has%20the%20ability,server%20to%20perform%20the%20deployment.) – Taimoor Mirza Sep 06 '22 at 06:44
  • ArgoCD will only detect new *chart-versions* though. If the chart stays the same and only the image is updated (e.g. a new "latest" version is uploaded to the image registry), ArgoCD will not update the deployment – asturm Jun 01 '23 at 11:31