영기
article thumbnail

코드 분석을 통한 ServiceAccount 로직 이해

  • 쿠버네티스에서 네임스페이스를 생성하면 자동으로 default 라는 이름의 서비스 어카운트가 생성됨.
  • 이 작업은 쿠버네티스 내부의 ServiceAccountsController에 의해 처리됨.

 



ServiceAccountsController 작동 방식

1. ServiceAccountsController는 kube-controller-manager의 일부로 실행됩니다.
2. ServiceAccountsController는 모든 네임스페이스에 default 서비스 어카운트가 존재하는지 확인하고, 없을 경우 자동으로 생성합니다.
3. 코드 내에서 DefaultServiceAccountsControllerOptions() 함수는 기본적으로 생성해야 할 서비스 어카운트 목록(기본적으로 default 서비스 어카운트)을 정의합니다.

 

ServiceAccount - Create 코드 부분

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직


    15-4. [실제 생성 작업] - Kubernetes API 호출
          실행순서: syncHandler() → syncNamespace() → Create()
          파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
          코드: `if _, err := c.client.CoreV1().ServiceAccounts(ns.Name).Create(ctx, &sa, metav1.CreateOptions{}); ...`  
          설명: Kubernetes API 서버에 요청하여 "default" 서비스어카운트 실제 생성

 

 

 

 

코드 호출 흐름

 

진입점: kube-controller-manager 시작

main()

##  파일위치 : cmd/kube-controller-manager/controller-manager.go
##  함수    : main()

main() → NewControllerManagerCommand()

##  파일위치 : cmd/kube-controller-manager/app/controllermanager.go
##  함수    : NewControllerManagerCommand()

 

컨트롤러 매니저 실행

RunE

[컨트롤러 매니저 실행]

##  파일위치 : cmd/kube-controller-manager/app/controllermanager.go
##  실행 순서 : NewControllerManagerCommand() → RunE
##  함수     : RunE
##  함수 설명 :

NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete())

 

RunE → Run(ctx, c.Complete())

1. [컴포넌트 초기화] - createClientBuilders() 클라이언트 빌더 생성  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → createClientBuilders()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `clientBuilder, rootClientBuilder := createClientBuilders(c)`  
   설명: 컨트롤러에서 사용할 클라이언트 빌더를 생성

Run() → createClientBuilders()
createClientBuilders() 함수

 

 

2. [컴포넌트 초기화] - newServiceAccountTokenControllerDescriptor() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → newServiceAccountTokenControllerDescriptor()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `saTokenControllerDescriptor := newServiceAccountTokenControllerDescriptor(rootClientBuilder)`  
   설명: 서비스 어카운트 토큰 컨트롤러 디스크립터 생성

Run() → newServiceAccountTokenControllerDescriptor()
newServiceAccountTokenControllerDescriptor() 함수

 

 

3. [실행준비] - run 함수 정의 (아직 실행되지 않음)  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete())  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `run := func(ctx context.Context, controllerDescriptors map[string]*ControllerDescriptor) { ... }`  
   설명: 컨트롤러 실행을 위한 함수 정의

 

 

4. [실행준비] - leader election 필요한지 판단  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete())  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `if !c.ComponentConfig.Generic.LeaderElection.LeaderElect { ... }`  
   설명: 리더 선출 필요 여부 확인

if !c.ComponentConfig.Generic.LeaderElection.LeaderElect

 

 

5. [컨트롤러 등록] - NewControllerDescriptors() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `controllerDescriptors := NewControllerDescriptors()`  
   설명: 모든 컨트롤러 디스크립터를 등록하는 맵 생성

Run() → No leader election → NewControllerDescriptors()
NewControllerDescriptors() 함수

 

5. [컨트롤러 등록] - NewControllerDescriptors() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `controllerDescriptors := NewControllerDescriptors()`  
   설명: 모든 컨트롤러 디스크립터를 등록하는 맵 생성

   a. [컨트롤러 등록] - ServiceAccountTokenController 디스크립터 등록  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors() → register(newServiceAccountTokenControllerDescriptor(nil))  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `register(newServiceAccountTokenControllerDescriptor(nil))`  
      설명: 토큰 컨트롤러 디스크립터 등록

 

 

5. [컨트롤러 등록] - NewControllerDescriptors() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `controllerDescriptors := NewControllerDescriptors()`  
   설명: 모든 컨트롤러 디스크립터를 등록하는 맵 생성

   a. [컨트롤러 등록] - ServiceAccountTokenController 디스크립터 등록  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors() → register(newServiceAccountTokenControllerDescriptor(nil))  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `register(newServiceAccountTokenControllerDescriptor(nil))`  
      설명: 토큰 컨트롤러 디스크립터 등록

   b. [컨트롤러 등록] - ServiceAccountController 디스크립터 등록  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors() → register(newServiceAccountControllerDescriptor())  
      파일: [cmd/kube-controller-manager/app/core.go]  
      코드: `register(newServiceAccountControllerDescriptor())`  
      설명: 서비스 어카운트 컨트롤러 디스크립터 등록
      
   c. [컨트롤러 등록] - ServiceAccountController 디스크립터 생성  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → NewControllerDescriptors() → newServiceAccountControllerDescriptor()  
      파일: [cmd/kube-controller-manager/app/core.go]  
      코드: `return &ControllerDescriptor{name: names.ServiceAccountController, aliases: []string{"serviceaccount"}, initFunc: startServiceAccountController}`  
      설명: 서비스 어카운트 컨트롤러 이름, 별칭, 초기화 함수 설정

 

중요

이 단계에서는 initFunc로 startServiceAccountController 함수를 참조만 등록하고 실제로는 실행되지 않음.
startServiceAccountController 함수가 실행되지 않고 포인터만 저장됨.

`go sac.Run(ctx, 1)` 코드도 아직 실행되지 않음
나중에 10번 단계(StartController 호출 시)에서 실행됨

 

 

6. [컨트롤러 설정] - saTokenControllerDescriptor를 맵에 추가  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete())  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `controllerDescriptors[names.ServiceAccountTokenController] = saTokenControllerDescriptor`  
   설명: 토큰 컨트롤러 디스크립터를 컨트롤러 맵에 추가

 

7. [실행 & 컨트롤러 디스크립터 전달] - run 함수 호출시 컨트롤러 디스크립터 맵 전달
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `run(ctx, controllerDescriptors)`  
   설명: 5번에서 생성한 컨트롤러 디스크립터 맵을 run 함수에 전달하여 실행

 

8. [컨텍스트 생성] - CreateControllerContext() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → CreateControllerContext()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `controllerContext, err := CreateControllerContext(ctx, c, rootClientBuilder, clientBuilder)`  
   설명: 컨트롤러 컨텍스트 생성 (인포머, 클라이언트 등 포함)

 

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작

   a. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `for _, controllerDesc := range controllerDescriptors { ... }`  
      설명: 5번에서 등록한 모든 컨트롤러 디스크립터를 순회하며 각각 시작

   b. [개별 컨트롤러 시작] - StartController 호출  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `check, err := StartController(ctx, controllerCtx, controllerDesc, unsecuredMux)`  
      설명: 각 컨트롤러 디스크립터에 대해 StartController 함수 호출 (ServiceAccountController 포함)

      b-1. [초기화 함수 가져오기] - 디스크립터에서 초기화 함수 가져오기  
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
           파일: [cmd/kube-controller-manager/app/controllermanager.go]  
           코드: `initFunc := controllerDescriptor.GetInitFunc()`  
           설명: 디스크립터에서 초기화 함수 참조를 가져옴 (ServiceAccountController의 경우 5b에서 저장한 startServiceAccountController)

      b-2. [초기화 함수 실행] - ServiceAccountController의 초기화 함수 실행  
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController()  
           파일: [cmd/kube-controller-manager/app/core.go]  
           코드: `ctrl, started, err := initFunc(klog.NewContext(ctx, ...), controllerCtx, controllerName)`  
           설명: 5b에서 저장했던 startServiceAccountController 함수가 실제로 호출되어 실행됨

      b-3. [ServiceAccount 컨트롤러 생성] - NewServiceAccountsController 호출
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController() → NewServiceAccountsController()
           파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
           코드: `sac, err := serviceaccountcontroller.NewServiceAccountsController(...)`
           설명: ServiceAccountsController 인스턴스 생성 및 이벤트 핸들러 구성

      b-4. [ServiceAccount 컨트롤러 실행] - 비동기 실행
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController()
           파일: [cmd/kube-controller-manager/app/core.go]
           코드: `go sac.Run(ctx, 1)`
           설명: ServiceAccountsController를 고루틴으로 비동기 실행 (1: 워커 수)

 

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작

 

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작

   a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `check, err := StartController(ctx, controllerCtx, serviceAccountTokenControllerDescriptor, unsecuredMux)`  
      설명: 토큰 컨트롤러 우선 시작 (다른 컨트롤러에서 필요)

   b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `for _, controllerDesc := range controllerDescriptors { ... }`  
      설명: 5번에서 등록한 모든 컨트롤러 디스크립터를 순회하며 각각 시작
      
   c. [개별 컨트롤러 시작] - StartController 호출  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `check, err := StartController(ctx, controllerCtx, controllerDesc, unsecuredMux)`  
      설명: 각 컨트롤러 디스크립터에 대해 StartController 함수 호출 (ServiceAccountController 포함)

a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작

   a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작  
   

   b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `for _, controllerDesc := range controllerDescriptors { ... }`  
      설명: 5번에서 등록한 모든 컨트롤러 디스크립터를 순회하며 각각 시작
      
   c. [개별 컨트롤러 시작] - StartController 호출  
      실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
      파일: [cmd/kube-controller-manager/app/controllermanager.go]  
      코드: `check, err := StartController(ctx, controllerCtx, controllerDesc, unsecuredMux)`  
      설명: 각 컨트롤러 디스크립터에 대해 StartController 함수 호출 (ServiceAccountController 포함)

b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회 & c. [개별 컨트롤러 시작] - StartController 호출

 

 


for _, controllerDesc 

controllerDesc 변수가 중요함

[controllerDesc] 1. NewControllerDescriptors()
[controllerDesc] 2-1. map[string]*ControllerDescriptor
[controllerDesc] 2-2. register
[controllerDesc] 2-3. controller > register
[controllerDesc] 3. run(ctx, controllerDescriptors) 변수로 전달
[controllerDesc] 4. StartControllers 함수로 전달
[controllerDesc] 5. StartControllers 함수 - for문에서 controllerDesc 변수로 사용됨

 

 

 

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작
   
   a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작  


   b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  


   c. [개별 컨트롤러 시작] - StartController 호출  

      c-1. [초기화 함수 가져오기] - 디스크립터에서 초기화 함수 가져오기  
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController()  
           파일: [cmd/kube-controller-manager/app/controllermanager.go]  
           코드: `initFunc := controllerDescriptor.GetInitFunc()`  
           설명: 디스크립터에서 초기화 함수 참조를 가져옴 (ServiceAccountController의 경우 5b에서 저장한 startServiceAccountController)

c-1. [초기화 함수 가져오기] - 디스크립터에서 초기화 함수 가져오기

 

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작
   
   a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작  


   b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  


   c. [개별 컨트롤러 시작] - StartController 호출  
      c-1. [초기화 함수 가져오기] - 디스크립터에서 초기화 함수 가져오기  

      c-2. [초기화 함수 실행] - newServiceAccountControllerDescriptor 실행  
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → newServiceAccountControllerDescriptor → initFunc: startServiceAccountController 실행 
           파일: [cmd/kube-controller-manager/app/core.go]  
           코드: `ctrl, started, err := initFunc(klog.NewContext(ctx, ...), controllerCtx, controllerName)`  
           설명: 5b에서 저장했던 startServiceAccountController 함수가 실제로 호출되어 실행됨

newServiceAccountControllerDescriptor → initFunc: startServiceAccountController
startServiceAccountController

 

9. [컨트롤러 시작] - StartControllers() 실행  
   실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers()  
   파일: [cmd/kube-controller-manager/app/controllermanager.go]  
   코드: `err := StartControllers(ctx, controllerContext, controllerDescriptors, unsecuredMux, healthzHandler)`  
   설명: 7번에서 전달받은 컨트롤러 디스크립터 맵을 사용하여 모든 컨트롤러 시작
   
   a. [특별 컨트롤러] - ServiceAccountTokenController 먼저 시작  


   b. [컨트롤러 순회] - 등록된 모든 컨트롤러 순회  


   c. [개별 컨트롤러 시작] - StartController 호출  
      c-1. [초기화 함수 가져오기] - 디스크립터에서 초기화 함수 가져오기  

      c-2. [초기화 함수 실행] - newServiceAccountControllerDescriptor 실행  

      c-3. [ServiceAccount 컨트롤러 생성] - NewServiceAccountsController 호출
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController() → NewServiceAccountsController()
           파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
           코드: `sac, err := serviceaccountcontroller.NewServiceAccountsController(...)`
           설명: ServiceAccountsController 인스턴스 생성 및 이벤트 핸들러 구성
           
      c-4. [ServiceAccount 컨트롤러 실행] - 비동기 실행
           실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController()
           파일: [cmd/kube-controller-manager/app/core.go]
           코드: `go sac.Run(ctx, 1)`
           설명: ServiceAccountsController를 고루틴으로 비동기 실행 (1: 워커 수)

go sac.Run()
serviceaccountcontroller.NewServiceAccountsController

 

 

 

10. [ServiceAccount 컨트롤러 초기화] - startServiceAccountController() 실행  
    실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController()  
    파일: [cmd/kube-controller-manager/app/core.go]  
    코드: `sac, err := serviceaccountcontroller.NewServiceAccountsController(..., serviceaccountcontroller.DefaultServiceAccountsControllerOptions())`  
    설명: ServiceAccount 컨트롤러 초기화 함수가 4가지 주요 파라미터로 호출됨
      - ServiceAccount 인포머: 클러스터의 모든 서비스어카운트 변경 감시
      - Namespace 인포머: 클러스터의 모든 네임스페이스 변경 감시
      - 클라이언트: API 서버와 통신하기 위한 클라이언트
      - 기본 옵션: "default" 서비스어카운트를 포함한 옵션

    a. [기본 옵션 설정] - DefaultServiceAccountsControllerOptions() 호출  
       실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController() → DefaultServiceAccountsControllerOptions()  
       파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
       코드: `return ServiceAccountsControllerOptions{ServiceAccounts: []v1.ServiceAccount{{ObjectMeta: metav1.ObjectMeta{Name: "default"}}}}`  
       설명: 기본 옵션 생성 - "default"라는 이름의 서비스어카운트가 포함됨

DefaultServiceAccountsControllerOptions

 

 

11. [ServiceAccount 컨트롤러 생성] - NewServiceAccountsController() 실행  
    실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController() → NewServiceAccountsController()  
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
    코드: `e := &ServiceAccountsController{client: cl, serviceAccountsToEnsure: options.ServiceAccounts, ...}`  
    설명: ServiceAccount 컨트롤러 객체 생성 및 이벤트 핸들러 등록
      - serviceAccountsToEnsure: "default" 서비스어카운트 목록 저장
      - 서비스어카운트 삭제 이벤트 핸들러 등록 (serviceAccountDeleted)
      - 네임스페이스 추가/업데이트 이벤트 핸들러 등록 (namespaceAdded, namespaceUpdated)

NewServiceAccountsController

 

12. [ServiceAccount 컨트롤러 실행] - Run() 함수 고루틴으로 시작
    실행순서: NewControllerManagerCommand() → RunE() → Run(ctx, c.Complete()) → run() → StartControllers() → StartController() → startServiceAccountController() → go sac.Run(ctx, 1)
    파일: [cmd/kube-controller-manager/app/core.go]
    코드: `go sac.Run(ctx, 1)`
    설명: core.go에서 ServiceAccount 컨트롤러를 비동기 고루틴으로 실행 (1은 워커 수)

[core.go] - go sac.Run(ctx, 1)

 

13. [컨트롤러 초기화] - Run 함수 내부 실행
    실행순서: startServiceAccountController() → go sac.Run() → ServiceAccountsController.Run()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `if !cache.WaitForNamedCacheSync("service account", ctx.Done(), c.saListerSynced, c.nsListerSynced) { return }`
    설명: 인포머 캐시가 동기화될 때까지 대기 (실제 작업 시작 전 준비)

if !cache.WaitForNamedCacheSync

 

14. [워커 시작] - 워커 고루틴 시작
    실행순서: startServiceAccountController() → go sac.Run() → ServiceAccountsController.Run()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `go wait.UntilWithContext(ctx, c.runWorker, time.Second)`
    설명: 워커 고루틴 시작 - 1초마다 c.runWorker 함수를 주기적으로 호출

[serviceaccoounts_controller.go] / func (c *ServiceAccountsController) Run(ctx context.Context, workers int)

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기
          실행순서: runWorker() → processNextWorkItem() → queue.Get()
          파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
          코드: `key, quit := c.queue.Get()`  
          설명: 워커가 큐에서 처리할 네임스페이스 이름을 가져옴

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출
          실행순서: runWorker() → processNextWorkItem() → syncHandler()
          파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
          코드: `err := c.syncHandler(ctx, key)`  
          설명: 가져온 네임스페이스 이름으로 syncNamespace 함수 호출

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직
          실행순서: processNextWorkItem() → syncHandler() → syncNamespace()
          파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
          코드: `for _, sa := range c.serviceAccountsToEnsure { ... }`  
          설명: serviceAccountsToEnsure에 포함된 각 서비스어카운트(여기서는 "default") 처리

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직


    15-4. [실제 생성 작업] - Kubernetes API 호출
          실행순서: syncHandler() → syncNamespace() → Create()
          파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
          코드: `if _, err := c.client.CoreV1().ServiceAccounts(ns.Name).Create(ctx, &sa, metav1.CreateOptions{}); ...`  
          설명: Kubernetes API 서버에 요청하여 "default" 서비스어카운트 실제 생성

 

 

 


 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직


    15-4. [실제 생성 작업] - Kubernetes API 호출

      15-4-1. [클라이언트 호출 경로] - API 클라이언트 메서드 호출 체인
              실행순서: c.client.CoreV1() → ServiceAccounts() → Create()
              파일: [staging/src/k8s.io/client-go/kubernetes/typed/core/v1/core_client.go]
              코드: `func (c *CoreV1Client) ServiceAccounts(namespace string) ServiceAccountInterface { return newServiceAccounts(c, namespace) }`
              설명: CoreV1Client에서 네임스페이스에 맞는 ServiceAccount 클라이언트 인터페이스 반환

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직


    15-4. [실제 생성 작업] - Kubernetes API 호출

      15-4-1. [클라이언트 호출 경로] - API 클라이언트 메서드 호출 체인


      15-4-2. [인터페이스 구현체] - serviceaccounts 구조체 생성
              실행순서: ServiceAccounts() → newServiceAccounts()
              파일: [staging/src/k8s.io/client-go/kubernetes/typed/core/v1/serviceaccount.go]
              코드: `return &serviceAccounts{ gentype.NewClientWithListAndApply[*corev1.ServiceAccount, ...] }`
              설명: ServiceAccountInterface를 구현하는 serviceaccounts 객체 생성

 

15. [작업 처리 루프] - runWorker 및 processNextWorkItem 함수
    실행순서: Run() → go wait.UntilWithContext() → runWorker() → processNextWorkItem()
    파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]
    코드: `for c.processNextWorkItem(ctx) { }`
    설명: 워커 고루틴이 지속적으로 큐를 모니터링하면서 작업 처리 루프 실행

    15-1. [작업 가져오기] - 큐에서 작업 가져오기


    15-2. [작업 처리] - syncHandler(syncNamespace) 호출


    15-3. [ServiceAccount 생성] - syncNamespace 함수 내부 로직


    15-4. [실제 생성 작업] - Kubernetes API 호출

      15-4-1. [클라이언트 호출 경로] - API 클라이언트 메서드 호출 체인


      15-4-2. [인터페이스 구현체] - serviceaccounts 구조체 생성


      15-4-3. [API 호출] - Create 메서드 실행
              실행순서: serviceAccounts.Create() → ClientWithListAndApply[T].Create() (상속) → Client[T].Create()
              파일: [staging/src/k8s.io/client-go/gentype/client.go]
              코드: `func (c *Client[T]) Create(ctx context.Context, obj T, opts metav1.CreateOptions) (T, error)`
              설명: 제네릭 Client 구조체의 Create 메서드가 ServiceAccount 객체를 전달받아 API 서버로 요청 생성

      15-4-4. [HTTP 요청] - REST 클라이언트 호출
              실행순서: Create() → RESTClient.Post()
              파일: [staging/src/k8s.io/client-go/rest/request.go]
              코드: REST 클라이언트가 HTTP POST 요청 생성 및 전송
              설명: `/api/v1/namespaces/{namespace}/serviceaccounts` 엔드포인트로 POST 요청 전송

      15-4-5. [API 서버 처리] - 요청 처리 및 저장
              실행경로: kube-apiserver → ServiceAccount 어드미션 컨트롤러 → etcd 저장
              설명: API 서버가 요청을 검증한 후 ServiceAccount 객체를 etcd에 저장
              특징: 이 부분은 클라이언트가 아닌 API 서버에서 처리됨

 

 

A. [이벤트 핸들러] - 네임스페이스 이벤트 발생 시 처리  
   실행순서: (인포머에서 이벤트 발생 시) → namespaceAdded() / namespaceUpdated()  
   파일: [pkg/controller/serviceaccount/serviceaccounts_controller.go]  
   코드: `c.queue.Add(namespace.Name)`  
   설명: 네임스페이스 생성/업데이트 이벤트 발생 시 해당 네임스페이스 이름을 작업 큐에 추가

c.queue.Add(newNamespace.Name)

 

 

profile

영기

@yeongki0944

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그