ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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가 필요하다.

     

    How it Works

    How the ACK controller works

    aws-controllers-k8s.github.io

     

    Services

    Project status of each supported service

    aws-controllers-k8s.github.io

    [참고] ACK는 현재(23년 5월 29일 기준까지) Preview(테스트, 상용 서비스 비권장) 10개와 General Avaliability(상용 서비스 권장) 17개를 지원한다.

     

     

     

     

    ACK Controller를  통해 S3 를 생성해보자

    Kubernetes RBAC 권한은 ACK service Controller 설치 시, Helm이나 static manifests 파일을 통해 이미 설정이 완료된다.

     

    Permissions Overview

    Configuring RBAC and IAM for ACK

    aws-controllers-k8s.github.io

    # 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
     

    ECR Public Gallery

    Amazon ECR Public Gallery is a website that allows anyone to browse and search for public container images, view developer-provided details, and see pull commands

    gallery.ecr.aws

    => 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

    CRD로 bucket이 생성된 것을 확인
    CRD로 등록되었기 때문에 kubectl api-resource 명령에서도 확인가능
    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
    ...
     

    GitHub - aws-controllers-k8s/s3-controller: ACK service controller for Amazon Simple Storage Service (S3)

    ACK service controller for Amazon Simple Storage Service (S3) - GitHub - aws-controllers-k8s/s3-controller: ACK service controller for Amazon Simple Storage Service (S3)

    github.com

    IRSA 적용 후 ServiceAccount Describe 전/후
    CloudFormation 및 IAM Permission Policy 확인
    Rollout restart 전/후 Pod Describe

    => 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를 생성해보자

     

    Create an ACK Resource

    Create, Update and Delete an S3 bucket

    aws-controllers-k8s.github.io

    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

    AWS S3 생성확인

    => 공식 예제를 참고해보면 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 

     

    GitHub - k8s-ho/eks-tools: I made a useful tool while doing eks study:)

    I made a useful tool while doing eks study:). Contribute to k8s-ho/eks-tools development by creating an account on GitHub.

    github.com

     

    GitHub - aws-controllers-k8s/rds-controller: ACK service controller for Amazon Relational Database Service (RDS)

    ACK service controller for Amazon Relational Database Service (RDS) - GitHub - aws-controllers-k8s/rds-controller: ACK service controller for Amazon Relational Database Service (RDS)

    github.com

    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를 이용하여 배포해보겠다.

     

    Manage a VPC Workflow with the ACK EC2-Controller

    Create and manage a network topology using ACK EC2-Controller deployed on Amazon Elastic Kubernetes Service (EKS) The ACK service controller for Elastic Compute Cloud (EC2-Controller) lets users manage EC2 resources directly from Kubernetes. This guide dem

    aws-controllers-k8s.github.io

    VPC Workflow예제 구성(왼쪽) / ACK Controller 역할 그림(오른쪽)
    sync 미완료로 모든정보가 보여지진 않음
    sync가 아직 되지 않은 상황 확인(왼쪽) / 해당 Resource 상세보기를 통한 원인확인(오른쪽)
    sync 완료

    => 오른쪽의 그림같이 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

    tunneling을 통한 SSH 접근
    Private subnet instance와 Public subnet의 instance가 ssh로 연결됨을 확인(왼쪽)  /  Private Subnet의 instance 공인 ip(오른쪽)

    나의 로컬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 생성

     

    Deploy PostgreSQL, MySQL, MariaDB Instances Using the ACK RDS Controller

    Create managed PostgreSQL, MySQL, and MariaDB instances in Amazon Relational Database Service (RDS) from a Amazon Elastic Kubernetes Service (EKS) deployment.

    aws-controllers-k8s.github.io

    # 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으로 생성해주었다.

     

    Bind Application to AWS Resources | EKS Workshop

    Now that the RDS database has been created successfully, we can reconfigure the catalog component to use it for persistence instead of its existing pod-based MySQL. But how do we configure the catalog component with the RDS endpoint and credentials for the

    www.eksworkshop.com

    * 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"}}'

    변경한 식별자의 RDS가 생성되고 Creating -> back up -> Availiable 상태가 됨

    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에서 관리한다는 의미이다.

     

    EKS 스터디 - 7주차 flux 예제

    이 글은 flux가 무엇이고 간단한 예제를 살펴봅니다. 예제를 쉽게 따라하기 위해 모든 예제는 flux CLI를 사용합니다. flux란? flux는 쿠버네티스를 위한 gitops 도구입니다. flux는 git에 있는 쿠버네티스

    malwareanalysis.tistory.com

     

    Installation

    Flux install, bootstrap, upgrade and uninstall documentation.

    fluxcd.io

    # 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

    Flux 정상 설치 진행 및 완료

    => 위에서 진행한대로 github에 fleet-infra라는 이름의 private repository가 생성되었으며 몇가지 YAML file이 존재하는 것도 확인할 수 있었다.

     

     

     

     

    gitops 도구 설치(flux 대시보드 설치 : admin / password)

     

    Weave GitOps OSS | Weave GitOps

    Installing Weave GitOps on your Cluster

    docs.gitops.weave.works

    # 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 타입 사용

     

    GitHub - sungwook-practice/fluxcd-test: fluxcd-test

    fluxcd-test. Contribute to sungwook-practice/fluxcd-test development by creating an account on GitHub.

    github.com

    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

    Dashboad에서 확인

     

    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

    flux delete kustomization을 진행했음에도 Pod와 service가 살아있음(왼쪽) /  --prune 옵션이 true인 경우 삭제된 것을 확인(오른쪽)

    => --prune 옵션이 기본 false이기 때문에 flux로 kustomization을 삭제해도 pod와 service는 남아있다. 때문에 해당 옵션을 true로 설정해야 같이 사라진다.

    반응형

    댓글

Designed by Tistory.