⭐ 가시다(gasida) 님이 진행하는 AWS EKS Workshop 실습 스터디 게시글입니다.
AWS 키 페어 생성하기
- 필요한 이유: CloudFormation 으로 K8s 관련 실습환경을 배포할때 사용한다!
- 키페어 유형: RSA
- 프라이빗 키 파일 형식: .pem (with OpenSSH)
클라우드 스택 포메이션
- 필요: 기본실습환경 배포
- 링크: https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-2#/stacks/new?stackName=myeks&templateURL=https:%2F%2Fs3.ap-northeast-2.amazonaws.com%2Fcloudformation.cloudneta.net%2FK8S%2Fmyeks-1week.yaml
- 설정:
- 키페어: 위에서 설정한 키페어
- SgIngressSshCidr: {네이버에 “내 ip주소 조회” 검색해서 나온 값}/32 넣기(공인아이피)
- MyInstanceType: 여기서 말하는 MyInstance 는 워커노드에 붙여저있는 작업용EC2 를 의미함(영어로는 bastion)
- 나머지는 건들지 말고 다음 → 다음 → 전송
CREATE_COMPLETE 라는 메세지가 보이면 배포완료된것이다.
- EC2 인스턴스 항목 접근: myeks-host 이름을 가진 instance 가 생성됨.
AWS EKS 구성
기본 K8s 구성 : Control Plane + Node Component
EKS?
EKS 는 K8s에서 Control Plane 을 관리해 주는 서비스이며, 이를 AWS Managed VPC 라고 구분하여 지칭한다.
또한 Autoscaling 기능을 제공해준다. EKS는 여러개의 AZ(Availablity Zone)으로 구성하여 사용한다.
EKS 로 kubectl 명령어를 사용한다면 네트워크플로우는
NLB 를 통해서 Control Plane 에 접근(앞단) → API Server 와 통신 → ELB 를 통해서 Etcd 에 접근
처럼 진행된다.
명령을 내리는 Control Plane 이 존재한다면, Pod가 작동하는 Node Component도 존재한다.
- 위에서 EKS 는 AWS Managed VPC 라고 지칭했는데, Node Component는 Your VPC(사용자, User) 라고 지칭한다.
AWS VPC의 AZ에 대응하는 Your(User) VPC의 AZ도 존재한다.
이때 하나 주의할점은, User VPC의 AZ에 AWS VPC 가 통신하기 위한 ENI인터페이스(Elastic Network Interface)가 있는데, 여기있는 ENI 의 소유권자는 User가 아닌, EKS 로 설정되어있다는것이다.
기본적으로 Node Component의 소유권은 User 이지만, 이유는 사용자가 Node Component에 직접 통신하지 않기 때문이다.
User는 EKS 가 제공하는 Kube Apiserver 에 통신하여, Kube Apiserver가 NodeComponent에 접근한다.
User 는 Node Component 를 소유하지만, Node Component에 직접 접근하지 않는다.
그러나 Node Component 의 ENI는 EKS소유이다.
따라서 EKS의 책임관리 영역을 구분해보자면,
Control Plane 은 AWS 의 영역
Node Component 는 User, AWS 의 영역으로 구분된다.
EKS 에서 API부하분산할때 NLB를 사용하는 이유, ALB를 사용하지 않는이유
ALB(Appplication Load Balancer)
ALB는 네트워크에서 Application Layer계층(7계층) 에서 작동하며, HTTP/HTTPS 트래픽을 처리한다.
일반적으로 고급라우팅, 트래픽 라우팅 등의 기능을 제공한다.
NLB(Network Load Balancer)
NLB는 네트워크에서 Transport Layer계층(4계층) 에서 작동하며, TCP,UDP, TLS 트래픽을 처리한다.
매우빠르다.
왜 NLB를 사용하는가?
- NLB 는 4계층에서 작동하여, ALB보다 낮은지연시간, 높은처리량을 제공한다.
- NLB는 TCP연결을 직접타겟해서 전달할 수 있으므로, Kubernetes API 서버의 트래픽을 효율적으로 라우팅할 수 있다.
결론: ALB보다 NLB가 조금 더 효율적으로 작동하기때문이다.
AWS CLI 자격증명 생성
- AWS IAM 사이트(https://us-east-1.console.aws.amazon.com/iam/home?region=ap-northeast-2#/users ) 에 들어가서 Administrator Policy 권한을 가진 IAM USER 생성하기
이렇게 선택하고 다음→다음 누르다보면 IAM 만들어지는데
여기서 액세스 키 만들기 선택 → 사용사례(Command Line Interface) → 선택
⭐여기서 나오는 ACCESS Key, PW 저장해두기!
하단 aws configure 할때 사용한다.
aws cli 자격증명
aws configure
#위에서 생성한 IAM 내용을 입력함
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: ap-northeast-2
Default output format [None]: json
자격증명 잘 되었는지 확인하는 방법
aws ec2 describe-instances
이 명령어를 입력했을때
An error occurred (AuthFailure) when calling the DescribeInstances operation: AWS was not able to validate the provided access credentials 가 출력되면, 제대로 자격증명이 되지 않은것
여러가지 json 내용 이 출력되면, 제대로 자격증명이 된 것이다.
VPC정보확인
#vpc 정보확인
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq
#VPC ID확인 및, 빈번히 사용하는만큼 /etc/profile에 등록
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId)
echo "export VPCID=$VPCID" >> /etc/profile
echo $VPCID
#배포할 subnet 정보확인
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" | jq
#서브넷 ID확인, /etc/profile에 등록
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
echo "export PubSubnet1=$PubSubnet1" >> /etc/profile
echo "export PubSubnet2=$PubSubnet2" >> /etc/profile
echo $PubSubnet1
echo $PubSubnet2
EKSCTL 실습
EKS 를 배포할때 사용하는 CLI 툴이다.
# 변수 확인
echo $AWS_DEFAULT_REGION
echo $CLUSTER_NAME
echo $VPCID
echo $PubSubnet1,$PubSubnet2
모니터링 창 띄우기(동일한 서버에 접근해서)
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done
(myeks-host 만 존재하는 상태)
배포 전 확인
- --dry-run 명령어를 사용하면 실제로 배포하지않은 상태에서, 배포되었을때의 결과값을 출력하여 확인할 수 있다.
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.28 --ssh-access --external-dns-access --dry-run | yh
배포하기
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.28 --ssh-access --external-dns-access --verbose 4
(배포중인 화면, 대략 15분 정도 걸림)
(배포완료된 화면, 하단 모니터링 화면에서 노드그룹 2개가 생성된 것을 확인가능하다)
(EKS 화면)
EKS 정보 확인
# 기존 설치된 명령어
kubectl krew list
# eks클러스터 정보 확인
kubectl cluster-info
Kubernetes control plane is running at https://9773F48197FF6031A83C14C2AA6D1164.gr7.ap-northeast-2.eks.amazonaws.com
CoreDNS is running at https://9773F48197FF6031A83C14C2AA6D1164.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
# 혹은 아래명령어로도 확인가능
aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint
이때 출력되는 control plane 주소는 EKS클러스터 화면에서도확인가능하다.
## dig 조회 : 해당 IP 소유 리소스는 어떤것일까요?
APIDNS=$(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint | cut -d '/' -f 3)
dig +short $APIDNS
출력 결과물로 확인해보면
15.165.156.210 43.203.74.28
가 출력되는데, 해당 IP는 Public Endpoint 주소임을 명심해야한다
(Public IP 가 노출되어있다는건, EKS가 Public IP 로 배포되었다는 뜻이다)
# eks API 접속 시도 : 도메인 or 출력되는 ip 주소로 https://<IP>/version 외부에서도 접속 가능!
#실패함
curl -k -s $(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint)
#성공
curl -k -s $(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint)/version | jq
# eks 노드 그룹 정보 확인
eksctl get nodegroup --cluster $CLUSTER_NAME --name $CLUSTER_NAME-nodegroup
aws eks describe-nodegroup --cluster-name $CLUSTER_NAME --nodegroup-name $CLUSTER_NAME-nodegroup | jq
# 노드 정보 확인 : OS와 컨테이너런타임 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
##result
NAME STATUS ROLES AGE VERSION INSTANCE-TYPE CAPACITYTYPE ZONE
ip-192-168-1-6.ap-northeast-2.compute.internal Ready <none> 26m v1.28.5-eks-5e0fdde t3.medium ON_DEMAND ap-northeast-2a
ip-192-168-2-219.ap-northeast-2.compute.internal Ready <none> 26m v1.28.5-eks-5e0fdde t3.medium ON_DEMAND ap-northeast-2c
# -v=6 으로 디버그 레벨을 높여서 확인
kubectl get node -v=6
##result
I0309 22:35:09.204142 19608 loader.go:395] Config loaded from file: /root/.kube/config
I0309 22:35:10.243696 19608 round_trippers.go:553] GET https://9773F48197FF6031A83C14C2AA6D1164.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 200 OK in 1022 milliseconds
NAME STATUS ROLES AGE VERSION
ip-192-168-1-6.ap-northeast-2.compute.internal Ready <none> 29m v1.28.5-eks-5e0fdde
ip-192-168-2-219.ap-northeast-2.compute.internal Ready <none> 29m v1.28.5-eks-5e0fdde
EKS 의 Public API 값을 찔러서 가져오는데, /root/.kube/config 값을 먼저 로드한다.
해당 파일은 인증정보와 관련되어있다는 정보만 알아두면된다.
#인증정보
cat /root/.kube/config
#pod확인
kubectl get pod -A
이때 API-server, Controller, Scheduler 파드가 안보이는 이유
- Control Plane 영역은 User의 영역이아닌, AWS EKS의 영역이므로, 굳이 사용자에게 보여줄 필요가 없다.
컨테이너 정보확인
kubectl get pod -n kube-system -o wide
IP 대역에서 192.168.2.x 대역과 192.168.1.x 대역으로 구분되는데
On-premise의 쿠버네티스 IP 에서는 Worker node의 Instance IP, Pod의 IP 가 다른 대역을 사용한다.
EKS의 쿠버네티스 IP 에서는 Workder node의 Instance IP, Pod의 IP가 같은 대역을 사용한다.
- 이유 : AWS VPC CNI 때문(자세한 이유는 나중에 설명)
노드 정보
#현재 노드 정보 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
echo $N1, $N2
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile
ping -c 1 $N1
ping -c 1 $N2
- ping 을 날렸을때 안되는 이유 : 접속가능한 보안그룹이 설정되어있지 않기때문이다.
현재 상황으로 설명
- Bastion(작업용) EC2 에는 워커노드의 관련 인증서, Kubectl, 기타 플러그인 등이 설치되어있다.
- 그러나 Bastion EC2 에는 워커노드로 ssh접근(TCP통신) 을 하기위한 보안그룹이 설정되어있지 않았다.
- 따라서 Bastion EC2에서 워커노드로 ssh 접근이 불가능한 상태였다.
# 노드 보안그룹 ID 확인
aws ec2 describe-security-groups --filters Name=group-name,Values=*nodegroup* --query "SecurityGroups[*].[GroupId]" --output text
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*nodegroup* --query "SecurityGroups[*].[GroupId]" --output text)
echo $NGSGID
echo "export NGSGID=$NGSGID" >> /etc/profile
# 노드 보안그룹에 eksctl-host 에서 노드(파드)에 접속 가능하게 룰(Rule) 추가 설정
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
- 모든 프로토콜 접근이 가능하게 보안그룹 룰 설정
# eksctl-host 에서 노드의IP나 coredns 파드IP로 ping 테스트
ping -c 2 $N1
ping -c 2 $N2
# 워커 노드 SSH 접속
ssh -i ~/.ssh/id_rsa ec2-user@$N1 hostname
ssh -i ~/.ssh/id_rsa ec2-user@$N2 hostname
ssh ec2-user@$N1
exit
ssh ec2-user@$N2
exit
노드정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ip -c addr; echo; done
노드그룹cgroup 버전확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i stat -fc %T /sys/fs/cgroup/; echo; done
노드프로세스정보확인
#kubelet
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo systemctl status kubelet; echo; done
#process
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo pstree; echo; done
#detail하게 봐야할때
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ps afxuwww; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ps axf |grep /usr/bin/containerd; echo; done
#manifests
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ls /etc/kubernetes/manifests/; echo; done
#kubelet
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ls /etc/kubernetes/kubelet/; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i cat /etc/kubernetes/kubelet/kubelet-config.json; echo; done
노드 스토리지 정보
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i lsblk; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i df -hT /; echo; done
EKS Owned ENI
#kubelet 은 kube-proxy와 어떻게 통신할까?
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ss -tnp; echo; done
##result
(jjongiam@myeks:N/A) [root@myeks-host ~]# for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ss -tnp; echo; done
>> node 192.168.1.6 <<
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB 0 0 192.168.1.6:57874 15.165.156.210:443 users:(("kubelet",pid=2933,fd=14))
ESTAB 0 0 192.168.1.6:56938 52.95.195.109:443 users:(("ssm-agent-worke",pid=2467,fd=14))
ESTAB 0 0 192.168.1.6:36390 10.100.0.1:443 users:(("controller",pid=3799,fd=11))
ESTAB 0 0 192.168.1.6:59584 43.203.74.28:443 users:(("kube-proxy",pid=3147,fd=7))
ESTAB 0 0 192.168.1.6:53882 10.100.0.1:443 users:(("aws-k8s-agent",pid=3397,fd=7))
ESTAB 0 0 192.168.1.6:34254 52.95.194.54:443 users:(("ssm-agent-worke",pid=2467,fd=10))
ESTAB 0 56 192.168.1.6:22 192.168.1.100:51372 users:(("sshd",pid=19427,fd=3),("sshd",pid=19395,fd=3))
>> node 192.168.2.219 <<
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB 0 0 192.168.2.219:22 192.168.1.100:34438 users:(("sshd",pid=19122,fd=3),("sshd",pid=19090,fd=3))
ESTAB 0 0 192.168.2.219:37714 43.203.74.28:443 users:(("kube-proxy",pid=3152,fd=7))
ESTAB 0 0 192.168.2.219:56812 15.165.156.210:443 users:(("kubelet",pid=2938,fd=24))
ESTAB 0 0 192.168.2.219:34338 52.95.195.109:443 users:(("ssm-agent-worke",pid=2486,fd=14))
ESTAB 0 0 192.168.2.219:59962 52.95.194.65:443 users:(("ssm-agent-worke",pid=2486,fd=10))
ESTAB 0 0 192.168.2.219:51266 10.100.0.1:443 users:(("controller",pid=3561,fd=11))
ESTAB 0 0 192.168.2.219:60188 10.100.0.1:443 users:(("aws-k8s-agent",pid=3404,fd=7))
kubelet과 kubeproxy 는 43.203.74.28:443, 15.165.156.210:443 에 연결되어있는데
이 값은 dig +short $APIDNS 로도 확인 가능한 값이다.
이건 EKS 퍼블릭 엔드포인트로 보이는 주소인
https://9773F48197FF6031A83C14C2AA6D1164.gr7.ap-northeast-2.eks.amazonaws.com
값이다.
아래그림에서 보이다시피 (Default 배포: Public only) 전체적인 network flow 는 3가지로 구분된다.
- EKS Cluster Endpoint - Public : 제어부 → (EKS owned ENI) 워커노드 kubelet, 워커노드 → (퍼블릭 도메인) 제어부, 사용자 kubectl → (퍼블릭 도메인) 제어부
kubelet,kube-proxy 는 API server 로 어떻게 통신하냐면
Internetgateway → Public IP 의 공인IP로 접근 → API Server
여기서 주목할 점 : Public 으로 배포한 EKS 는 kubelet, kube-proxy 도 Public IP로 연결된다.(굳이 그럴필요 없는데)
# [터미널] aws-node 데몬셋 파드 1곳에 bash 실행해두기
kubectl exec daemonsets/aws-node -it -n kube-system -c aws-eks-nodeagent -- bash
# exec 실행으로 추가된 연결 정보의 Peer Address는 어딘인가요? >> AWS 네트워크 인터페이스 ENI에서 해당 IP 정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ss -tnp; echo; done
...
ESTAB 0 0 [::ffff:192.168.1.129]:10250 [::ffff:192.168.1.7]:38238 users:(("kubelet",pid=2933,fd=9))
...
네트워크 인터페이스 항목 확인
네트워크 인터페이스의 소유자, 요청자ID가 다른것을 확인이 가능하다.
여기서 알아야하는 것(통신경로)
- kubectl exec, log 로 확인할때의 흐름: User - Public IP - API server - EKS owned ENI - pod
- 네트워크 인터페이스 소유자 : User
- 네트워크 인터페이스 요청자, 인스턴스 소유자 : AWS EKS
- ref: https://kubernetes.io/docs/concepts/architecture/control-plane-node-communication
Communication between Nodes and the Control Plane
This document catalogs the communication paths between the API server and the Kubernetes cluster. The intent is to allow users to customize their installation to harden the network configuration such that the cluster can be run on an untrusted network (or
kubernetes.io
만약 EKS Endpoint 를 Public, Private 으로 설정한다면
- EKS Cluster Endpoint - Public Private : 제어부 → (EKS owned ENI) 워커노드 kubelet, 워커노드 → (프라이빗 도메인, EKS owned ENI) 제어부, 사용자 kubectl → (퍼블릭 도메인) 제어부
worker node 에서 API Server 로 연결하는 플로우가
before: worker node(kubelet, kube-proxy) → Internal gateway → API Server
after: worker node(kubelet, kube-proxy) → EKS owned ENI
이때의 핵심은 Workernode → Control Plane 으로 접근할때는 PRIVATE 설정 되었지만
사용자가 kubectl 로 접근할때에는 PRIVATE 로 접근한다는 것이다.
만약 EKS Endpoint 를 PRIVATE으로 설정한다면
- EKS Cluster Endpoint - Private : 제어부 → (EKS owned ENI) 워커노드 kubelet, 워커노드,사용자 kubectl → (프라이빗 도메인, EKS owned ENI) 제어부
kubectl 도 EKS owned ENI 로 통신할 수 있게된다.
선언형 실습
# 터미널1 (모니터링)
watch -d 'kubectl get pod'
# 터미널2
# Deployment 배포(Pod 3개)
kubectl create deployment my-webs --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --replicas=3
kubectl get pod -w
# 파드 증가 및 감소
kubectl scale deployment my-webs --replicas=6 && kubectl get pod -w
kubectl scale deployment my-webs --replicas=3
kubectl get pod
# 강제로 파드 삭제 : 바라는상태 + 선언형에 대한 대략적인 확인! ⇒ 어떤 일이 벌어지는가?
kubectl delete pod --all && kubectl get pod -w
kubectl get pod
# 실습 완료 후 Deployment 삭제
kubectl delete deploy my-webs
마리오 배포 테스트
# 터미널1 (모니터링)
watch -d 'kubectl get pod,svc'
# 수퍼마리오 디플로이먼트 배포
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/1/mario.yaml
kubectl apply -f mario.yaml
cat mario.yaml | yh
# 배포 확인 : CLB 배포 확인
kubectl get deploy,svc,ep mario
# 마리오 게임 접속 : CLB 주소로 웹 접속
kubectl get svc mario -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Maria URL = http://"$1 }'
⭐실습 종료 후 리소스제거
#EKS 제거
eksctl delete cluster --name $CLUSTER_NAME
#CloudFormation제거
aws cloudformation delete-stack --stack-name myeks
'외부활동' 카테고리의 다른 글
[AEWS] 2기 스터디: EKS Storage 에 대해서 (1) | 2024.03.24 |
---|---|
[AEWS] 2기 스터디: AWS VPC + ALB (3) | 2024.03.17 |
코딩테스트 준비 플랫폼 추천: 코드트리 (0) | 2024.03.03 |
[DOIK2] 스터디: Stackable 로 Airflow 배포하기 + 스터디후기 (3) | 2023.11.26 |
[DOIK2] 스터디: Strimzi로 Kafka Cluster 배포하기 (0) | 2023.11.18 |