1. 소개
이 사용방법(예제)에서는 공식 클라이언트 라이브러리를 사용하여 Java 애플리케이션에서 Kubernetes API를 사용하는 방법을 보여줍니다.
2. Kubernetes API를 사용하는 이유는 무엇입니까?
요즘에는 쿠버네티스가 컨테이너화 된 애플리케이션을 관리하기 위한 사실상 의 표준이 되었다고 해도 과언이 아닙니다 . 스토리지, 비밀 및 환경 변수와 같은 애플리케이션 및 관련 리소스를 배포, 확장 및 모니터링할 수 있는 풍부한 API를 제공합니다. 실제로 이 API에 대해 생각하는 한 가지 방법은 일반 운영 체제에서 사용할 수 있는 시스템 호출의 분산 아날로그입니다.
대부분의 경우 애플리케이션은 Kubernetes에서 실행되고 있다는 사실을 무시할 수 있습니다. 이를 통해 로컬에서 개발하고 몇 가지 명령과 YAML 주문을 사용하여 사소한 변경만으로 여러 클라우드 Provider에 신속하게 배포할 수 있으므로 좋은 일입니다.
그러나 특정 기능을 달성하기 위해 Kubernetes API와 대화해야 하는 몇 가지 흥미로운 사용 사례가 있습니다.
- 일부 작업을 수행하기 위해 외부 프로그램을 시작하고 나중에 완료 상태를 검색합니다.
- 일부 고객 요청에 대한 응답으로 일부 서비스를 동적으로 생성/수정
- 여러 Kubernetes 클러스터, 심지어 클라우드 Provider 간에 실행되는 솔루션에 대한 사용자 정의 모니터링 대시보드 생성
물론 이러한 사용 사례는 일반적이지 않지만 API 덕분에 달성하기가 매우 간단하다는 것을 알 수 있습니다.
또한 Kubernetes API는 개방형 사양이므로 인증된 구현에서 코드를 수정하지 않고도 코드가 실행될 것이라고 확신할 수 있습니다 .
3. 지역 개발 환경
애플리케이션 생성을 진행하기 전에 가장 먼저 해야 할 일은 작동하는 Kubernetes 클러스터에 액세스하는 것입니다. 이를 위해 퍼블릭 클라우드 Provider를 사용할 수 있지만 일반적으로 로컬 환경은 설정의 모든 측면에 대해 더 많은 제어를 제공합니다.
이 작업에 적합한 몇 가지 경량 배포판이 있습니다.
실제 설정 단계는 이 기사의 범위를 벗어나지만 어떤 옵션을 선택 하든 개발을 시작하기 전에 kubectl 이 제대로 실행되는지 확인하십시오.
4. 메이븐 의존성
먼저 프로젝트의 pom.xml 에 Kubernetes Java API 의존성을 추가해 보겠습니다 .
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>11.0.0</version>
</dependency>
최신 버전의 client-java 는 Maven Central에서 다운로드할 수 있습니다.
5. 안녕, 쿠버네티스
이제 사용 가능한 노드와 노드에 대한 정보를 나열하는 매우 간단한 Kubernetes 애플리케이션을 만들어 보겠습니다.
단순함에도 불구하고 이 애플리케이션은 실행 중인 클러스터에 연결하고 API 호출을 수행하기 위해 거쳐야 하는 필수 단계를 보여줍니다. 실제 애플리케이션에서 사용하는 API에 관계없이 해당 단계는 항상 동일합니다.
5.1. API 클라이언트 초기화
ApiClient 클래스 는 Kubernetes API 서버에 대한 호출을 수행하는 모든 논리를 포함하므로 API에서 가장 중요한 클래스 중 하나입니다 . 이 클래스의 인스턴스를 만드는 권장 방법은 Config 클래스에서 사용 가능한 정적 메서드 중 하나를 사용하는 것입니다. 특히 가장 쉬운 방법은 defaultClient() 메서드를 사용하는 것입니다.
ApiClient client = Config.defaultClient();
이 방법을 사용하면 코드가 원격 및 클러스터 내 시나리오 모두에서 작동합니다. 또한 구성 파일을 찾기 위해 kubectl 유틸리티에서 사용하는 것과 동일한 단계를 자동으로 따릅니다.
- KUBECONFIG 환경 변수 에 의해 정의된 구성 파일
- $HOME/.kube/config 파일
- /var/run/secrets/kubernetes.io/serviceaccount 아래의 서비스 계정 토큰
- http://localhost:8080 에 직접 액세스
세 번째 단계는 적절한 서비스 계정을 사용할 수 있는 한 앱이 모든 포드 의 일부로 클러스터 내에서 실행될 수 있도록 하는 것입니다.
또한 구성 파일에 정의된 여러 컨텍스트가 있는 경우 이 절차는 kubectl config set-context 명령을 사용하여 정의된 대로 "현재" 컨텍스트를 선택합니다.
5.2. API 스텁 생성
ApiClient 인스턴스를 확보 하면 이를 사용하여 사용 가능한 모든 API에 대한 스텁을 생성할 수 있습니다. 이 경우 사용 가능한 노드를 나열하는 데 필요한 메서드가 포함된 CoreV1Api 클래스를 사용합니다.
CoreV1Api api = new CoreV1Api(client);
여기서는 이미 존재하는 ApiClient 를 사용하여 API 스텁을 생성합니다.
인수가 없는 생성자도 사용할 수 있지만 일반적으로 사용을 자제해야 합니다 . 사용 하지 않는 이유 는 내부적으로 Configuration.setDefaultApiClient() 를 통해 이전에 설정해야 하는 전역 ApiClient 를 사용하기 때문입니다 . 이렇게 하면 스텁을 사용하기 전에 이 메서드를 호출하는 사람에 대한 암시적 의존성이 생성되어 런타임 오류 및 유지 관리 문제가 발생할 수 있습니다.
더 나은 접근 방식은 의존성 주입 프레임워크를 사용하여 이 초기 배선을 수행하고 필요할 때마다 결과 스텁을 주입하는 것입니다.
5.3. Kubernetes API 호출
마지막으로 사용 가능한 노드를 반환하는 실제 API 호출을 시작하겠습니다. CoreApiV1 스텁에는 정확히 이 작업을 수행하는 메서드가 있으므로 간단합니다 .
V1NodeList nodeList = api.listNode(null, null, null, null, null, null, null, null, 10, false);
nodeList.getItems()
.stream()
.forEach((node) -> System.out.println(node));
이 예에서는 선택 사항이므로 대부분의 메서드 매개 변수에 대해 null 을 전달 합니다. 마지막 두 매개변수는 호출 시간 제한과 이것이 Watch 호출 인지 여부를 지정하므로 모든 listXXX 호출과 관련이 있습니다. 메서드의 서명을 확인하면 나머지 인수가 표시됩니다.
public V1NodeList listNode(
String pretty,
Boolean allowWatchBookmarks,
String _continue,
String fieldSelector,
String labelSelector,
Integer limit,
String resourceVersion,
String resourceVersionMatch,
Integer timeoutSeconds,
Boolean watch) {
// ... method implementation
}
이 빠른 소개에서는 페이징, 감시 및 필터 인수를 무시합니다. 이 경우 반환 값은 반환된 문서의 Java 표현이 포함된 POJO입니다 . 이 API 호출의 경우 문서에는 각 노드에 대한 여러 정보가 있는 V1Node 개체 List이 포함되어 있습니다. 다음은 이 코드에 의해 콘솔에서 생성되는 일반적인 출력입니다.
class V1Node {
metadata: class V1ObjectMeta {
labels: {
beta.kubernetes.io/arch=amd64,
beta.kubernetes.io/instance-type=k3s,
// ... other labels omitted
}
name: rancher-template
resourceVersion: 29218
selfLink: null
uid: ac21e09b-e3be-49c3-9e3a-a9567b5c2836
}
// ... many fields omitted
status: class V1NodeStatus {
addresses: [class V1NodeAddress {
address: 192.168.71.134
type: InternalIP
}, class V1NodeAddress {
address: rancher-template
type: Hostname
}]
allocatable: {
cpu=Quantity{number=1, format=DECIMAL_SI},
ephemeral-storage=Quantity{number=18945365592, format=DECIMAL_SI},
hugepages-1Gi=Quantity{number=0, format=DECIMAL_SI},
hugepages-2Mi=Quantity{number=0, format=DECIMAL_SI},
memory=Quantity{number=8340054016, format=BINARY_SI},
pods=Quantity{number=110, format=DECIMAL_SI}
}
capacity: {
cpu=Quantity{number=1, format=DECIMAL_SI},
ephemeral-storage=Quantity{number=19942490112, format=BINARY_SI},
hugepages-1Gi=Quantity{number=0, format=DECIMAL_SI},
hugepages-2Mi=Quantity{number=0, format=DECIMAL_SI},
memory=Quantity{number=8340054016, format=BINARY_SI},
pods=Quantity{number=110, format=DECIMAL_SI}}
conditions: [
// ... node conditions omitted
]
nodeInfo: class V1NodeSystemInfo {
architecture: amd64
kernelVersion: 4.15.0-135-generic
kubeProxyVersion: v1.20.2+k3s1
kubeletVersion: v1.20.2+k3s1
operatingSystem: linux
osImage: Ubuntu 18.04.5 LTS
// ... more fields omitted
}
}
}
보시다시피 사용 가능한 정보가 상당히 많습니다. 비교를 위해 다음은 기본 설정이 있는 동등한 kubectl 출력입니다.
root@rancher-template:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
rancher-template Ready control-plane,master 24h v1.20.2+k3s1
6. 결론
이 기사에서는 Java용 Kubernetes API에 대한 간략한 소개를 제공했습니다. 향후 기사에서는 이 API를 자세히 살펴보고 다음과 같은 몇 가지 추가 기능을 살펴보겠습니다.
- 사용 가능한 API 호출 변형 간의 차이점 설명
- Watch 를 사용하여 클러스터 이벤트를 실시간으로 모니터링
- 페이징을 사용하여 클러스터에서 대량의 데이터를 효율적으로 검색하는 방법
늘 그렇듯이 예제의 전체 소스 코드는 GitHub 에서 찾을 수 있습니다 .