[School Of DevOps] Ultimate Argo Bootcamp: Argo Events and Argo Image Updater


Делаю:
2026.01.22


https://kubernetes-tutorial.schoolofdevops.com/argo_events/


Инсталляция Argo Events

Инсталляция Argo Image Updater


Create an Argo Events EventSource

$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
  name: webhook
  namespace: argo-events
spec:
  service:
    ports:
      - port: 12000
        targetPort: 12000
  webhook:
    example:
      port: "12000"
      endpoint: /example
      method: POST

    github:
      port: "12000"
      endpoint: /github
      method: POST
EOF


// workflow template
$ kubectl get pods -n argo-events | grep eventsource
webhook-eventsource-cxtnt-568686b87d-kfmdf   1/1     Running   0          43s


$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: vote-ci-template
  namespace: argo-events
spec:
  entrypoint: main
  serviceAccountName: default
  arguments:
    parameters:
    - name: repo-url
      value: "https://github.com/your-username/your-flask-app.git"
    - name: branch
      value: "main"
    - name: image
      value: "your-registry/your-flask-app"
    - name: dockerfile
      value: "Dockerfile"

  volumeClaimTemplates:
  - metadata:
      name: workspace
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Mi

  volumes:
  - name: docker-config
    secret:
      secretName: docker-registry-creds
      items:
        - key: .dockerconfigjson
          path: config.json

  templates:
  - name: main
    inputs:
      parameters:
      - name: repo-url
      - name: branch
      - name: image
      - name: dockerfile
    steps:
    - - name: clone
        template: clone
        arguments:
          parameters:
          - name: repo-url
            value: ""
          - name: branch
            value: ""
    - - name: build
        template: build
    - - name: test
        template: test
    - - name: imagebuild
        template: imagebuild
        arguments:
          parameters:
          - name: commit-sha
            value: ""
          - name: image
            value: ""
          - name: dockerfile
            value: ""

  # Clone task
  - name: clone
    inputs:
      parameters:
      - name: repo-url
      - name: branch
    script:
      image: alpine/git
      command: [sh]
      source: |
        #!/bin/sh
        git clone --branch   /workspace
        cd /workspace
        COMMIT_SHA=$(git rev-parse --short HEAD)
        echo $COMMIT_SHA > /workspace/commit-sha.txt
      volumeMounts:
      - name: workspace
        mountPath: /workspace
    outputs:
      parameters:
      - name: commit-sha
        valueFrom:
          path: /workspace/commit-sha.txt

  # Build task
  - name: build
    script:
      image: python:3.9
      command: ["sh"]
      source: |
        #!/bin/sh
        cd /workspace
        pip install -r requirements.txt
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  # Test task
  - name: test
    script:
      image: python:3.9
      command: ["sh"]
      source: |
        #!/bin/sh
        cd /workspace
        pip install nose
        nosetests
      volumeMounts:
      - name: workspace
        mountPath: /workspace

  # Image build and publish task using Kaniko
  - name: imagebuild
    inputs:
      parameters:
      - name: commit-sha
      - name: image
      - name: dockerfile
    container:
      image: gcr.io/kaniko-project/executor:latest
      command: ["/kaniko/executor"]
      args:
      - --dockerfile=/workspace/
      - --context=/workspace
      - --destination=:
      - --force
      volumeMounts:
      - name: workspace
        mountPath: /workspace
      - name: docker-config
        mountPath: /kaniko/.docker
      env:
      - name: DOCKER_CONFIG
        value: /kaniko/.docker
EOF


$ kubectl get workflowtemplate -A
NAMESPACE     NAME               AGE
argo-events   vote-ci-template   22s


$ argo template list -A
NAMESPACE     NAME
argo-events   vote-ci-template


$ {
    export REGISTRY_SERVER=https://index.docker.io/v1/
    export REGISTRY_USER=webmakaka
    export REGISTRY_PASSWORD=webmakaka-password

    echo ${REGISTRY_SERVER}
    echo ${REGISTRY_USER}
    echo ${REGISTRY_PASSWORD}
}


$ kubectl create secret -n argo-events docker-registry docker-registry-creds \
    --docker-server=${REGISTRY_SERVER} \
    --docker-username=${REGISTRY_USER} \
    --docker-password=${REGISTRY_PASSWORD}


Add sensor

$ cat << EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
  name: polling-sensor
  namespace: argo-events
spec:
  template:
    serviceAccountName: operate-workflow-sa
  dependencies:
    - name: poll-github
      eventSourceName: webhook
      eventName: github
  triggers:
    - template:
        name: launch-vote-ci
        argoWorkflow:
          operation: submit
          source:
            resource:
              apiVersion: argoproj.io/v1alpha1
              kind: Workflow
              metadata:
                generateName: ci-pipeline-
              spec:
                workflowTemplateRef:
                  name: vote-ci-template
                arguments:
                  parameters:
                  - name: repo-url
                    value: "https://github.com/wildmakaka/vote.git"
                  - name: branch
                    value: "main"
                  - name: image
                    value: "webmakaka/vote"
                  - name: dockerfile
                    value: "Dockerfile"
EOF


// too many open files
// чтобы ушла до перезагрузки
$ sudo sysctl fs.inotify.max_user_instances=8192
$ sudo sysctl fs.inotify.max_user_watches=524288


$ kubectl get pods -n argo-events
NAME                                           READY   STATUS    RESTARTS   AGE
controller-manager-59884fd695-qgnxk            1/1     Running   0          35m
eventbus-default-stan-0                        2/2     Running   0          34m
eventbus-default-stan-1                        2/2     Running   0          34m
eventbus-default-stan-2                        2/2     Running   0          34m
events-webhook-588ccdfcb5-bcpg9                1/1     Running   0          35m
polling-sensor-sensor-mj4bg-64f6f77d58-f9fgk   1/1     Running   0          74s
webhook-eventsource-cxtnt-568686b87d-kfmdf     1/1     Running   0          22m


$ kubectl logs -n argo-events -l "controller=sensor-controller"


Deploy GitHub Poller


$ kubectl create secret generic github-token-secret \
    --from-literal=token=<GITHUB_ACCESS_TOKEN>


// OK!
https://localhost:2746/workflows/argo-events


$ cat << EOF | kubectl apply -f -
apiVersion: batch/v1
kind: CronJob
metadata:
  name: github-polling-job
spec:
  schedule: "* * * * *"  # Poll every minute
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: poller
            image: schoolofdevops/github-poller:latest
            env:
            - name: GITHUB_API_URL
              value: "https://api.github.com/repos/wildmakaka/vote/commits"
            - name: GITHUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: github-token-secret
                  key: token
            - name: LAST_COMMIT_FILE
              value: "/data/last_commit.txt"
            - name: ARGO_EVENT_SOURCE_URL
              value: "http://webhook-eventsource-svc.argo-events.svc.cluster.local:12000/github"
            volumeMounts:
            - name: commit-storage
              mountPath: /data
          restartPolicy: OnFailure
          volumes:
          - name: commit-storage
            persistentVolumeClaim:
              claimName: poller-pvc  # Use a PVC to persist the last commit file
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: poller-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Mi
EOF


$ kubectl get cronjobs
NAME                 SCHEDULE    TIMEZONE   SUSPEND   ACTIVE   LAST SCHEDULE   AGE
github-polling-job   * * * * *   <none>     False     1        5s              80s


$ kubectl -n argo port-forward --address 0.0.0.0 svc/argo-server 2746:2746 > /dev/null


Появился новый image (делал коммит в репо):
https://hub.docker.com/r/webmakaka/vote/tags


Image Updater


https://kubernetes-tutorial.schoolofdevops.com/argo_iamge_updater/


$ kubectl -n argocd create secret generic git-creds \
  --from-literal=username=wildmakaka \
  --from-literal=password=<GITHUB_ACCESS_TOKEN>


$ kubectl get application -n argocd

$ kubectl describe application -n argocd vote-staging


$ cat > ~/tmp/argo_applications_vote-staging_patch.yaml <<'EOF'
metadata:
  annotations:
    argocd-image-updater.argoproj.io/git-branch: main
    argocd-image-updater.argoproj.io/image-list: myimage=webmakaka/vote
    argocd-image-updater.argoproj.io/myimage.allow-tags: regexp:^[0-9a-f]{7}$
    argocd-image-updater.argoproj.io/myimage.ignore-tags: latest, dev
    argocd-image-updater.argoproj.io/myimage.update-strategy: latest
    argocd-image-updater.argoproj.io/myimage.kustomize.image-name: schoolofdevops/vote
    argocd-image-updater.argoproj.io/myimage.force-update: "true"
    argocd-image-updater.argoproj.io/write-back-method: git:secret:argocd/git-creds
    argocd-image-updater.argoproj.io/write-back-target: "kustomization:../base"
EOF


image-list - где искать образ
kustomize.image-name - что менять в манифестах


$ kubectl patch application --type=merge -n argocd vote-staging --patch-file ~/tmp/argo_applications_vote-staging_patch.yaml


$ kubectl get application vote-staging -n argocd -o jsonpath='{.metadata.annotations}' | jq .


// логи
$ kubectl logs -f -l "app.kubernetes.io/name=argocd-image-updater" -n argocd


Обновился tag в репо wildmakaka.
Потом спустя минут 10 обновились images в ns staging
Делаем MR в release
Потом спустя минут 10 обновились images в ns prod