5.6.2.4. 컨트롤러 구현
새 API 및 컨트롤러를 생성하면 컨트롤러 논리를 구현할 수 있습니다.
프로세스
pom.xml파일에 다음 종속성을 추가합니다.<dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.2</version> </dependency>이 예에서는 생성된 컨트롤러 파일
MemcachedReconciler.java를 다음 예제 구현으로 교체합니다.예 5.9. Example
MemcachedReconciler.javapackage com.example; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.fabric8.kubernetes.api.model.ContainerBuilder; import io.fabric8.kubernetes.api.model.ContainerPortBuilder; import io.fabric8.kubernetes.api.model.LabelSelectorBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpecBuilder; import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder; import org.apache.commons.collections.CollectionUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MemcachedReconciler implements Reconciler<Memcached> { private final KubernetesClient client; public MemcachedReconciler(KubernetesClient client) { this.client = client; } // TODO Fill in the rest of the reconciler @Override public UpdateControl<Memcached> reconcile( Memcached resource, Context context) { // TODO: fill in logic Deployment deployment = client.apps() .deployments() .inNamespace(resource.getMetadata().getNamespace()) .withName(resource.getMetadata().getName()) .get(); if (deployment == null) { Deployment newDeployment = createMemcachedDeployment(resource); client.apps().deployments().create(newDeployment); return UpdateControl.noUpdate(); } int currentReplicas = deployment.getSpec().getReplicas(); int requiredReplicas = resource.getSpec().getSize(); if (currentReplicas != requiredReplicas) { deployment.getSpec().setReplicas(requiredReplicas); client.apps().deployments().createOrReplace(deployment); return UpdateControl.noUpdate(); } List<Pod> pods = client.pods() .inNamespace(resource.getMetadata().getNamespace()) .withLabels(labelsForMemcached(resource)) .list() .getItems(); List<String> podNames = pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList()); if (resource.getStatus() == null || !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) { if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus()); resource.getStatus().setNodes(podNames); return UpdateControl.updateResource(resource); } return UpdateControl.noUpdate(); } private Map<String, String> labelsForMemcached(Memcached m) { Map<String, String> labels = new HashMap<>(); labels.put("app", "memcached"); labels.put("memcached_cr", m.getMetadata().getName()); return labels; } private Deployment createMemcachedDeployment(Memcached m) { Deployment deployment = new DeploymentBuilder() .withMetadata( new ObjectMetaBuilder() .withName(m.getMetadata().getName()) .withNamespace(m.getMetadata().getNamespace()) .build()) .withSpec( new DeploymentSpecBuilder() .withReplicas(m.getSpec().getSize()) .withSelector( new LabelSelectorBuilder().withMatchLabels(labelsForMemcached(m)).build()) .withTemplate( new PodTemplateSpecBuilder() .withMetadata( new ObjectMetaBuilder().withLabels(labelsForMemcached(m)).build()) .withSpec( new PodSpecBuilder() .withContainers( new ContainerBuilder() .withImage("memcached:1.4.36-alpine") .withName("memcached") .withCommand("memcached", "-m=64", "-o", "modern", "-v") .withPorts( new ContainerPortBuilder() .withContainerPort(11211) .withName("memcached") .build()) .build()) .build()) .build()) .build()) .build(); deployment.addOwnerReference(m); return deployment; } }예제 컨트롤러는 각
MemcachedCR(사용자 정의 리소스)에 대해 다음 조정 논리를 실행합니다.- Memcached 배포가 없는 경우 생성합니다.
-
배포 크기가
MemcachedCR 사양에 지정된 크기와 일치하는지 확인합니다. -
MemcachedCR 상태를memcachedPod의 이름으로 업데이트합니다.
다음 하위 섹션에서는 구현 예제의 컨트롤러에서 리소스를 조사하는 방법과 조정 반복문을 트리거하는 방법을 설명합니다. 이러한 하위 섹션을 건너뛰어 Operator 실행으로 직접 이동할 수 있습니다.
5.6.2.4.1. 조정 반복문 링크 복사링크가 클립보드에 복사되었습니다!
모든 컨트롤러에는 조정 반복문을 구현하는
Reconcile()메서드가 포함된 조정기 오브젝트가 있습니다. 조정 루프는 다음 예와 같이Deployment인수를 전달합니다.Deployment deployment = client.apps() .deployments() .inNamespace(resource.getMetadata().getNamespace()) .withName(resource.getMetadata().getName()) .get();다음 예와 같이
Deployment가null인 경우 배포를 생성해야 합니다. 배포를 생성한 후 조정이 필요한지 여부를 확인할 수 있습니다.조정이 필요하지 않은 경우UpdateControl.noUpdate()의 값을 반환하고, 그렇지 않으면 'UpdateControl.updateStatus(resource) 값을 반환합니다.if (deployment == null) { Deployment newDeployment = createMemcachedDeployment(resource); client.apps().deployments().create(newDeployment); return UpdateControl.noUpdate(); }배포를 가져온
후다음 예와 같이 현재 및 필수 복제본을 가져옵니다.int currentReplicas = deployment.getSpec().getReplicas(); int requiredReplicas = resource.getSpec().getSize();currentReplicas가requiredReplicas와 일치하지 않는 경우 다음 예와 같이Deployment를 업데이트해야 합니다.if (currentReplicas != requiredReplicas) { deployment.getSpec().setReplicas(requiredReplicas); client.apps().deployments().createOrReplace(deployment); return UpdateControl.noUpdate(); }다음 예제에서는 Pod 및 해당 이름 목록을 가져오는 방법을 보여줍니다.
List<Pod> pods = client.pods() .inNamespace(resource.getMetadata().getNamespace()) .withLabels(labelsForMemcached(resource)) .list() .getItems(); List<String> podNames = pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList());리소스가 생성되었는지 확인하고 Memcached 리소스를 사용하여 podname을 확인합니다. 이러한 조건 중 하나에 불일치가 있는 경우 다음 예에 표시된 대로 조정을 수행합니다.
if (resource.getStatus() == null || !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) { if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus()); resource.getStatus().setNodes(podNames); return UpdateControl.updateResource(resource); }