아래 포스팅과 내용이 이어집니다!
앰배서더 컨테이너를 이용한 API 서버 통신 간소화
HTTPS, 인증서, 인증 토큰을 다루는 일은 때때로 너무 복잡해 보일 때가 있습니다. 종종 서버 인증서의 유효성 검사를 비활성화하는 경우를 많이 있습니다. 실제로 이러한 사유로 공겨을 당해 보안 이슈가 공개 되는 경우도 있었구요. 다행히 보안을 유지하면서 통신을 훨씬 간단하게 만들 수 있는 방법이 있습니다.
바로 전 포스팅에서 kubectl proxy 명령을 다루었습니다. API 서버에 좀 더 쉽게 액세스할 수 있도록 로컬 컴퓨터에서 명령을 실행했습니다. API 서버로 직접 요청을 보내는 대신 프록시로 요청을 보내 인증, 암호화 및 서버 검증을 처리하게 합니다. 파드 내에서도 동일한 방법을 사용할 수 있습니다.
앰배서더 컨테이너 패턴 소개
API 서버를 쿼리해야 하는 애플리케이션이 있다고 가정하고 이전에 proxy를 다루었던 것처럼 API 서버와 직접 통신하는 대신 메인 컨테이너 옆의 앰배서더 컨테이너에서 kubectl proxy를 실행하고 이를 통해 API 서버와 통신할 수 있습니다.
API 서버와 직접 통신하는 대신 메인 컨테이너의 애플리케이션은 HTTPS 대신 HTTP 로 앰배서더에 연결하고 앰배서더 프록시가 API 서버에 대한 HTTPS 연결을 처리하도록 해 보안을 투명하게 관리할 수 있습니다. 시크릿 볼륨에 있는 default-token 파일을 사용해 이를 수행할 수 있습니다. 파드의 모든 컨테이너는 동일한 루프백 네트워크 인터페이스를 공유하므로 애플리케이션은 localhost의 포트로 프록시에 액세스할 수 있습니다.
추가적인 앰배서더 컨테이너를 사용한 curl 파드 실행
앰배서더 컨테이너 패턴을 실제로 보려면 앞에서 만든 curl 파드와 같은 파드를 새로 생성 해야 하지만, 이번에는 파드에서 단일 컨테이너를 실행하는 대신 제가 공부하고 있는 책의 저자가 이미 만들어서 도커 허브에 푸시해놓은 다목적 kubect1-proxy 컨테이너 이미지를 기반으로 추가적인 앰배서더 컨테이너를 실행하겠습니다. 직접 빌드하려는 경우 코드 아카이브(/Chapter08/kubectl_ proxy/)에서 이미지의 Dockerfile을 찾을 수 있을 것입니다.
파드의 매니페스트는 다음 예제와 같습니다.
예제 1) 앰배서더 컨테이너가 있는 파드: curl-with-ambassador.yml
apiVersion: v1
kind: Pod
metadata:
name: curl-with-ambassador
spec:
containers:
- name: main
image: tutum/curl
command: ["sleep", "9999999"]
- name: ambassador # kubectl-proxy 이미지를 실행하는 앰배서더 컨테이너
image: luksa/kubectl-proxy:1.6.2
파드 스펙은 이전과 거의 동일하지만 파드 이름과 추가적인 컨테이너가 다릅니다. 파드를 실행한 다음 main 컨테이너로 들어갑니다.
$ kubectl exec -it curl-with-ambassador -c main bash
root@curl-with-ambassador:/#
이제 파드에는 두 개의 컨테이너가 있으며 main 컨테이너에서 bash를 실행하려면 -c main 옵션이 필요합니다. 파드의 첫 번째 컨테이너에서 명령을 실행하려는 경우 컨테이너를 명시적으로 지정할 필요는 없습니다. 그러나 다른 컨테이너 내에서 명령을 실행하려면 -c 옵션 을 사용해 컨테이너 이름을 지정해야 합니다.
앰배서더를 통한 API 서버와의 통신
이제 앰배서더 컨테이너로 API 서버에 접속할 수 있습니다. 기본적으로 kubectl proxy는 포트 8001에 바인딩되며, 파드의 두 컨테이너 모두 루프백을 포함해 동일한 네트워크 인터페이스를 공유하므로 다음 예제와 같이 curl로 localhost:8001에 접속할 수 있다.
예제 2) 앰배서더 컨테이너로 API 서버 액세스하기
root@curl-with-ambassador:/# curl localhost:8001
"paths": [
"/api",
...
]
}
curl로 출력된 결과는 앞에서 본 것과 동일한 응답이지만 이번에는 인증 토큰 및 서버 인증서를 처리할 필요가 없습니다.
정확히 무슨 일이 일어났는지 명확하게 파악하려면 아래 그림을 보면 이해가 쉬울 것입니다. curl은 (인증 헤더 없이) 일반 HTTP 요청을 앰배서더 컨테이너 내에서 실행 중인 프록시로 전송한 다음, 프록시는 HTTPS 요청을 API 서버로 전송하며, 토큰을 전송해 클라이언트 인증을 처리하 고 서버의 인증서를 검증해 서버의 신원을 확인합니다.
이것은 외부 서비스에 연결하는 복잡성을 숨기고 메인 컨테이너에서 실행되는 애플리케이션을 단순화하기 위해 앰배서더 컨테이너를 사용하는 좋은 예시입니다. 앰배서더 컨테이 너는 메인 애플리케이션의 언어에 관계없이 여러 애플리케이션에서 재사용할 수 있습니다. 단점은 추가 프로세스가 실행 중이고 추가 리소스를 소비한다는 것입니다.
클라이언트 라이브러리를 사용해 API 서버와 통신
애플리케이션이 API 서버와 간단한 몇 가지 작업만 수행하면 되는 경우, 특히 이전 예제에 서 했던 방식과 같이 kubectl-proxy 앰배서더 컨테이너를 이용하면 일반적인 HTTP 클라이언트 라이브러리를 사용해서 간단히 HTTP 요청을 수행할 수 있습니다. 그러나 단순한 API 요청 이상을 수행하려면 쿠버네티스 API 클라이언트 라이브러리 중 하나를 사용하는 것이 좋습니다.
클라이언트 라이브러리 사용
현재 API Machinery SIG Special Interest Group에서 지원하는 Kubernetes API 클라이언트 라이브러리는 두 가지가 있습니다.
- Golang 클라이언트: https://github.com/kubernetes/client-go
- Python: https://github.com/kubernetes-incubator/client-python/
공식적으로 지원되는 두 개의 라이브러리 외에도 다른 여러 언어에 관한 사용자 제공 클라이언트 라이브러리 목록이 다음과 같이 있습니다.
- Java client by Fabric8: https://github.com/fabric8io/kubernetes-client madu)
- Java client by Amdatu: https://bitbucket.org/amdatulabs/amdatu-kubernetes
- Node.js client by tenxcloud: https://github.com/tenxcloud/node-kubernetes-client
- Node.js client by GoDaddy: https://github.com/godaddy/kubernetes-client
- PHP: https://github.com/devstub/kubernetes-api-php-client
- Another PHP client: https://github.com/maclof/kubernetes-client
- Ruby: https://github.com/Ch00k/kubr
- Another Ruby client: https://github.com/abonas/kubeclient
- Clojur: https://github.com/yanatan16/clj-kubernetes-api
- Scala: https://github.com/doriordan/skuber
- Perl: https://metacpan.org/pod/Net::Kubernetes
이 라이브러리는 일반적으로 HTTPS를 지원하고 인증을 관리하므로 앰배서더 컨테이너를 사용할 필요가 없습니다. 이 외에도 쿠버네티스 커뮤니티에는 쿠버네티스의 특정 영역에 초점을 맞춘 다수의 SIG와 워킹 그룹 (Working Group)이 있습니다. https://github.com/kubernetes/community/blob/master/sig-list.md에서 목록을 찾을 수 있습니다.
Fabric Java Client를 사용한 쿠버네티스와의 상호작용 예시
클라이언트 라이브러리를 사용해 API 서버와 통신하는 방법을 이해하기 위해 다음 예제는 Fabric쿠버네티스 클라이언트를 사용해 Java 애플리케이션에서 서비스를 나열하는 예시를 보여줍니다.
예제 3) Fabric8 Java client를 사용한 파드의 나열, 생성, 업데이트, 삭제
import java.util.Arrays;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
public class Test {
public static void main(String[] args) throws Exception {
KubernetesClient client = new DefaultKubernetesClient();
// List pods in the default namespace
PodList pods = client.pods().inNamespace("default").list();
pods.getItems().stream()
.forEach(s -> System.out.println("Found pod: " + s.getMetadata().getName()));
// Create a pod
System.out.println("Creating a pod");
Pod pod = client.pods().inNamespace("default")
.createNew()
.withNewMetadata()
.withName("programmatically-created-pod")
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName("main")
.withImage("busybox")
.withCommand(Arrays.asList("sleep", "99999"))
.endContainer()
.endSpec()
.done();
System.out.println("Created pod: " + pod);
// Edit the pod (add a label to it)
client.pods().inNamespace("default")
.withName("programmatically-created-pod")
.edit()
.editMetadata()
.addToLabels("foo", "bar")
.endMetadata()
.done();
System.out.println("Added label foo=bar to pod");
System.out.println("Waiting 1 minute before deleting pod...");
Thread.sleep(60000);
// Delete the pod
client.pods().inNamespace("default")
.withName("programmatically-created-pod")
.delete();
System.out.println("Deleted the pod");
}
}
Fabric8 클라이언트는 훌륭하고 유창한 도메인 특화 언어(DSL, Domain-Specific-Language) API를 제공하기 때문에 코드를 자체적으로 설명되도록 작성해야 합니다. 또한 가독성이 좋고 이해하기 쉽습니다.
스웨거와 OpenAPI를 사용해 자신의 라이브러리 구축
선택한 프로그래밍 언어에 사용할 수 있는 클라이언트가 없는 경우 스웨거 Swagger API 프 레임워크를 사용해 클라이언트 라이브러리와 문서를 생성할 수 있다. 쿠버네티스 API 서버는/swaggerapi에서 스웨거 API 정의를 공개하고 /swagger.json에서 OpenAPI 스펙을 공개합니다.
스웨거 프레임워크에 대한 자세한 내용을 보려면 웹사이트(http://swagger.io)를 방문하여 확인할 수 있습니다.
스웨거 UI로 API 살펴보기
이전 포스팅 앞부분에서 curl을 이용해 REST 엔드포인트에 접속하는 대신, REST API를 탐색하는 더 좋은 방법을 알려준다고 언급했습니다. 이전 절에서 언급한 스웨거는 API를 설정하기 위한 도구일 뿐만 아니라 스웨거 API 정의를 공개하는 경우 REST API를 탐색하기 위한 웹 UI도제공합니다. 이 UI로 REST API를 더 나은 방식으로 탐색할 수 있습니다.
쿠버네티스는 스웨거 API가 공개돼 있는 데다가 API 서버에 스웨거 UI도 통합돼 있지만 기본적으로 활성화돼 있진 않습니다. API 서버를 --enable-swagger-ui=true 옵션으로 실 행하면 활성화할 수 있습니다. UI를 활성화한 후 브라우저에서 다음 URL로 접속해 UI를 실행할 수 있습니다.
http(s)://<api 서버>: <port>/swagger-ui
스웨거 UI를 사용해보셨으면 합니다. 쿠버네티스 API를 탐색할 수 있을 뿐만 아니라 API MA 와 상호작용할 수도 있습니다(예를 들어, JSON 리소스 매니페스트를 POST하고 리소스를 PATCH 또는 DELETE할 수 있다).
이번 포스팅은 여기서 마무리하도록 하겠습니다. 끝까지 읽어주셔서 감사합니다!
'Container > Kubernetes' 카테고리의 다른 글
[Kubernetes] 쿠버네티스 API와 사용방법 (1) (2) | 2023.05.27 |
---|---|
[Kubernetes] Downward API와 메타데이터(2) (2) | 2023.05.27 |
[Kubernetes] Downward API와 메타데이터(1) (0) | 2023.05.27 |
[Kubernetes Secrets] 쿠버네티스 시크릿(Secret)이란? (0) | 2023.04.17 |
[Kubernetes Configmap] 컨피그맵이란? (2) (0) | 2023.04.16 |