리소스 동작

리소스 동작 (Resource Actions)

Argo CD는 운영자가 특정 리소스 유형에 대해 사용자가 수행할 수 있는 커스텀 동작을 정의할 수 있게 해줘요. 이 기능은 내부적으로 DaemonSet에 대한 restart, Argo Rollout에 대한 retry 같은 동작을 제공하는 데 사용돼요. 운영자는 Lua 스크립트 형태로 커스텀 리소스에 동작을 추가하고 그 기능을 확장할 수 있답니다.

출처: 문서

본문

개요 (Overview)

Argo CD는 운영자가 특정 리소스 유형에 대해 사용자가 수행할 수 있는 커스텀 동작을 정의할 수 있게 해줘요. 이것은 내부적으로 DaemonSet에 대한 restart, Argo Rollout에 대한 retry 같은 동작을 제공하는 데 사용돼요.

운영자는 Lua 스크립트 형태로 커스텀 리소스에 동작을 추가하고 그 기능을 확장할 수 있어요.

내장 동작 (Built-in Actions)

다음은 Argo CD에 내장된 동작들이에요. 각 동작 이름은 그 Lua 스크립트 정의에 연결돼요:

이 동작들에 대한 접근을 제어하는 방법은 RBAC 문서를 참고하세요.

커스텀 리소스 동작 (Custom Resource Actions)

Argo CD는 Lua로 작성된 커스텀 리소스 동작을 지원해요. 다음의 경우에 유용해요:

  • Argo CD가 내장 동작을 제공하지 않는 커스텀 리소스가 있는 경우
  • 사용자가 kubectl로 실행하면 오류가 발생하기 쉬운, 흔히 수행하는 수동 작업이 있는 경우

리소스 동작은 단일 객체에 대해 작동해요.

argocd-cm ConfigMap에서 자신만의 커스텀 리소스 동작을 정의할 수 있어요.

커스텀 리소스 동작 유형 (Custom Resource Action Types)

소스 리소스를 수정하는 동작 (An action that modifies the source resource)

이 동작은 소스 리소스를 수정하고 반환해요. 이런 종류의 동작은 2.8까지 유일한 방식이었고, 여전히 지원돼요.

새 리소스 또는 수정된 리소스 목록을 생성하는 동작 (An action that produces a list of new or modified resources)

2.8에서 도입된 알파 기능.

이 동작은 영향받는 리소스 목록을 반환하며, 각 영향받는 리소스에는 K8S 리소스와 수행할 작업(operation)이 있어요. 현재 지원되는 작업은 "create"와 "patch"이며, "patch"는 소스 리소스에만 지원돼요. 반환 목록의 각 리소스에 "create" 작업을 지정해 새 리소스를 만드는 것이 가능해요. 반환된 리소스 중 하나는 필요하다면 "patch" 작업이 있는 수정된 소스 객체일 수 있어요. 아래 정의 예시를 참고하세요.

argocd-cm ConfigMap에서 커스텀 리소스 동작 정의 (Define a Custom Resource Action in argocd-cm ConfigMap)

커스텀 리소스 동작은 argocd-cmresource.customizations.actions.<group_kind> 필드에 정의할 수 있어요. 다음 예시는 CronJob 리소스에 대한 커스텀 동작 집합을 보여주며, 각 동작은 수정된 CronJob을 반환해요. 커스터마이즈 키는 resource.customizations.actions.<apiGroup_Kind> 형식이에요.

resource.customizations.actions.batch_CronJob: |
  discovery.lua: |
    actions = {}
    actions["suspend"] = {["disabled"] = true}
    actions["resume"] = {["disabled"] = true}

    local suspend = false
    if obj.spec.suspend ~= nil then
        suspend = obj.spec.suspend
    end
    if suspend then
        actions["resume"]["disabled"] = false
    else
        actions["suspend"]["disabled"] = false
    end
    return actions
  definitions:
  - name: suspend
    action.lua: |
      obj.spec.suspend = true
      return obj
  - name: resume
    action.lua: |
      if obj.spec.suspend ~= nil and obj.spec.suspend then
          obj.spec.suspend = false
      end
      return obj

discovery.lua 스크립트는 키 이름이 동작 이름을 나타내는 테이블을 반환해야 해요. 현재 객체 상태를 기반으로 특정 동작을 활성화하거나 비활성화하는 로직을 선택적으로 포함할 수 있어요.

각 동작 이름은 리소스 수정을 제어하는 action.lua 스크립트와 함께 definitions 목록에 나타나야 해요. obj는 리소스를 포함하는 전역 변수예요. 각 동작 스크립트는 선택적으로 수정된 리소스 버전을 반환해요. 이 예시에서는 단순히 .spec.suspendtrue 또는 false로 설정하고 있어요.

기본적으로 리소스 동작 커스터마이즈를 정의하면 이 리소스 종류에 대한 내장 동작을 덮어써요. Argo CD 버전 2.13.0부터 내장 동작을 유지하려면 mergeBuiltinActions 키를 true로 설정할 수 있어요. 커스텀 동작이 내장 동작보다 우선해요.

resource.customizations.actions.argoproj.io_Rollout: |
  mergeBuiltinActions: true
  discovery.lua: |
    actions = {}
    actions["do-things"] = {}
    return actions
  definitions:
  - name: do-things
    action.lua: |
      return obj        

커스텀 동작으로 새 리소스 만들기 (Creating new resources with a custom action)

[!IMPORTANT] Argo CD UI를 통해 리소스를 만드는 것은 GitOps 원칙에서 의도적이고 전략적인 이탈이에요. 이 기능을 드물게, 그리고 애플리케이션의 원하는 상태에 속하지 않는 리소스에만 사용할 것을 권장해요.

동작이 호출되는 리소스를 source resource(소스 리소스)라고 해요. 새 리소스와 그 결과로 암시적으로 생성된 모든 리소스는 AppProject 수준에서 허용되어야 하며, 그렇지 않으면 생성이 실패할 거예요.

커스텀 동작으로 소스 리소스의 자식 리소스 만들기 (Creating a source resource child resources with a custom action)

새 리소스가 소스 리소스의 k8s 자식이라면, 소스 리소스의 ownerReference가 새 리소스에 설정되어야 해요. 다음은 소스 CronJob 리소스의 자식인 Job 리소스를 구성하는 Lua 스니펫 예시예요. obj는 소스 리소스를 포함하는 전역 변수예요:

-- ...
ownerRef = {}
ownerRef.apiVersion = obj.apiVersion
ownerRef.kind = obj.kind
ownerRef.name = obj.metadata.name
ownerRef.uid = obj.metadata.uid
job = {}
job.metadata = {}
job.metadata.ownerReferences = {}
job.metadata.ownerReferences[1] = ownerRef
-- ...
커스텀 동작으로 독립적인 자식 리소스 만들기 (Creating independent child resources with a custom action)

새 리소스가 소스 리소스와 독립적이라면, 기본적으로 새 리소스는 소스 리소스의 App에 알려지지 않아요 (원하는 상태의 일부가 아니고 ownerReference도 없으니까요). App이 새 리소스를 인식하게 하려면 app.kubernetes.io/instance 라벨(또는 구성된 다른 ArgoCD 추적 라벨)이 리소스에 설정되어야 해요. 소스 리소스에서 다음과 같이 복사할 수 있어요:

-- ...
newObj = {}
newObj.metadata = {}
newObj.metadata.labels = {}
newObj.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"]
-- ...

추적 라벨이 있으면 새 리소스는 App의 일부가 되지만, App에 auto prune이 설정되어 있으면 즉시 삭제돼요. 리소스를 유지하려면 다음 Lua 스니펫으로 리소스에 Prune=false 어노테이션을 설정하세요:

-- ...
newObj.metadata.annotations = {}
newObj.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false"
-- ...

(Prune=false 동작을 설정하면 리소스는 App이 삭제될 때 삭제되지 않으며 수동 정리가 필요해요.)

이제 리소스와 App은 out of sync로 나타날 거예요 — 이것은 원하는 상태의 일부가 아닌 리소스를 만들 때의 예상되는 ArgoCD 동작이에요.

그런 App을 synced로 취급하고 싶다면 Lua 코드에 다음 리소스 어노테이션을 추가하세요:

-- ...
newObj.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous"
-- ...

리소스 목록을 생성하는 동작 - 완전한 예시: (An action that produces a list of resources - a complete example:)

resource.customizations.actions.ConfigMap: |
  discovery.lua: |
    actions = {}
    actions["do-things"] = {}
    return actions
  definitions:
  - name: do-things
    action.lua: |
      -- Create a new ConfigMap
      cm1 = {}
      cm1.apiVersion = "v1"
      cm1.kind = "ConfigMap"
      cm1.metadata = {}
      cm1.metadata.name = "cm1"
      cm1.metadata.namespace = obj.metadata.namespace
      cm1.metadata.labels = {}
      -- Copy ArgoCD tracking label so that the resource is recognized by the App
      cm1.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"]
      cm1.metadata.annotations = {}
      -- For Apps with auto-prune, set the prune false on the resource, so it does not get deleted
      cm1.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false"     
      -- Keep the App synced even though it has a resource that is not in Git
      cm1.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous"         
      cm1.data = {}
      cm1.data.myKey1 = "myValue1"
      impactedResource1 = {}
      impactedResource1.operation = "create"
      impactedResource1.resource = cm1

      -- Patch the original cm
      obj.metadata.labels["aKey"] = "aValue"
      impactedResource2 = {}
      impactedResource2.operation = "patch"
      impactedResource2.resource = obj

      result = {}
      result[1] = impactedResource1
      result[2] = impactedResource2
      return result       

동작 아이콘과 표시 이름 (Action Icons and Display Names)

기본적으로 동작은 actions 키에 지정된 이름으로 UI에 나타나며 아이콘은 없어요. iconClassdisplayName 키를 동작 정의에 추가해 동작의 표시 이름과 아이콘을 커스터마이즈할 수 있어요.

아이콘 클래스 이름은 무료 아이콘 세트에서 가져온 FontAwesome 아이콘 이름이에요. fa-fw 클래스는 다른 아이콘과 정렬 문제가 생기지 않도록 아이콘이 고정 폭으로 표시되게 해줘요.

local actions = {}
actions["create-workflow"] = {
  ["iconClass"] = "fa fa-fw fa-plus",
  ["displayName"] = "Create Workflow"
}
return actions

동작 파라미터 (Action Parameters)

커스텀 동작에 대한 파라미터를 정의할 수 있어요. 파라미터는 동작 discovery 정의의 parameters 키에 정의돼요.

임베딩이 동작하지 않는 GitHub에서 문서를 읽는 사람을 위해 스크립트로 직접 연결하세요.

Deployment 동작 discovery 스크립트를 참고하세요:

ReadTheDocs가 항상 최신 예시를 갖도록 실제 스크립트를 임베드하세요.

local actions = {}

actions["restart"] = {
    ["iconClass"] = "fa fa-fw fa-redo"
}

local paused = false
if obj.spec.paused ~= nil then
    paused = obj.spec.paused
end

actions["pause"] = {
    ["disabled"] = paused,
    ["iconClass"] = "fa fa-fw fa-pause-circle"
}

actions["resume"] = {
    ["disabled"] = not(paused),
    ["iconClass"] = "fa fa-fw fa-play-circle"
}

actions["scale"] = {
    ["iconClass"] = "fa fa-fw fa-plus-circle",
    ["params"] = {
        {
            ["name"] = "replicas"
        }
    },
}

return actions

리소스 스케일 동작 문서는 이 함수가 UI에서 어떻게 동작하는지 보여줘요.

커스텀 리소스 동작 기여 (Contributing a Custom Resource Action)

리소스 동작은 Argo CD에 번들로 포함될 수 있어요. 커스텀 리소스 동작 스크립트는 https://github.com/argoproj/argo-cdresource_customizations 디렉터리에 위치해요. 기여된 각 커스텀 동작은 discovery용 Lua 스크립트와 실제 동작 로직용 Lua 스크립트가 필요해요. 또한 동작 수행 결과를 나타내는 testdata와 예상 K8s 리소스 매니페스트도 필요해요.

다음 디렉터리 구조를 따라야 해요:

argo-cd
|-- resource_customizations
|    |-- your.crd.group.io                         # CRD group
|    |    |-- MyKind                               # Resource kind
|    |    |    |-- actions                         # Actions folder
|    |    |    |    |-- action_test.yaml           # Test inputs and expected results
|    |    |    |    |-- testdata                   # Folder with sample K8s manifest yaml files, for testing the outcome of performing the custom actions 
|    |    |    |    |-- discovery.lua              # Conditions upon which the custom action would be visible in the UI
|    |    |    |    |-- <action_name>              # Folder for each custom action, named as the custom action
|    |    |    |    |    |-- action.lua            # Custom action logic Lua script 

커스텀 동작에 대해 discovery 테스트와 action 테스트를 모두 제공하는 것이 필요해요.

AnalysisRun에 대해 terminate라고 불리는 완전한 커스텀 동작의 예시예요.

discoveryTestsactionTests가 있는 action_test.yaml 파일 내용의 예시:

discoveryTests:
- inputPath: testdata/runningAnalysisRun.yaml
  result:
  - name: terminate
    disabled: false
- inputPath: testdata/failedAnalysisRun.yaml
  result:
  - name: terminate
    disabled: true
actionTests:
- action: terminate
  inputPath: testdata/runningAnalysisRun.yaml
  expectedOutputPath: testdata/runningAnalysisRun_terminated.yaml

더 알아보기 (Learn more)