EKS는 제대로 써본적이 없어서 이번에 한번 공부해봐야겠다 싶어 신청했는데 좋은 기회가 왔다. aws 워크샵을 토대로 여러 쟁쟁한 분들께서 참여&도움주시는 스터디다.
유튜브부터 각종 커뮤니티에서 활동하시는 정
말 현업에서 쟁쟁하신분들께서 함께 공유에 힘쓰는 모습이 멋있다는 생각이 든다.

특히 유튜브 악분일상님보고 너무 반가웠다. 개인적으로 공부법이 자기전에 그냥 틀어놓고 자는건데 악분일상님 유튜브 많이 틀어놓는데.. 혼자서 반가웠다.

여튼 알려주신 회사동료와 좋은 교육을 제공해주시는 모든 분들께 감사인사를 표해야겠다.

 

 

이 글의 목표
eks교육 1주차를 듣고... 내가 아는 IT 지인들중 쿠버네티스(EKS) 이름만 들어보고 뭔지 모르는 사람들이 이 글을 읽고 언제 어떻게 왜 써야 하는지 알게끔 하기.
최대한 간략하고 이해하기 쉽게 쓰기.

 

시작.

1. EKS란 

AWS에서 제공하는 쿠버네티스 서비스.
쿠버네티스란 컨테이너가 한두개면 상관없는데 너~무 많아지면서(컨테이너당 서비스 하나가 표준) 컨테이너 관리가 어려워졌다. 그래서 나온게 k8s.
k8s란 컨테이너 오케스트레이션 도구. 컨테이너 인프라를 더 똑똑하게 효율적으로 잘 관리해주는 도구.
ㄴ똑똑하고 효율적이다 : 자원을 모니터링해서 오토힐링, 오토스케일링등

 

컨테이너란 ? https://kk-7790.tistory.com/135 참고

 

컨테이너를 왜쓰지 ? 
1. 서비스 이식성 - 어떤 OS건 도커등 컨테이너 실행환경만 갖춰진 OS라면 바로 실행이 가능하다. 
2. 빠른 복구 - 서비스 이식성이 좋기 때문에 서버 다운시 다른 서버로 빠르게 복구가 가능하다.
ㄴbefore : 기존 서버와 동일한 아파치,php, mysql 설치하고 설정파일 복사해서 붙여넣고 등등...
ㄴafter : 컨테이너만 기존꺼랑 맞게 실행해주면 끝(주기적으로 변경되는 데이터(DB등)은 당연히 리스토어해야함)

3. 배포 및 관리 단순화 - 통일된 인프라(도커 컨테이너라는)가 되기 때문에 오퍼레이터 입장에서 상당히 편해짐
ㄴbefore : OS별로 설치,배포방법 다름...
ㄴafter : OS위에 도커만 설치하면 그 뒤부터는 도커위에 컨테이너 올려서 사용. 

이외에도 여러 장점이 있음.


요약하자면
1. 컨테이너의 장점이 워낙 뚜렷하기때문에 현재 IT 인프라는 컨테이너 기반이 표준이 됐다.

2. 근데 관리해야할 컨테이너가 너무 많아짐에따라 관리도구가 필요했고 그게 K8S다.

3. EKS는 aws에서 제공하는 k8s 서비스

 

2. EKS와 쿠버네티스의 차이

쿠버네티스 - 온프레미스에 직접 설치해서 사용해야함. 그래서 쿠버네티스에 필요한 구성요소들. 컨트롤플레인등을 직접 설치하고 관리해줘야한다.

EKS - 관리에 필요한 구성요소들을 제외(aws에서 관리해줌)하고 실제 서비스 운영에 필요한 요소(워커노드)만 관리하면 된다. 

컨트롤플레인은 물론 데이터플레인중 일부까지도 aws에서 관리

예를들어 l7 로드밸런싱에 엔진엑스 리버스프록시서버 1대, 실제 서비스 서버2대 총 3대가 있을경우

k8s - 3대 모두 직접 구성하고 관리해줘야함. 특히 리버스 프록시 서버 도구 설치부터 설정, 이후 관리(고가용성등)까지.

EKS - 실제 운영되는 서버 2대만 관리하면됨. 그 2대도 aws에서 구축(ec2)해준다. 관리만 하면됨.

 

꼭 k8s(eks)를 써야하나...?

꼭 그렇진 않다. 클러스터가 필요하지 않은 환경. 대표적으로 접속자가 일정하고 한대의 서버에서 충분히 커버가 가능하고 어느정도의 다운타임(업무시간에 30분정도 ?)이 허용되는 환경이라면 k8s를 굳이 사용할필요는 없다. 컨테이너 환경으로도 충분하다.

그럼에도 k8s를 구축하면 좋은점은 소유한 서버들의 리소스를 최대한 효율적으로 사용할 수 있다. 반대로 k8s를 도입함으로써의 쓰이는 인적자원도 있고... 잘 생각해보고 도입하면 된다. 도입할 여건(운영지식)만 된다면 실보단 득이 더 많다고 본다.

 

4. EKS 아키텍처

용어 설명

controlplane(master node) -  k8s 클러스터를 제어노드

dataplane(worker node) - 실제 데이터(파드,볼륨등)이 쌓이고 자원(cpu, 메모리)이 사용되는 노드

kubectl - 쿠버네티스 제어 도구. eks의 경우 컨트롤플레인 서버에 직접 접속이 안되니까 외부에 kubectl 설치해서 컨트롤플레인(마스터노드)의 api server로 명령을 전달한다.

Scheduler - 새로운 파드를 상황에 맞게 노드에 할당하는 역할

API server - 모든 컴포넌트들사이에서 api 서버 역할을 하며 통신해주는 역할

etcd - 데이터 저장소

controller manager - 클러스터 상태를 감시(오토힐링, 오토스케일링을위한)하고 작업을 수행하는 역할

kubelet - 워커노드의 상태 관리

kube-proxy - 네트워크 역할

 

아키텍처를 알아봤으니 어떻게 동작하는지도 알아보자. deployment로 파드를 배포했을때의 동작과정은 다음과같다.

1. 파드 생성 - 사용자가 kubectl run 명령어 타이핑 엔터

2. kubectl에서 컨트롤플레인(마스터노드)의 apiserver에 전달

3-1. apiserver가 etcd에 생성에 관한 정보(unscheduled pod)를 etcd에 저장

3-2. 동시에 apiserver가 etcd에 deployment에 포함된 replicas에 관한 정보를 etcd에 저장

4. scheduler는 unscheduled pod를 감지

5. 이후 scheduler가 어떤 워커노드에 배포할지 확인

6. 정해진 노드를 apiserver에 전달

7. api서버는 그 노드를 etcd에 또 저장

8. kubelet이 api서버에서 해당 노드에 파드를 배포

 

최대한 간략하게 적었고 자세한건.

https://blog.eunsukim.me/posts/understanding-how-kubernetes-works

참고

 

개인적으로 쿠버네티스, eks나 깃랩이나 여러 솔루션, 도구들을 관리하는 서버 관리자라면 해당 도구들의 아키텍쳐와 주요 컴포넌트들. 그 컴포넌트들이 어떤일을 왜 하는지정도는 알아야 한다고 생각한다.

허나 개발자들이 클라우드 환경에서 사용한다면 알면 좋겠지만 몰라도 괜찮다고는 생각한다.(그래야 우리같은 엔지니어가 밥벌이를 하니까..) 여튼 개발자분들은 다른 컴포넌트들은 몰라도 되는데 알아야할건 apiserver이다.

어떤 컴포넌트들이건 무조건 apiserver 와 통신을 한다. 심지어 외부에서 접근할때도 apiserver 서버와 통신을한다. 

온프렘에 설치한 k8s를 컨트롤하기 위한 kubeadmin 명령어대신 K8s.domain.co.kr/api 로도 통신이 가능하다.

 

5. EKS 구축방법

 

 

 

  • 기본 인프라 배포 - 링크 ← AWS CloudFormation 페이지로 연결되며, 파라미터 입력 후 스택 실행
  • CLI 를 이용하여 배포 (CLI를 사용하기 위해선 aws confiure 설정이 완료되어야 한다)
# yaml 파일 다운로드
curl -O <https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/**myeks-1week.yaml**>

# 배포
# aws cloudformation deploy --template-file ~/Downloads/myeks-1week.yaml --stack-name mykops --parameter-overrides KeyName= SgIngressSshCidr=/32 --region <리전>
예시) aws cloudformation deploy --template-file ~/Downloads/**myeks-1week.yaml** \\
     --stack-name **myeks** --parameter-overrides KeyName=**kp-gasida** SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 EC2 IP 출력
aws cloudformation describe-stacks --stack-name **myeks** --query 'Stacks[*].Outputs[*].OutputValue' --output text
예시) 3.35.137.31

# ec2 에 SSH 접속
예시) ssh -i  **ec2-user**@3.35.137.31
ssh -i **~/.ssh/kp-gasida.pem** ec2-user@$(aws cloudformation describe-stacks --stack-name **myeks** --query 'Stacks[*].Outputs[0].OutputValue' --output text)
  • IAM User 자격 증명 설정 및 VPC 확인 및 변수 지정
# 자격 구성 설정 없이 확인
**aws ec2 describe-instances**

# IAM User 자격 구성 : 실습 편리를 위해 administrator 권한을 가진 IAM User 의 자격 증명 입력
**aws configure**
AWS Access Key ID [None]: ***AKIA5...***
AWS Secret Access Key [None]: ***CVNa2...***
Default region name [None]: ***ap-northeast-2***
Default output format [None]: json

# 자격 구성 적용 확인 : 노드 IP 확인
**aws ec2 describe-instances**

# EKS 배포할 VPC 정보 확인
**aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq**
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq Vpcs[]
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq Vpcs[].VpcId
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId
**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

****# EKS 배포할 VPC에 속한 Subnet 정보 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --output json | jq
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --output yaml | yh

****## 퍼블릭 서브넷 ID 확인
**aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" | jq**
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text
**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
  • Amazon EKS 배포 실습
# 변수 확인
echo $AWS_DEFAULT_REGION
echo $CLUSTER_NAME
echo $VPCID
echo $PubSubnet1,$PubSubnet2

# 옵션 [터미널1] EC2 생성 모니터링
#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
**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**

# eks 클러스터 & 관리형노드그룹 배포 전 정보 확인
**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.24 --ssh-access --external-dns-access --dry-run | yh**
...
**vpc**:
  autoAllocateIPv6: false
  cidr: 192.168.0.0/16
  clusterEndpoints:
    privateAccess: false
    publicAccess: true
  **id**: vpc-0505d154771a3dfdf
  manageSharedNodeSecurityGroupRules: true
  nat:
    gateway: Disable
  **subnets**:
    **public**:
      ap-northeast-2a:
        az: ap-northeast-2a
        cidr: 192.168.1.0/24
        id: subnet-0d98bee5a7c0dfcc6
      ap-northeast-2c:
        az: ap-northeast-2c
        cidr: 192.168.2.0/24
        id: subnet-09dc49de8d899aeb7
****
# eks 클러스터 & 관리형노드그룹 배포: 총 16분(13분+3분) 소요 
**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.24 --ssh-access --external-dns-access --verbose 4**
...
023-04-23 01:32:22 [▶]  setting current-context to admin@myeks.ap-northeast-2.eksctl.io
2023-04-23 01:32:22 [✔]  **saved kubeconfig as "/root/.kube/config"**
...

eks 클러스터 & 관리형노드그룹 배포 전

 

배포 완료

AWS CloudFormation 확인

 

AWS EKS 확인

 

Daemon Set pod를 통한 pod가 통신하는 ENI 확인

# 노드 IP 확인
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

# PrivateIP 변수 지정
N1=<PrivateIPAdd.myeks-myeks-nodegroup-Node1>
N2=<PrivateIPAdd.myeks-myeks-nodegroup-Node2>

# 노드 보안그룹 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

# 노드 보안그룹에 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

# kubelet, kube-proxy 통신 Peer Address 확인
ssh -i ~/.ssh/id_rsa ec2-user@$N1 sudo ss -tnp
ssh -i ~/.ssh/id_rsa ec2-user@$N2 sudo ss -tnp

# aws-node 데몬셋 파드 1곳에 bash 실행해두기 
kubectl exec daemonsets/aws-node -it -n kube-system -c aws-node -- bash

# 추가된 kubelet, kube-proxy 통신 Peer Address 확인
ssh -i ~/.ssh/id_rsa ec2-user@$N1 sudo ss -tnp
ssh -i ~/.ssh/id_rsa ec2-user@$N2 sudo ss -tnp

aws-node 데몬셋에 bash 실행 전

  • aws-node 데몬셋에 bash 실행 후
    • 실행 후 IP 확인을 해보면 추가된 연결정보를 확인할 수 있다.
      • 추가된 IP : 192.168.2.240

  • 추가된 연결된 정보(192.168.2.240)를 확인하기 위해 ENI를 확인
    • ENI가 추가로 생성되어있고 “소유자”와 “요청자”가 다르다.

  • 실습 완료 후 자원 삭제
# Amazon EKS 클러스터 삭제 (약 10분 소요)
eksctl delete cluster --name $CLUSTER_NAME

# 클러스터 삭제 완료 후 AWS CloudFormmation 스택 삭제
aws cloudformation delete-stack --stack-name myeks

'job > eks' 카테고리의 다른 글

eks 6주차  (0) 2023.05.31
eks 5주차  (0) 2023.05.23
4주차 eks 스터디  (0) 2023.05.16
3주차 eks 스터디  (0) 2023.05.13
eks 2주차  (0) 2023.05.02

devops, se 관점에서 Keycloak을 운영할때 필요한 것들을 알아본다.

 

1. IAM 관리시 알아야할것들

1-1) 계정 생성 및 관리
  패스워드 분실등 관리자가 서버 이벤트에 대한 알림을 받을 이메일 발송에 필요한 SMTP 설정

1-2) 그룹 생성 및 관리

1-3) realm 생성 및 관리

realm을 어떻게 관리하는게 B/P일까 ?
우선 마스터 realm은 시스템 관리(other realm 생성 관리)에만 사용해야하고 실제 클라이언트는 용도에 맞게 other realm을 생성해서 포함시켜줘야 한다.

그렇다면 Realm은 어떤 환경에따라 분류를 해줘야할까 ?

 

2. 디비 백업

 

3. 로그 관리

 

4. 주요 SP별 연동 방법

 

5. 알아두면 좋은 기능들

 

6. 고가용성 방안

 

7. 이중화

 

8. 실 서비스에 keycloak 사용하는법(keycloak을 브로커로 구성)

1. 인증되지 않은 사용자가 클라이언트 애플리케이션에서 보호된 리소스를 요청합니다.

2. 클라이언트 애플리케이션은 인증하기 위해 사용자를 Keycloak으로 리디렉션합니다.

3. Keycloak은 영역에 구성된 ID 공급자 목록이 있는 로그인 페이지를 표시합니다.

4. 사용자는 버튼 또는 링크를 클릭하여 ID 공급자 중 하나를 선택합니다.

5. Keycloak은 인증을 요청하는 대상 ID 공급자에게 인증 요청을 발급하고 사용자를 ID 공급자의 로그인 페이지로 리디렉션합니다. 관리자는 이미 관리 콘솔의 ID 공급자에 대한 연결 속성 및 기타 구성 옵션을 설정했습니다.

6. 사용자가 자격 증명을 제공하거나 ID 공급자에 인증하는 데 동의합니다.

7. ID 공급자가 인증에 성공하면 사용자는 인증 응답과 함께 Keycloak으로 다시 리디렉션됩니다. 일반적으로 이 응답에는 Keycloak에서 ID 공급자의 인증을 신뢰하고 사용자 정보를 검색하는 데 사용하는 보안 토큰이 포함됩니다.

8. Keycloak은 ID 공급자의 응답이 유효한지 확인합니다. 유효한 경우, 사용자가 아직 존재하지 않는 경우 Keycloak는 사용자를 가져와서 만듭니다. 토큰에 해당 정보가 포함되어 있지 않은 경우 Keycloak는 ID 공급자에게 추가 사용자 정보를 요청할 수 있습니다. 이 동작을 ID 페더레이션이라고 합니다. 사용자가 이미 존재하는 경우, Keycloak는 ID 공급자로부터 반환받은 ID를 기존 계정과 연결하도록 사용자에게 요청할 수 있습니다. 이 동작을 계정 연결이라고 합니다. Keycloak에서는 계정 연결을 구성하고 첫 로그인 플로우에서 계정 연결을 지정할 수 있습니다. 이 단계에서 Keycloak은 사용자를 인증하고 토큰을 발급하여 서비스 공급자의 요청된 리소스에 액세스할 수 있도록 합니다.
9. 사용자가 인증하면 Keycloak은 로컬 인증 중에 이전에 발급한 토큰을 전송하여 사용자를 서비스 공급자로 리디렉션합니다.
10. 서비스 공급자는 Keycloak으로부터 토큰을 받고 보호된 리소스에 대한 액세스를 허용합니다.

 

이 흐름의 변형이 가능합니다. 예를 들어, 클라이언트 애플리케이션에서 ID 공급자의 목록을 표시하지 않고 특정 공급자를 요청하거나, 사용자가 ID를 페더레이션하기 전에 추가 정보를 제공하도록 Keycloak을 설정할 수 있습니다.

인증 프로세스가 끝나면 Keycloak는 토큰을 클라이언트 애플리케이션에 발급합니다. 클라이언트 애플리케이션은 외부 ID 공급자와 분리되어 있으므로 클라이언트 애플리케이션의 프로토콜이나 사용자 신원을 검증하는 방법을 볼 수 없습니다. 공급자는 Keycloak에 대해서만 알면 됩니다.



구글 계정을통해 keycloak으로 연동한 saml로 실 서비스에 로그인하기.

 

 

version: '3.7'
services:
  reverse-proxy:
    image: traefik:v2.9
    restart: always
    ports:
      - '80:80' # http
      - '443:443' # https
      - '8080:8080' # https
    networks:
      - harbor
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./letsencrypt:/letsencrypt
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=harbor"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.ssh.address=:2222"
        #- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
        #- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=sabo@infograb.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      - "--api.insecure=true"
networks:
  harbor:
    external: true

 

 

 

 

+ Recent posts