메모. 번역: Operator는 특정 이벤트가 발생할 때 클러스터 개체에 대한 일상적인 작업 실행을 자동화하도록 설계된 Kubernetes용 보조 소프트웨어입니다. 우리는 이미 연산자에 대해 썼습니다.
Kubernetes용 연산자를 만드는 방법에 대한 문서를 찾다가 코드 연구를 거쳐 실제 사례를 사용하여 이 게시물을 작성하기로 결정했습니다.
설명할 예는 다음과 같습니다. Kubernetes 클러스터에서 각 Namespace
팀의 샌드박스 환경을 나타내며, 우리는 팀이 자신의 샌드박스에서만 플레이할 수 있도록 이에 대한 액세스를 제한하고 싶었습니다.
다음과 같은 그룹을 사용자에게 할당하여 원하는 것을 얻을 수 있습니다. RoleBinding
특정 Namespace
и ClusterRole
편집 권한이 있습니다. YAML 표현은 다음과 같습니다.
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: kubernetes-team-1
namespace: team-1
subjects:
- kind: Group
name: kubernetes-team-1
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
하나 만들기 RoleBinding
수동으로 수행할 수도 있지만 XNUMX개의 네임스페이스 표시를 넘은 후에는 지루한 작업이 됩니다. 여기에서 Kubernetes 운영자가 유용합니다. 이를 통해 리소스 변경 사항에 따라 Kubernetes 리소스 생성을 자동화할 수 있습니다. 우리의 경우 우리는 만들고 싶습니다 RoleBinding
만드는 동안 Namespace
.
먼저 함수를 정의해보자. main
명령문을 실행하는 데 필요한 설정을 수행한 다음 명령문 작업을 호출합니다.
(메모. 번역: 여기와 아래의 코드 주석은 러시아어로 번역됩니다. 또한 Habr 레이아웃 내에서 가독성을 높이기 위해 들여쓰기를 [Go에서 권장] 탭 대신 공백으로 수정했습니다. 각 목록 뒤에는 영어 댓글과 탭이 저장되어 있는 GitHub의 원본 링크가 있습니다.
func main() {
// Устанавливаем вывод логов в консольный STDOUT
log.SetOutput(os.Stdout)
sigs := make(chan os.Signal, 1) // Создаем канал для получения сигналов ОС
stop := make(chan struct{}) // Создаем канал для получения стоп-сигнала
// Регистрируем получение SIGTERM в канале sigs
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
// Goroutines могут сами добавлять себя в WaitGroup,
// чтобы завершения их выполнения дожидались
wg := &sync.WaitGroup{}
runOutsideCluster := flag.Bool("run-outside-cluster", false, "Set this flag when running outside of the cluster.")
flag.Parse()
// Создаем clientset для взаимодействия с кластером Kubernetes
clientset, err := newClientSet(*runOutsideCluster)
if err != nil {
panic(err.Error())
}
controller.NewNamespaceController(clientset).Run(stop, wg)
<-sigs // Ждем сигналов (до получения сигнала более ничего не происходит)
log.Printf("Shutting down...")
close(stop) // Говорим goroutines остановиться
wg.Wait() // Ожидаем, что все остановлено
}
우리는 다음을 수행합니다:
- 특정 운영 체제 신호에 대한 처리기를 구성하여 연산자를 정상적으로 종료합니다.
- 우리는 사용
WaitGroup
애플리케이션을 종료하기 전에 모든 고루틴을 정상적으로 중지합니다. - 우리는 다음을 생성하여 클러스터에 대한 액세스를 제공합니다.
clientset
. - 시작하다
NamespaceController
, 여기에 모든 논리가 위치합니다.
이제 우리는 논리의 기초가 필요하며, 우리의 경우에는 이것이 언급된 것입니다. NamespaceController
:
// NamespaceController следит через Kubernetes API за изменениями
// в пространствах имен и создает RoleBinding для конкретного namespace.
type NamespaceController struct {
namespaceInformer cache.SharedIndexInformer
kclient *kubernetes.Clientset
}
// NewNamespaceController создает новый NewNamespaceController
func NewNamespaceController(kclient *kubernetes.Clientset) *NamespaceController {
namespaceWatcher := &NamespaceController{}
// Создаем информер для слежения за Namespaces
namespaceInformer := cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return kclient.Core().Namespaces().List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return kclient.Core().Namespaces().Watch(options)
},
},
&v1.Namespace{},
3*time.Minute,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
)
namespaceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: namespaceWatcher.createRoleBinding,
})
namespaceWatcher.kclient = kclient
namespaceWatcher.namespaceInformer = namespaceInformer
return namespaceWatcher
}
여기서는 구성합니다. SharedIndexInformer
, 이는 (캐시를 사용하여) 네임스페이스의 변경을 효과적으로 기다립니다. (“기사에서 정보 제공자에 대해 자세히 알아보십시오.EventHandler
네임스페이스를 추가할 때(Namespace
) 함수가 호출됩니다. createRoleBinding
.
다음 단계는 이 함수를 정의하는 것입니다. createRoleBinding
:
func (c *NamespaceController) createRoleBinding(obj interface{}) {
namespaceObj := obj.(*v1.Namespace)
namespaceName := namespaceObj.Name
roleBinding := &v1beta1.RoleBinding{
TypeMeta: metav1.TypeMeta{
Kind: "RoleBinding",
APIVersion: "rbac.authorization.k8s.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("ad-kubernetes-%s", namespaceName),
Namespace: namespaceName,
},
Subjects: []v1beta1.Subject{
v1beta1.Subject{
Kind: "Group",
Name: fmt.Sprintf("ad-kubernetes-%s", namespaceName),
},
},
RoleRef: v1beta1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "edit",
},
}
_, err := c.kclient.Rbac().RoleBindings(namespaceName).Create(roleBinding)
if err != nil {
log.Println(fmt.Sprintf("Failed to create Role Binding: %s", err.Error()))
} else {
log.Println(fmt.Sprintf("Created AD RoleBinding for Namespace: %s", roleBinding.Name))
}
}
우리는 네임스페이스를 다음과 같이 얻습니다. obj
그리고 그것을 객체로 변환 Namespace
. 그런 다음 우리는 정의합니다 RoleBinding
, 처음에 언급한 YAML 파일을 기반으로 제공된 객체를 사용하여 Namespace
그리고 창조 RoleBinding
. 마지막으로 생성이 성공했는지 기록합니다.
마지막으로 정의할 함수는 다음과 같습니다. Run
:
// Run запускает процесс ожидания изменений в пространствах имён
// и действия в соответствии с этими изменениями.
func (c *NamespaceController) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
// Когда эта функция завершена, пометим как выполненную
defer wg.Done()
// Инкрементируем wait group, т.к. собираемся вызвать goroutine
wg.Add(1)
// Вызываем goroutine
go c.namespaceInformer.Run(stopCh)
// Ожидаем получения стоп-сигнала
<-stopCh
}
여기서 우리는 이야기하고 있습니다 WaitGroup
고루틴을 시작한 다음 호출합니다. namespaceInformer
, 이는 이전에 정의된 것입니다. 정지 신호가 도착하면 기능이 종료되고 이를 알려줍니다. WaitGroup
는 더 이상 실행되지 않으며 이 함수는 종료됩니다.
Kubernetes 클러스터에서 이 명령문을 빌드하고 실행하는 방법에 대한 정보는 다음에서 찾을 수 있습니다.
그게 바로 운영자를 위한 것입니다. RoleBinding
언제 Namespace
Kubernetes 클러스터에서 준비되었습니다.
출처 : habr.com