-
[AWS] EKS - Automation(스터디 7주차)Infra/Cloud 2023. 6. 7. 21:35
스터디 마지막 7주차 주제는 EKS Automation이다.
벌써 마지막이라니.. 7주가 순식간에 지나갔다.
포스팅전에 스터디 후기부터 작성해보려고한다.
kubernetes가 재미있어서, kubernetes 보안에 도움이 될 것 같아 신청한 스터디였는데 역시나 굉장히 많은 도움이 된 것 같다.
(좋은 스터디에 참여할 기회를 주신 Gasida님 그리고 CloudNet@팀에 감사드립니다)
구체적으로 어떤점이 도움이 되었냐고 한다면...
1. 견문이 넓어졌다.
Kubernetes의 Cluster에도 다양한 종류가 있다는 것을 알게되었다. 단순히 On-premise 환경만 알고 있었다면 관리형 Kubernetes인 EKS를 처음 마주했을 때 당황스러웠을 것 같다(다행..ㅎㅎ). 그리고 굉장히 편리한 꿀팁이나 tool, 오픈소스들을 배울 수 있었다. cloud나 kubernetes는 특정 기능에 대한 불편함을 해결/개선/향상시키기 위한 수많은 오픈소스와 plugin 등이 존재하는데 사용해보니 좋았던 내용들을 공유받을 수 있었다(이런 것이 있다는 걸 알고 있는 것만으로도 몸이 편해지는..ㅎㅎ 완전 편리한 것들이 많았다...)
2. 퀄리티 높은 공유 자료 & AWS와 친해지기
주변에서도 실수로 인해 많은 과금이 발생한적이 있어 과금이 살짝 부담스러웠지만 지금은 자주 접하다보니 굉장히 친숙해졌다. 그리고 스터디에서 제공해주는 자료의 퀄리티가 좋다... 때문에 공부 시간이나 시행착오를 겪는 시간을 굉장히 단축시켜주었다고 생각한다. 또한 같은 내용을 진행하더라도 스터디원들마다 보는 관점이나 생각, 학습내용이 조금씩 상이한데 내가 미쳐 생각하지 못한 부분까지, 또는 진행하지 못한 부분도 나눌 수 있었다(스터디의 긍정적인 순기능이라고 생각한다). 그리고 내용 정리를 잘하시는 분들이 굉장히 많다...(스터디가 끝났으니 차근차근 다시봐야겠다)
3. 스터디원분들이 실무자가 많았다(네트워킹 및 경험 발표)
특히 미래에 많은 도움이 될 거라고 생각하는 부분이다. Kubernetes, Cloud 관련 실무자 분들이 많이 계셨다. 엔지니어, 개발자, 인프라담당자, 관리자분들이 어떤식으로 AWS, EKS를 운영하고 있고 어떤 고민을 하고, 어떤 부분을 중요하게 생각하는지 들을 수 있었고 값진 경험 발표들을 들을 수 있었다. 미래에 내가 하고 싶어하는 보안 직무와 연결지어 생각하는데 도움이 되었고 고려해야할 점이나 서로의 입장에서의 이해관계, 생각의 범위가 넓어진 것 같아 커뮤니케이션에 많은 도움이 될 것 같다.
결론은..다음스터디도 반드시 참여하고싶다ㅎㅎ
ACK - AWS Controller for Kubernetes
ACK란 Kubernetes에서 AWS Resource들을 직접 정의해서 사용하는 것이다.
즉, kubectl 명령을 통해 (kube-apiserver를 통해) AWS Resource를 생성할 수 있게 할 수 있다.
쉽게말해 Kubernetes 환경에서 AWS Resource를 Kubernetes스럽게(?), Kubernetes native하게(?) 생성할 수 있다.
AWS IAM + Kubernetes RBAC가 필요하다.
[참고] ACK는 현재(23년 5월 29일 기준까지) Preview(테스트, 상용 서비스 비권장) 10개와 General Avaliability(상용 서비스 권장) 17개를 지원한다.
ACK Controller를 통해 S3 를 생성해보자
Kubernetes RBAC 권한은 ACK service Controller 설치 시, Helm이나 static manifests 파일을 통해 이미 설정이 완료된다.
# ACK S3 Controller Helm 차트 다운로드 export SERVICE=s3 # helm 차트 다운로드 export RELEASE_VERSION=$(curl -sL https://api.github.com/repos/aws-controllers-k8s/$SERVICE-controller/releases/latest | grep '"tag_name":' | cut -d'"' -f4 | cut -c 2-) helm pull oci://public.ecr.aws/aws-controllers-k8s/$SERVICE-chart --version=$RELEASE_VERSION tar xzvf $SERVICE-chart-$RELEASE_VERSION.tgz # helm chart 확인 tree ~/$SERVICE-chart
=> AWS에서 제공하는 Elastic Container Registry(ECR)에서 helm chart를 install해주었다.
# ACK S3 Controller 설치 export ACK_SYSTEM_NAMESPACE=ack-system export AWS_REGION=ap-northeast-2 helm install --create-namespace -n $ACK_SYSTEM_NAMESPACE ack-$SERVICE-controller --set aws.region="$AWS_REGION" ~/$SERVICE-chart # 설치 확인 helm list --namespace $ACK_SYSTEM_NAMESPACE kubectl -n ack-system get pods kubectl get crd | grep $SERVICE kubectl get all -n ack-system kubectl get-all -n ack-system kubectl describe sa -n ack-system ack-s3-controller
=> helm install 옵션을 통해 namespace가 없더라도 생성되게 옵션을 주었으며 ack s3 controller를 우리가 원하는 ap-northeast2 region에 진행되로록 설치를 진행했다.
IRSA 설정
# Create an iamserviceaccount - AWS IAM role bound to a Kubernetes service account eksctl create iamserviceaccount \ --name ack-$SERVICE-controller \ --namespace ack-system \ --cluster $CLUSTER_NAME \ --attach-policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3FullAccess`].Arn' --output text) \ --override-existing-serviceaccounts --approve # 확인 >> 웹 관리 콘솔에서 CloudFormation Stack >> IAM Role 확인 eksctl get iamserviceaccount --cluster $CLUSTER_NAME # Inspecting the newly created Kubernetes Service Account, we can see the role we want it to assume in our pod. kubectl get sa -n ack-system kubectl describe sa ack-$SERVICE-controller -n ack-system # Restart ACK service controller deployment using the following commands. kubectl -n ack-system rollout restart deploy ack-$SERVICE-controller-$SERVICE-chart # IRSA 적용으로 Env, Volume 추가 확인 kubectl describe pod -n ack-system -l k8s-app=$SERVICE-chart ...
=> Controller 별로 해당 repository 경로에 Recommand Policy를 명시해주고 있으니 참고해서 IRSA를 진행하면 된다. IRSA 적용 후 해당 serviceaccount를 확인해보면 Annotations에 role-arn이 추가된 것을 확인할 수 있다. 해당 serviceaccount를 재적용하기위해 pod rollout restart를 진행해주면 Pod에 aws-iam token mount와 Environment 값이 추가된 것을 확인할 수 있었다(Mutating Webhook에 의해 수정됨)
이제 kubectl을 통해 AWS S3 Resource를 생성해보자
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) export BUCKET_NAME=my-ack-s3-bucket-$AWS_ACCOUNT_ID read -r -d '' BUCKET_MANIFEST <<EOF apiVersion: s3.services.k8s.aws/v1alpha1 kind: Bucket metadata: name: $BUCKET_NAME spec: name: $BUCKET_NAME EOF echo "${BUCKET_MANIFEST}" > bucket.yaml kubectl create -f bucket.yaml kubectl describe bucket/$BUCKET_NAME
=> 공식 예제를 참고해보면 S3의 이름은 다른사람들과 겹치면 안되기 때문인지 AWS_ACCOUNT_ID를 가져다 사용하도록 설정했다. ack-s3-controller(+ RBAC, IRSA)에 의해 kubectl로 AWS s3 Resource를 생성한 것을 확인할 수 있었다(물론 동일한 방법으로 삭제도 가능하다)
Clean up
# S3 bucket 삭제 kubectl delete -f bucket.yaml # helm uninstall export SERVICE=s3 helm uninstall -n ack-system ack-$SERVICE-controller # ACK S3 Controller 관련 crd 삭제 kubectl delete -f ~/$SERVICE-chart/crds # IRSA 삭제 eksctl delete iamserviceaccount --cluster myeks --name ack-$SERVICE-controller --namespace ack-system # Namespace 삭제 kubectl delete ns ack-system
ACK Controller를 통해 EC2 & VPC 를 생성해보자
설정에 대해서는 위의 S3랑 다를게 없다. 환경변수 SERVICE 값과 이후에 IRSA에서 Policy만 달라질뿐 나머지는 그대로 진행하면 된다.
ack resource 명은 ec2지만 VPC와 관련된 내용도 생성이 가능하다.
[참고] ACK Controller Download & Install + IRSA
git clone https://github.com/k8s-ho/eks-tools chmod +x ack.sh ./ack.sh [namespace] [ACK Resource] ./ack.sh ack-system ec2
=> 스터디에서 제공해주신 내용을 조금 수정하고 가공해서 만들어봤다. 사용법은 간단하다. 참고로 IRSA에서 사용되는 IAM Policy에 대해서는 ack controller github에서 recommand하는 정보를 자동으로 가져오게 했다.
VPC & Subnet 생성 & 삭제
# [터미널1] 모니터링 while true; do aws ec2 describe-vpcs --query 'Vpcs[*].{VPCId:VpcId, CidrBlock:CidrBlock}' --output text; echo "-----"; sleep 1; done # VPC 생성 cat <<EOF > vpc.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: VPC metadata: name: vpc-tutorial-test spec: cidrBlocks: - 10.0.0.0/16 enableDNSSupport: true enableDNSHostnames: true EOF kubectl apply -f vpc.yaml
# 서브넷 생성 VPCID=$(kubectl get vpcs vpc-tutorial-test -o jsonpath={.status.vpcID}) # 모니터링 while true; do aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --query 'Subnets[*].{SubnetId:SubnetId, CidrBlock:CidrBlock}' --output text; echo "-----"; sleep 1 ; done cat <<EOF > subnet.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Subnet metadata: name: subnet-tutorial-test spec: cidrBlock: 10.0.0.0/20 vpcID: $VPCID EOF kubectl apply -f subnet.yaml
=> 역시나 제대로 생성 및 삭제가 완료되는 것을 확인할 수 있었다.
VPC Workflow 예제 배포
아래와 같은 VPC 환경을 ACK-ec2-Controller를 이용하여 배포해보겠다.
=> 오른쪽의 그림같이 ACK Controller가 AWS의 해당 Resource의 현재 상태를 체크하고 체크가 완료되어야 sync가 된다. 따라서 kubernetes의 CRD로 존재하는 AWS resource들을 확인했을 때 제대로 확인이 안될 수도 있다. 이는 상세한 정보들이 sync되기까지 어느정도 시간이 소요되기 때문이다.
* VPC Workflow 예제 YAML file (더보기 확인)
더보기cat <<EOF > vpc-workflow.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: VPC metadata: name: tutorial-vpc spec: cidrBlocks: - 10.0.0.0/16 enableDNSSupport: true enableDNSHostnames: true tags: - key: name value: vpc-tutorial --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: InternetGateway metadata: name: tutorial-igw spec: vpcRef: from: name: tutorial-vpc --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: NATGateway metadata: name: tutorial-natgateway1 spec: subnetRef: from: name: tutorial-public-subnet1 allocationRef: from: name: tutorial-eip1 --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: ElasticIPAddress metadata: name: tutorial-eip1 spec: tags: - key: name value: eip-tutorial --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: RouteTable metadata: name: tutorial-public-route-table spec: vpcRef: from: name: tutorial-vpc routes: - destinationCIDRBlock: 0.0.0.0/0 gatewayRef: from: name: tutorial-igw --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: RouteTable metadata: name: tutorial-private-route-table-az1 spec: vpcRef: from: name: tutorial-vpc routes: - destinationCIDRBlock: 0.0.0.0/0 natGatewayRef: from: name: tutorial-natgateway1 --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Subnet metadata: name: tutorial-public-subnet1 spec: availabilityZone: ap-northeast-2a cidrBlock: 10.0.0.0/20 mapPublicIPOnLaunch: true vpcRef: from: name: tutorial-vpc routeTableRefs: - from: name: tutorial-public-route-table --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Subnet metadata: name: tutorial-private-subnet1 spec: availabilityZone: ap-northeast-2a cidrBlock: 10.0.128.0/20 vpcRef: from: name: tutorial-vpc routeTableRefs: - from: name: tutorial-private-route-table-az1 --- apiVersion: ec2.services.k8s.aws/v1alpha1 kind: SecurityGroup metadata: name: tutorial-security-group spec: description: "ack security group" name: tutorial-sg vpcRef: from: name: tutorial-vpc ingressRules: - ipProtocol: tcp fromPort: 22 toPort: 22 ipRanges: - cidrIP: "0.0.0.0/0" description: "ingress" EOF # VPC 환경 생성 kubectl apply -f vpc-workflow.yaml
생성된 VPC 환경의 Public subnet에 instance를 생성해보자.
# public 서브넷 ID 확인 PUBSUB1=$(kubectl get subnets tutorial-public-subnet1 -o jsonpath={.status.subnetID}) echo $PUBSUB1 # 보안그룹 ID 확인 TSG=$(kubectl get securitygroups tutorial-security-group -o jsonpath={.status.id}) echo $TSG # Amazon Linux 2 최신 AMI ID 확인 AL2AMI=$(aws ec2 describe-images --owners amazon --filters "Name=name,Values=amzn2-ami-hvm-2.0.*-x86_64-gp2" --query 'Images[0].ImageId' --output text) echo $AL2AMI # 각자 자신의 SSH 키페어 이름 변수 지정 MYKEYPAIR=<각자 자신의 SSH 키페어 이름> # 변수 확인 > 특히 서브넷 ID가 확인되었는지 꼭 확인하자! echo $PUBSUB1 , $TSG , $AL2AMI , $MYKEYPAIR # [터미널1] 모니터링 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 table; date ; sleep 1 ; done # public 서브넷에 인스턴스 생성 cat <<EOF > tutorial-bastion-host.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Instance metadata: name: tutorial-bastion-host spec: imageID: $AL2AMI # AL2 AMI ID - ap-northeast-2 instanceType: t3.medium subnetID: $PUBSUB1 securityGroupIDs: - $TSG keyName: $MYKEYPAIR tags: - key: producer value: ack EOF kubectl apply -f tutorial-bastion-host.yaml # 인스턴스 생성 확인 kubectl get instance kubectl describe instance 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
instance가 정상적으로 생성된 것을 확인할 수 있었으며 AWS Console에서도 SG와 Tag 등 YAML file로 설정한대로 적용된 것을 확인할 수 있었다.
추가적으로 해당 Public instance가 외부통신을 하기위해서는 egress rule을 SG에 추가해주어야한다.
cat <<EOF > modify-sg.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: SecurityGroup metadata: name: tutorial-security-group spec: description: "ack security group" name: tutorial-sg vpcRef: from: name: tutorial-vpc ingressRules: - ipProtocol: tcp fromPort: 22 toPort: 22 ipRanges: - cidrIP: "0.0.0.0/0" description: "ingress" egressRules: - ipProtocol: '-1' ipRanges: - cidrIP: "0.0.0.0/0" description: "egress" EOF kubectl apply -f modify-sg.yaml # 변경 확인 >> 보안그룹에 아웃바운드 규칙 확인 kubectl logs -n $ACK_SYSTEM_NAMESPACE -l k8s-app=ec2-chart -f
이번에는 Private subnet에 instance를 생성해보자.
# private 서브넷 ID 확인 >> NATGW 생성 완료 후 RT/SubnetID가 확인되어 다소 시간 필요함 PRISUB1=$(kubectl get subnets tutorial-private-subnet1 -o jsonpath={.status.subnetID}) echo $PRISUB1 # 변수 확인 > 특히 private 서브넷 ID가 확인되었는지 꼭 확인하자! echo $PRISUB1 , $TSG , $AL2AMI , $MYKEYPAIR # private 서브넷에 인스턴스 생성 cat <<EOF > tutorial-instance-private.yaml apiVersion: ec2.services.k8s.aws/v1alpha1 kind: Instance metadata: name: tutorial-instance-private spec: imageID: $AL2AMI # AL2 AMI ID - ap-northeast-2 instanceType: t3.medium subnetID: $PRISUB1 securityGroupIDs: - $TSG keyName: $MYKEYPAIR tags: - key: producer value: ack EOF kubectl apply -f tutorial-instance-private.yaml # 인스턴스 생성 확인 kubectl get instance kubectl describe instance 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
생성된 Private Subnet에 존재하는 Instance에 Public subnet의 Instance Tunneling을 통해 접속해보자
ssh -i <Keypair file> -L <임의 로컬 포트>:<private 서브넷의 인스턴스의 private ip 주소>:22 ec2-user@<public 서브넷에 인스턴스 퍼블릭IP> -v ex) ssh -i abc.pem -L 9999:10.0.129.196:22 ec2-user@3.34.96.12 -v ssh -i <Keypair file> -p 9999 ec2-user@localhost
나의 로컬PC 포트 -> public subnet instance -> private subnet instance의 경로로 연결된다. 또한 private subnet에 존재하는 instance의 공인ip는 NAT Gateway의 ip이다.
Clean up
# vpc workflow 관련 리소스 삭제 kubectl delete -f tutorial-bastion-host.yaml && kubectl delete -f tutorial-instance-private.yaml kubectl delete -f vpc-workflow.yaml # vpc 관련 모든 리소스들 삭제에는 다소 시간이 소요됨 # vpc, subnet 삭제 kubectl delete -f subnet.yaml && kubectl delete -f vpc.yaml # helm uninstall export SERVICE=ec2 helm uninstall -n ack-system ack-$SERVICE-controller # ACK S3 Controller 관련 crd 삭제 kubectl delete -f ~/$SERVICE-chart/crds # IRSA 삭제 eksctl delete iamserviceaccount --cluster myeks --name ack-$SERVICE-controller --namespace ack-system # Namespace 삭제 kubectl delete ns ack-system
ACK Controller를 통해 RDS 생성해보자
관련 ACK Controller 및 IRSA setting은 자동화 스크립트로 진행해주었다
git clone https://github.com/k8s-ho/eks-tools chmod +x ack.sh ./ack.sh ack-system rds
AWS RDS for MariaDB 생성
# DB 암호를 위한 secret 생성 RDS_INSTANCE_NAME="<your instance name>" RDS_INSTANCE_PASSWORD="<your instance password>" RDS_INSTANCE_NAME=myrds RDS_INSTANCE_PASSWORD=qwe12345 kubectl create secret generic "${RDS_INSTANCE_NAME}-password" --from-literal=password="${RDS_INSTANCE_PASSWORD}" # 확인 kubectl get secret $RDS_INSTANCE_NAME-password # [터미널1] 모니터링 RDS_INSTANCE_NAME=myrds watch -d "kubectl describe dbinstance "${RDS_INSTANCE_NAME}" | grep 'Db Instance Status'" # RDS 배포 생성 : 15분 이내 시간 소요 >> 보안그룹, 서브넷 등 필요한 옵션들은 추가해서 설정해보자! cat <<EOF > rds-mariadb.yaml apiVersion: rds.services.k8s.aws/v1alpha1 kind: DBInstance metadata: name: "${RDS_INSTANCE_NAME}" spec: allocatedStorage: 20 dbInstanceClass: db.t4g.micro dbInstanceIdentifier: "${RDS_INSTANCE_NAME}" engine: mariadb engineVersion: "10.6" masterUsername: "admin" masterUserPassword: namespace: default name: "${RDS_INSTANCE_NAME}-password" key: password EOF kubectl apply -f rds-mariadb.yaml # 생성 확인 kubectl get dbinstances ${RDS_INSTANCE_NAME} kubectl describe dbinstance "${RDS_INSTANCE_NAME}" aws rds describe-db-instances --db-instance-identifier $RDS_INSTANCE_NAME | jq kubectl describe dbinstance "${RDS_INSTANCE_NAME}" | grep 'Db Instance Status' Db Instance Status: creating kubectl describe dbinstance "${RDS_INSTANCE_NAME}" | grep 'Db Instance Status' Db Instance Status: backing-up kubectl describe dbinstance "${RDS_INSTANCE_NAME}" | grep 'Db Instance Status' Db Instance Status: available # 생성 완료 대기 : for 지정 상태가 완료되면 정상 종료됨 kubectl wait dbinstances ${RDS_INSTANCE_NAME} --for=condition=ACK.ResourceSynced --timeout=15m dbinstance.rds.services.k8s.aws/myrds condition met
환경변수를 이용하여 해당 RDS MariaDB에 바로 접근이 가능한 Pod를 만들어보자(feat. filedexport)
우선 fieldexport를 이용하여 필요정보들을 configmap으로 생성해주었다.
* fieldexport로 configmap 생성(더보기 참고)
더보기RDS_INSTANCE_CONN_CM="${RDS_INSTANCE_NAME}-conn-cm" cat <<EOF > rds-field-exports.yaml --- apiVersion: v1 kind: ConfigMap metadata: name: ${RDS_INSTANCE_CONN_CM} data: {} --- apiVersion: services.k8s.aws/v1alpha1 kind: FieldExport metadata: name: ${RDS_INSTANCE_NAME}-host spec: to: name: ${RDS_INSTANCE_CONN_CM} kind: configmap from: path: ".status.endpoint.address" resource: group: rds.services.k8s.aws kind: DBInstance name: ${RDS_INSTANCE_NAME} --- apiVersion: services.k8s.aws/v1alpha1 kind: FieldExport metadata: name: ${RDS_INSTANCE_NAME}-port spec: to: name: ${RDS_INSTANCE_CONN_CM} kind: configmap from: path: ".status.endpoint.port" resource: group: rds.services.k8s.aws kind: DBInstance name: ${RDS_INSTANCE_NAME} --- apiVersion: services.k8s.aws/v1alpha1 kind: FieldExport metadata: name: ${RDS_INSTANCE_NAME}-user spec: to: name: ${RDS_INSTANCE_CONN_CM} kind: configmap from: path: ".spec.masterUsername" resource: group: rds.services.k8s.aws kind: DBInstance name: ${RDS_INSTANCE_NAME} EOF kubectl apply -f rds-field-exports.yaml
kubectl describe dbinstance "${RDS_INSTANCE_NAME}"
=> Pod가 환경변수를 활용하여 RDS mariaDB에 바로 접근할 수 있도록 하기 위해서는 RDS의 Endpoint 주소 등, 몇가지 정보들이 필요하다. 이때 활용할 수 있는 것이 바로 Fieldexport이다. Fieldexport를 통해 우리가 활용하는데 필요한 정보를 configmap이나 secret으로 편리하게 생성할 수 있다.
* 생성된 Configmap 확인
# 상태 정보 확인 : address 와 port 정보 kubectl get dbinstances myrds -o jsonpath={.status.endpoint} | jq # 상태 정보 확인 : masterUsername 확인 kubectl get dbinstances myrds -o jsonpath={.spec.masterUsername} ; echo # 컨피그맵 확인 kubectl get cm myrds-conn-cm -o yaml | kubectl neat | yh # fieldexport 정보 확인 kubectl get crd | grep fieldexport kubectl get fieldexport kubectl get fieldexport myrds-host -o yaml | k neat | yh
Export한 configmap을 이용한 Pod 생성
APP_NAMESPACE=default cat <<EOF > rds-pods.yaml apiVersion: v1 kind: Pod metadata: name: app namespace: ${APP_NAMESPACE} spec: containers: - image: busybox name: myapp command: - sleep - "3600" imagePullPolicy: IfNotPresent env: - name: DBHOST valueFrom: configMapKeyRef: name: ${RDS_INSTANCE_CONN_CM} key: "${APP_NAMESPACE}.${RDS_INSTANCE_NAME}-host" - name: DBPORT valueFrom: configMapKeyRef: name: ${RDS_INSTANCE_CONN_CM} key: "${APP_NAMESPACE}.${RDS_INSTANCE_NAME}-port" - name: DBUSER valueFrom: configMapKeyRef: name: ${RDS_INSTANCE_CONN_CM} key: "${APP_NAMESPACE}.${RDS_INSTANCE_NAME}-user" - name: DBPASSWORD valueFrom: secretKeyRef: name: "${RDS_INSTANCE_NAME}-password" key: password EOF kubectl apply -f rds-pods.yaml # 생성 확인 kubectl get pod app # 파드의 환경 변수 확인 kubectl exec -it app -- env | grep DB
=> 이를 통해 Pod 생성 시, 바로 DB에 접속할 수 있게 환경변수를 구성할 수 있다.
RDS DB 식별자 변경
kubectl patch dbinstance myrds --type=merge -p '{"spec":{"dbInstanceIdentifier":"studyend"}}'
kubectl get dbinstances myrds -o jsonpath={.status.endpoint} | jq kubectl delete pod app && kubectl apply -f rds-pods.yaml kubectl exec -it app -- env | grep DB
=> 변경한 DB 식별자의 RDS가 새로 생성되며 이는 Rolling Update가 아니라 기존의 RDS를 삭제하는 등의 관리가 진행되지 않는다.
=> 변경된 내용에 대한 tracking이 부족하다는 단점이 존재하므로 사용할거라면 이러한 문제를 고려해봐야한다(때문에 실습 이후 삭제는 AWS Console에서 수동으로 확실하게 전부 삭제해주는 것이 좋다)=> 변경한 식별자와 관련된 환경변수 변화를 살펴보기 위해서는 Pod를 다시 생성해야한다(Pod 생성 시, configMap을 통해 Env를 설정했기 때문에 Pod를 재생성해야 정확한 확인이 가능). 시간이 조금 지나고 새로 생성된 RDS가 available 상태가 되면 변경된 Env 및 정보 확인을 할 수 있게 된다.
Flux
Flux는 Kubernetes에서 사용하는 gitops 도구이며 git에 정의되어있는 kubernetes resource(pod, service, deployment 등) 정보(manifests)를 kubernetes에 배포할 수 있다. github의 token이 필요하기 때문에 발급해서 진행해야한다.
* GitOps란 - Git Operation
DevOps의 실천방법 중 하나로 Application의 배포와 운영에 관련된 모든 요소들을 Git에서 관리한다는 의미이다.
# Flux CLI 설치 curl -s https://fluxcd.io/install.sh | sudo bash . <(flux completion bash) # 버전 확인 flux --version flux version 2.0.0-rc.5 # 자신의 Github 토큰과 유저이름 변수 지정 export GITHUB_TOKEN=<your-token> export GITHUB_USER=<your-username> # Bootstrap ## Creates a git repository fleet-infra on your GitHub account. ## Adds Flux component manifests to the repository. ## Deploys Flux Components to your Kubernetes Cluster. ## Configures Flux components to track the path /clusters/my-cluster/ in the repository. flux bootstrap github \ --owner=$GITHUB_USER \ --repository=fleet-infra \ --branch=main \ --path=./clusters/my-cluster \ --personal
=> 위에서 진행한대로 github에 fleet-infra라는 이름의 private repository가 생성되었으며 몇가지 YAML file이 존재하는 것도 확인할 수 있었다.
gitops 도구 설치(flux 대시보드 설치 : admin / password)
# gitops 도구 설치 - ?Would you like to turn on analytics to help us improve our product? [Y/n] n으로 진행했음 curl --silent --location "https://github.com/weaveworks/weave-gitops/releases/download/v0.24.0/gitops-$(uname)-$(uname -m).tar.gz" | tar xz -C /tmp sudo mv /tmp/gitops /usr/local/bin gitops version # flux 대시보드 설치 PASSWORD="password" gitops create dashboard ww-gitops --password=$PASSWORD # 확인 flux -n flux-system get helmrelease kubectl -n flux-system get pod,svc
Ingress 설정 및 Dashboard 접속(+ ALB, External DNS)
# External DNS MyDomain=im-youngho.com echo "export MyDomain=im-youngho.com" >> /etc/profile MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text) echo $MyDomain, $MyDnzHostedZoneId curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f - # AWS LB Controller helm repo add eks https://aws.github.io/eks-charts helm repo update helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \ --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text` echo $CERT_ARN # Ingress 설정 cat <<EOT > gitops-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: gitops-ingress annotations: alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN alb.ingress.kubernetes.io/group.name: study alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]' alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/ssl-redirect: "443" alb.ingress.kubernetes.io/success-codes: 200-399 alb.ingress.kubernetes.io/target-type: ip spec: ingressClassName: alb rules: - host: gitops.$MyDomain http: paths: - backend: service: name: ww-gitops-weave-gitops port: number: 9001 path: / pathType: Prefix EOT kubectl apply -f gitops-ingress.yaml -n flux-system # 배포 확인 kubectl get ingress -n flux-system # GitOps 접속 정보 확인 >> 웹 접속 후 정보 확인 echo -e "GitOps Web https://gitops.$MyDomain"
Github에 있는 Nginx Manifest를 Kubernetes에 배포(악분님 예시 사용) - Kustomize 타입 사용
GITURL="https://github.com/sungwook-practice/fluxcd-test.git" flux create source git nginx-example1 --url=$GITURL --branch=main --interval=30s
# [터미널] 모니터링 watch -d kubectl get pod,svc nginx-example1 # flux 애플리케이션 생성 : nginx-example1 flux create kustomization nginx-example1 --target-namespace=default --interval=1m --source=nginx-example1 --path="./nginx" --health-check-timeout=2m # 확인 kubectl get pod,svc nginx-example1 kubectl get kustomizations -n flux-system flux get kustomizations
Clean up
# flux 애플리케이션 삭제 >> 파드와 서비스는? flux 애플리케이션 생성 시 --prune 옵션 false(default 값) flux delete kustomization nginx-example1 flux get kustomizations kubectl get pod,svc nginx-example1 # flux 애플리케이션 다시 생성 : --prune 옵션 true flux create kustomization nginx-example1 \ --target-namespace=default \ --prune=true \ --interval=1m \ --source=nginx-example1 \ --path="./nginx" \ --health-check-timeout=2m # 확인 flux get kustomizations kubectl get pod,svc nginx-example1 # flux 애플리케이션 삭제 >> 파드와 서비스는? flux delete kustomization nginx-example1 flux get kustomizations kubectl get pod,svc nginx-example1 # flux 소스 삭제 flux delete source git nginx-example1 # 소스 확인 flux get sources git kubectl -n flux-system get gitrepositories flux uninstall --namespace=flux-system
=> --prune 옵션이 기본 false이기 때문에 flux로 kustomization을 삭제해도 pod와 service는 남아있다. 때문에 해당 옵션을 true로 설정해야 같이 사라진다.
반응형'Infra > Cloud' 카테고리의 다른 글
[AWS] LocalStack이란? (4) 2023.12.04 [AWS] Lambda와 Nodejs 이용한 영화 예매순위 알람 서비스 (0) 2023.12.04 [AWS] EKS - Security(스터디 6주차) (0) 2023.05.30 [AWS] EKS - AutoScaling(스터디 5주차) (0) 2023.05.23 [AWS] EKS - Observability(스터디 4주차) (0) 2023.05.15 댓글