Skip to content

ixxeL-DevOps/demo-web-py

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

demo-web-py

This application is using a specific workflow in combination with ArgoCD and github action.

Workflow

The artefact creation workflow:

  • Create artefact on PR with tags sha-<sha1> and pr-<pr-number>
  • Create new artefact on PR commit sha-<sha2> and update pr-<pr-number> to the new commit
  • Promote artefact pr-<pr-number> on merge PR

PR number can be identified from a commit on Github API with following command:

gh pr list --search <sha> --state merged --json url --jq '.[0].url'

ArgoCD notifies Github for successful deployment:

To notify Github for a deployment status for a specific commit use this command:

gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/ixxeL-DevOps/demo-web-py/statuses/<sha> -f state='success' -f description='Ephemeral env deployment' -f
context='continuous-integration/argocd'

Curl version:

curl -L -X POST -H "Accept: application/vnd.github+json" H "Authorization: Bearer <YOUR-TOKEN>" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/ixxeL-DevOps/demo-web-py/statuses/<sha> -d '{"state":"success","description":"Ephemeral env deployment","context":"continuous-integration/argocd"}'

and check it:

gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/ixxeL-DevOps/demo-web-py/commits/<sha>/statuses

Curl version:

curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer <YOUR-TOKEN>" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/ixxeL-DevOps/demo-web-py/commits/<sha>/statuses

Documentation:

ArgoCD deployment config

Documentation :

Here is the description of the ArgoCD ApplicationSet responsible for app creation (works with umbrella chart in this example):

---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: demo-web-preview
spec:
  generators:
    - pullRequest:
        github:
          owner: ixxeL-DevOps
          repo: demo-web-py
          tokenRef:
            key: github_token
            secretName: github-creds
        requeueAfterSeconds: 60
  template:
    metadata:
      name: 'demo-web-pr-{{number}}'
      annotations:
        notifications.argoproj.io/subscribe.on-ephemeral-deployed.github: ""
        notifications.argoproj.io/subscribe.on-ephemeral-health-degraded.github: ""
        notifications.argoproj.io/subscribe.on-ephemeral-sync-failed.github: ""
    spec:
      destination:
        namespace: 'demo-web-pr-{{number}}'
        name: 'vk-pprod'
      project: ephemeral
      source:
        path: deploy/
        repoURL: 'https://github.com/ixxeL-DevOps/demo-web-py.git'
        targetRevision: '{{branch}}'
        helm:
          releaseName: 'demo-web-pr-{{number}}'
          parameters:
            - name: demo-web.tag
              value: 'sha-{{head_sha}}'
            - name: demo-web.name
              value: 'demo-web-pr-{{number}}'
            - name: demo-web.pr.enabled
              value: 'true'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - Validate=true
          - PruneLast=false
          - RespectIgnoreDifferences=true
          - Replace=false
          - ApplyOutOfSyncOnly=true
          - CreateNamespace=true
          - ServerSideApply=true
        retry:
          limit: 2 # number of failed sync attempt retries; unlimited number of attempts if less than 0
          backoff:
            duration: 5s # the amount to back off. Default unit is seconds, but could also be a duration (e.g. "2m", "1h")
            factor: 2 # a factor to multiply the base duration after each failed retry
            maxDuration: 3m # the maximum amount of time allowed for the backoff strategy
        managedNamespaceMetadata:
          labels:
            argocd.argoproj.io/instance: 'demo-web-pr-{{number}}'
          annotations:
            argocd.argoproj.io/tracking-id: >-
              demo-web-pr-{{number}}:/Namespace:demo-web-pr-{{number}}/demo-web-pr-{{number}}
      info:
      - name: url
        value: 'https://demo-web-pr-{{number}}.k8s-app.fredcorp.com/'

Notice the section managedNamespaceMetadata which is very useful to enable automatic namespace deletion after PR close/merge:

managedNamespaceMetadata:
  labels:
    argocd.argoproj.io/instance: 'demo-web-pr-{{number}}'
  annotations:
    argocd.argoproj.io/tracking-id: >-
      demo-web-pr-{{number}}:/Namespace:demo-web-pr-{{number}}/demo-web-pr-{{number}}

If you do not use this section, you need to inject the Namespace resource inside the helm chart:

{{- if .Values.pr.enabled}}
apiVersion: v1
kind: Namespace
metadata:
  name: {{ .Values.name }}
{{- end }}

Notice the annotation for webhook callback to Github:

annotations:
  notifications.argoproj.io/subscribe.on-ephemeral-deployed.github: ""
  notifications.argoproj.io/subscribe.on-ephemeral-health-degraded.github: ""
  notifications.argoproj.io/subscribe.on-ephemeral-sync-failed.github: ""

And here is the configuration for ArgoCD:

secret:
  name: repo-creds-github # uses this secret to fetch the 'password' key in it (which has access to api Github for notifications)

notifiers:
  service.webhook.github: |
    url: https://api.github.com
    headers:
    - name: Authorization
      value: token $password

triggers:
  trigger.on-ephemeral-deployed: |
    - description: Application is synced and healthy. Triggered once per commit.
      oncePer: app.status.operationState.syncResult.revision
      send:
      - github-commit-status
      when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy' and app.status.sync.status == 'Synced'
  trigger.on-ephemeral-health-degraded: |
    - description: Application has degraded
      oncePer: app.status.operationState.syncResult.revision
      send:
      - github-commit-status
      when: app.status.health.status == 'Degraded'
  trigger.on-ephemeral-sync-failed: |
    - description: Application syncing has failed
      oncePer: app.status.operationState.syncResult.revision
      send:
      - github-commit-status
      when: app.status.operationState.phase in ['Error', 'Failed']

templates:
  template.github-commit-status: |
    webhook:
      github:
        method: POST
        path: /repos/{{call .repo.FullNameByRepoURL .app.spec.source.repoURL}}/statuses/{{.app.status.operationState.operation.sync.revision}}
        body: |
          {
            {{if eq .app.status.operationState.phase "Running"}} "state": "pending"{{end}}
            {{if eq .app.status.operationState.phase "Succeeded"}} "state": "success"{{end}}
            {{if eq .app.status.operationState.phase "Error"}} "state": "error"{{end}}
            {{if eq .app.status.operationState.phase "Failed"}} "state": "error"{{end}},
            "description": "{{.app.metadata.name}} img tag: {{.app.status.operationState.operation.sync.revision}}",
            "target_url": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
            "context": "continuous-integration/argocd"
          }

ApplicationSet points to the repository where the code lives. You can use an umbrella chart to automatically pull the latest version of the deployment in the deploy directory:

apiVersion: v2
name: demo-web
version: 1.0.0
dependencies:
- name: demo-web
  version: '*'
  repository: https://chartmuseum.k8s-app.fredcorp.com

see the helm version constraints documentation:

This setup allows for {{.app.status.operationState.operation.sync.revision}} usage when setting targetRevision: '{{branch}}' for the ApplicationSet.

If you prefer not to, you can use specific {{ (call .repo.GetAppDetails).Helm.GetParameterValueByName "tag" }} call function to target a Helm parameter from your release.

Argocd display application information:

argocd app get argocd/demo-web-pr-5 --grpc-web --show-params --show-operation

result:

Name:               argocd/demo-web-pr-5
Project:            ephemeral
Server:             vk-pprod
Namespace:          demo-web-pr-5
URL:                https://argocd.k8s-app.fredcorp.com/applications/demo-web-pr-5
Repo:               https://github.com/ixxeL-DevOps/demo-web-py.git
Target:             feat/ephemeral4
Path:               deploy/
SyncWindow:         Sync Allowed
Sync Policy:        Automated (Prune)
Sync Status:        Synced to feat/ephemeral4 (d751238)
Health Status:      Healthy

Operation:          Sync
Sync Revision:      d751238e003a92968e2276456f2e0e3ac2ba7216
Phase:              Succeeded
Start:              2024-03-24 17:02:22 +0100 CET
Finished:           2024-03-24 17:02:25 +0100 CET
Duration:           3s
Message:            successfully synced (all tasks run)


NAME  VALUE
tag   sha-d751238e003a92968e2276456f2e0e3ac2ba7216
name  demo-web-pr-5

GROUP              KIND        NAMESPACE      NAME           STATUS   HEALTH   HOOK  MESSAGE
                   Namespace                  demo-web-pr-5  Running  Synced         namespace/demo-web-pr-5 serverside-applied
                   Service     demo-web-pr-5  demo-web-pr-5  Synced   Healthy        service/demo-web-pr-5 serverside-applied
apps               Deployment  demo-web-pr-5  demo-web-pr-5  Synced   Healthy        deployment.apps/demo-web-pr-5 serverside-applied
networking.k8s.io  Ingress     demo-web-pr-5  demo-web-pr-5  Synced   Healthy        ingress.networking.k8s.io/demo-web-pr-5 serverside-applied

The line :

"description": "{{.app.metadata.name}} img tag: {{ (call .repo.GetAppDetails).Helm.GetParameterValueByName "tag" }}",

Reference :

NAME  VALUE
tag   sha-d751238e003a92968e2276456f2e0e3ac2ba7216

You can also gather the commit sha within helm parameter and adapt it:

templates:
  template.github-commit-status: |
    webhook:
      github:
        method: POST
        {{ $sha := (split "-" ((call .repo.GetAppDetails).Helm.GetParameterValueByName "tag"))._1 }}
        path: /repos/{{call .repo.FullNameByRepoURL .app.spec.source.repoURL}}/statuses/{{ $sha }}
        body: |
          {
            {{if eq .app.status.operationState.phase "Running"}} "state": "pending"{{end}}
            {{if eq .app.status.operationState.phase "Succeeded"}} "state": "success"{{end}}
            {{if eq .app.status.operationState.phase "Error"}} "state": "error"{{end}}
            {{if eq .app.status.operationState.phase "Failed"}} "state": "error"{{end}},
            "description": "{{.app.metadata.name}} img tag: {{ (call .repo.GetAppDetails).Helm.GetParameterValueByName "tag" }}",
            "target_url": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",
            "context": "continuous-integration/argocd"
          }

Testing

You can test application with a postsync hook. Add this job to the helm chart:

---
apiVersion: batch/v1
kind: Job
metadata:
  generateName: e2e-tests-
  annotations:
    argocd.argoproj.io/hook: PostSync
spec:
  template:
    spec:
      containers:
      - name: e2e-tests
        image: alpine
        command:
          - "/bin/bash"
          - "-c"
          - |
            apk add curl bash
            response_code=$(curl -fsSkLw "%{http_code}" "http://{{ .Values.name }}.{{ .Release.Namespace}}.svc.cluster.local:8080" -o /dev/null)
            echo "Response code is $response_code"
            if [ $response_code -eq 200 ]; then
              echo "SUCCESS : response code is $response_code"
              exit 0
            else
              echo "FAIL : response code is $response_code"
              exit 1
            fi
      restartPolicy: Never
  backoffLimit: 0

Job will be launched after app is sync.

Trigger

Github action let you triggers workflow manually. It can be coupled with ArgoCD notification.

Documentation:

curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer <YOUR-TOKEN>" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/dispatches -d '{"ref":"topic-branch","inputs":{"name":"Mona the Octocat","home":"San Francisco, CA"}}'

About

Demo application for testing CI and deployment workflows

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •