설치한 prometheus 메인 config yaml 파일에 recording_rules.yml, alertiing_rules.yml 항목이 data 필드로 존재하는 것을 확인했으며 해당 부분에 주요 major라고 생각하는 메트릭을 추가해보았다.

 

추가한 recording_rules 는 다음 항목과 같았다.

  recording_rules.yml: |
    groups:
    - name: core_metric
      rules:
      - record: instance:cpu_usage
        expr: sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance)
      - record: node_memory_bytes_total
        expr: sum(node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes)
      - record: node_disk_io_time_seconds_total
        expr: sum(rate(node_disk_io_time_seconds_total[5m])) by (device)
      - record: node_network_receive_bytes_total
        expr: sum(rate(node_network_receive_bytes_total[5m])) by (device)
      - record: node_network_transmit_bytes_total
        expr: sum(rate(node_network_transmit_bytes_total[5m])) by (device)
      - record: node_cpu_seconds_total
        expr: sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (mode)
      - record: node_filesystem_avail_bytes
        expr: sum(node_filesystem_avail_bytes) by (device)
      - record: node_filesystem_size_bytes
        expr: sum(node_filesystem_size_bytes) by (device)
      - record: node_filesystem_free_bytes
        expr: sum(node_filesystem_free_bytes) by (device)
      - record: node_filesystem_used_bytes
        expr: sum(node_filesystem_size_bytes - node_filesystem_free_bytes) by (device)

 

다음은 알럿과 연관된 alert 룰이다.

 

data:
  alerting_rules.yml: |
    groups:
    - name: core_alerts
      rules:
      - alert: HighCpuUsage
        expr: sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage detected"
          description: "CPU usage is above 90% for at least 5 minutes."
      - alert: HighMemoryUsage
        expr: (node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes) / node_memory_MemTotal_bytes > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High memory usage detected"
          description: "Memory usage is above 90% for at least 5 minutes."

 

각각 정의한 네임인 core_metric과 core_alerts 가 다음과 같이 배포되어 프로메테우스 페이지에서 확인되었다.

배포는 메인 컨피그 yaml 파일을 kubectl apply -f config.yaml 식으로 배포하였고, 배포하면 running 중인 pod에 반영이 되는데 테스트하다가 pod를 재생성하려고 delete를 하였다. pod 삭제 후 기본 설정에 따라 pod 하나와 container 두개가 새로 생성되었지만 해당 nlb 타겟그룹에서 unhealthy로 기록되었다.

아래는 grafana 배포관련 캡처이지만 비슷한 상태였던것 같다.

pod description을 보니 아이피가 바뀐 것을 확인하고 해당 파드의 보안그룹을 허용해주고, 그 파드 안에서 프로세스를 확인해보니 9090 포트로 계속 TIME_WAIT 가 나고 connection refused가 나는 것을 확인했다.

 

메인 컨피그 yaml에서 다음 항목을 줄여주고, 해당 배포 pod ec2에서 sysctl 설정을 업데이트 하였다.

main_config.yaml

terminationGracePeriodSeconds: 60 (300에서 60)

 

pod 서버 (내 경우는 ec2노드의 pod)에서

/etc/sysctl.conf 편집하여 다음 항목 추가:

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

저장 후 나와서 sudo sysctl -p 커맨드 입력 (위 ipv4.tcp_tw_reuse 값 설정은 timeout wait 상태의 소켓 수를 줄이고 포트를 더 빨리 풀어줌. tw_recycle은 리눅스 커널 버전 4.12 이후 deprecated)
netstat 으로 9090 포트 확인9090 포트의 target 서버 ip로 요청 및 정상적으로 응답오는 것을 확인 (location 헤더에 /graph 라고 보임) 후,해당 Prometheus 의 AWS NLB 타겟 그룹에 기존에 명시적으로 들어가있던 아이피 대신 타겟 아이피 register, healthy로 바뀌는 것을 확인하였다.아직 상태는 미흡하지만 프로메테우스로 어디까지 커스텀 가능한지 지속해서 확인해봐야겠다.

alerting_rules.yml

 

 

recording_rules.yml

 

 

kubectl로 prometheus 확인 시 유용했던 명령어 정리:

kubectl logs -f prometheus-pod-name -n namespaceofpm -c prometheus-containername | more (해당 pod에 컨테이너 여러개일때 특정 컨테이너 지정하여 로그 확인 방법)
kubectl get pods <prometheus-pod-name> -n <namespace> -o jsonpath="{.spec.containers[*].name}" (해당 pod의 컨테이너를 찾을때)
kubectl describe configmap fluentd-config
kubectl get configmap -n <namespace> -l app=fluentd -o yaml (app이 fluentd인 configmap yaml파일 찾기)
kubectl kill -s HUP <prometheus-pod-name> -n <namespace> (안먹을때도 있음 버전따라)
kubectl rollout restart deployment/<grafana-deployment-name> -n <namespace> (apply 후 pod 삭제 없이 deploy)
kubectl get deployments -n <namespace> (deployment 이름 찾기)

 

EKS에서 보통 EKS 노드가 생성될 때 bootstrap 스크립트를 통해 kubelet arguments를 설정할 수 있고, keep-alive 관련 수정을 원하는 경우 '--allowed-unsafe-sysctls' 파라미터를 포함하는 kubelet을 기동하는 node group을 생성하여 원하는 작업을 수행한다.

 

우선 아래 github link를 통해 eks 노드가 생성될때 각 설정에 대해 참고할 수 있다.

https://github.com/awslabs/amazon-eks-ami/blob/master/files/bootstrap.sh

 

GitHub - awslabs/amazon-eks-ami: Packer configuration for building a custom EKS AMI

Packer configuration for building a custom EKS AMI - GitHub - awslabs/amazon-eks-ami: Packer configuration for building a custom EKS AMI

github.com

또한 아래 링크에서 EKS(eksctl) Config 파일 설정에 대해 각 항목을 참고할 수 있다.

https://eksctl.io/usage/schema/#nodeGroups-overrideBootstrapCommand

 

Config file schema - eksctl

Config file schema Use eksctl utils schema to get the raw JSON schema.

eksctl.io

제목에 따라 EKS pod에 keep alive 관련 설정을 하려면 먼저 Custom AMI를 지정하고,

eksctl config file 설정 중 overrideBootstrapCommand 설정을 통해 bootstrap script를 지정하여

--allowed-unsafe-sysctls 파라미터가 설정된 kubelet 을 기동하는 노드 그룹을 생성한다.

 

 

pod.yaml 예시

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu
    command: ["sleep"]
    args: ["1d"]
  securityContext:
    sysctls:
    - name: net.ipv4.tcp_keepalive_intvl
      value: "60"

eksctl-config.yaml 예시

 

apiVersion: eksctl.io/v1alpha5 
kind: ClusterConfig

metadata:
  name: <cluster name>
  region: <region>

managedNodeGroups:
- name: <nodegroup name>
  ami: <ami id>
  amiFamily: AmazonLinux2
  minSize: 0
  maxSize: 10
  desiredCapacity: 2
  ssh:
    allow: true
    publicKeyName: <public key>
  overrideBootstrapCommand: |
    #!/bin/bash
    set -ex
    /etc/eks/bootstrap.sh <cluster name> --kubelet-extra-args "--node-labels=alpha.eksctl.io/cluster-name=<cluster name>,alpha.eksctl.io/nodegroup-name=<nodegroup-name>,eks.amazonaws.com/nodegroup=<nodegroup-name>,eks.amazonaws.com/nodegroup-image=<ami  id> --allowed-unsafe-sysctls 'net.ipv4.tcp_keepalive_intvl'"

 

kubectl 명령어로 설정된 값을 확인한다.

$ kc exec -it ubuntu -- sysctl -a | grep -i keepalive
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200

 

추가 참고 자료:

쿠버네티스에서 sysctl 이용하기: https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/

개발팀으로부터 cloudon 네임스페이스에 있는 cloudon-ingress를 삭제하려고 하는데 권한오류로 삭제가 안되어서 재배포가 안된다고 요청이 왔다.

에러 메시지는 다음과 같다.

 

Error Message : 
{"level":"error","ts":xxxxxxxx.xxxxxx,"logger":"controller.ingress","msg":"Reconciler error","name":"cloudon-ingress","namespace":"cloudon","error":"AccessDenied: User: arn:aws:sts::[account id]:assumed-role/AmazonEKSLoadBalancerControllerRole/xxxxxxxxxxxxx is not authorized to perform: elasticloadbalancing:DeleteLoadBalancer on resource: arn:aws:elasticloadbalancing:[region]:[account id]:loadbalancer/app/xxxxxx-cloudon-cloudonin-xxxx/xxxxxxxxxxxx because no identity-based policy allows the elasticloadbalancing:DeleteLoadBalancer action\n\tstatus code: 403, request id: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}

 

 

확인해보니 해당 역할 신뢰관계에 해당 EKS 클러스터의 OIDC 네임스페이스가 특정 네임스페이스만 명시적으로 sts 액션이 허용되어있어, cloudon 네임스페이스를 추가하였다.

 

        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::[account id]:oidc-provider/oidc.eks.[region].amazonaws.com/id/[eks oidc id]"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.[region].amazonaws.com/id/[eks oidc id]:sub": "system:serviceaccount:cloudon:aws-load-balancer-controller",
                    "oidc.eks.[region].amazonaws.com/id/[eks oidc id]:aud": "sts.amazonaws.com"
                }
            }
        }

 

허용 후 바로 해결되었다.

 

kubectl을 이용해 cloudwatch agent 배포후 해당 pod 가 이미지 pull에 실패해 backoff 된것을 확인했다.

 

아래 명령어를 사용해서 에러 원인이 추정 가능했다.

 

kubectl describe pod cloudwatch-agent-xxxx -n amazon-cloudwatch

Scheduled -> Pulling -> Failed -> BackOff

Error: ErrImagePull
Error: ImagePullBackOff

 

해당 에러메시지가 있는 화면에서 Scheduled Message Event의 ip-xx-xx-xxx-xxx.ap-northeast-1.compute.internal 부분을 확인하면 어떤 인스턴스의 ENI가 네트워킹에 사용되었는지 확인가능하고, 해당 EKS 인스턴스의 서브넷에 443 port 연결 허용 및 라우팅 추가 후 위에 이용된 ENI에 임시로 ENI를 붙여 인터넷이 되게 하여 이미지 풀이 가능하게 한다.

그다음 작업과 관련된 해당 pod를 삭제하면 스케줄링에 의해 새로운 pod가 배포되며 이미지를 가져와서 running상태로 바뀐다.

 

kubectl delete pod cloudwatch-agent-fz4hj -n amazon-cloudwatch

작업한 pod를 삭제 후 다시 해당 네임스페이스에 get pod 하면 새로운 pod가 배포중인 것이 확인된다.

kubectl get pod -n amazon-cloudwatch

위에서는 cloudwatch-agent-pdklg pod가 새로 배포되었다.

 

해당 EKS pod의 private 한 연결 상태를 유지하고 이미지를 배포하길 바란다면 아래 방법을 이용해보자.

 

To download a container image from public server(public ec2) and then deploy it to a pod in a private EKS cluster (private pod), you can follow these general steps:

  1. Connect to the public EC2 instance and use a command-line tool like Docker or Podman to download the container image that you want to deploy.

For example, if you're using Docker, you can use the following command to download an image from Docker Hub:

docker pull <image-name>
  1. After downloading the image, you can save it to a file using the Docker save command. This will create a tar archive of the image and its dependencies that you can transfer to another machine.
docker save <image-name> > <image-file>.tar
  1. Transfer the image file to a machine that has access to your private EKS cluster. You can use tools like SCP or AWS S3 to transfer the file.
  2. On the machine that has access to the EKS cluster, use the Docker load command to load the image from the file.
docker load < <image-file>.tar
  1. After loading the image, you can create a Kubernetes deployment or pod definition that references the new image. You can use the kubectl apply command to apply the configuration.
kubectl apply -f <deployment-or-pod-definition>.yaml

Note that to deploy a container image to a private EKS cluster, you will need to have the necessary credentials and permissions to access the EKS cluster and deploy the image. You may also need to configure network settings to allow the pod to access any required resources, such as databases or other services.

 

========================================================

명령어 메모:

특정 네임스페이스에 pod 생성:

kubectl run <POD_NAME> --image=<IMAGE_NAME> --namespace=<NAMESPACE_NAME>

모든 네임스페이스에 대한 pod 확인:

kubectl get pods --all-namespaces

kubectl get pods -A

 

Sample of error: 
Unable to connect to the server: getting credentials: decoding stdout: no kind "ExecCredential" is registered for version "client.authentication.k8s.io/v1alpha1 " in scheme "pkg/client/auth/exec/exec.go:62"

 

Preferred check list:

 

-. Need to verify if the communication with the endpoint is normal or not.

-. The version of AWS CLI should be latest.

-. Please check if there's any difference in kubectl version for client and server. this gap can cause this kind of error.

The command of checking each version:

kubectl version --short

-. Please update apiVersion value in User section of .kube/config file to client.authentication.k8s.io/v1beta1
or run "aws eks update-kubeconfig --region region-code --name my-cluster" after updating kubectl version.

 

Reference:

https://github.com/aws/aws-cli/issues/6920
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
https://kubernetes.io/releases/version-skew-policy/
https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html
https://stackoverflow.com/questions/73744199/unable-to-connect-to-the-server-getting-credentials-decoding-stdout-no-kind

Firstly, Create IAM Role with below permission for replication job.

 

Trust relationships

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "s3.amazonaws.com",
                    "batchoperations.s3.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

IAM Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetObjectVersionAcl",
                "s3:GetObjectVersionTagging",
                "s3:GetObjectRetention",
                "s3:GetObjectLegalHold"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::source-bucket-A",
                "arn:aws:s3:::source-bucket-A/*",
                "arn:aws:s3:::destination-bucket-B",
                "arn:aws:s3:::destination-bucket-B/*"
            ]
        },
        {
            "Action": [
                "s3:ReplicateObject",
                "s3:ReplicateDelete",
                "s3:ReplicateTags",
                "s3:ObjectOwnerOverrideToBucketOwner"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::source-bucket-A/*",
                "arn:aws:s3:::destination-bucket-B/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:InitiateReplication",
                "s3:GetReplicationConfiguration",
                "s3:PutInventoryConfiguration"
            ],
            "Resource": [
                "arn:aws:s3:::source-bucket-A",
                "arn:aws:s3:::source-bucket-B/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::source-bucket-A/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt",
                "kms:GenerateDataKey"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-2:[Source A Account ID]:key/[keystrings]"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:GenerateDataKey",
                "kms:Encrypt"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-2:[Destination B Account ID]:key/[keystrings]"
            ]
        }
    ]
}

The action of KMS will depend on the encryption setting of the S3 bucket.

 

Due to the requirement of the setting, a replication rule of S3 bucket management in source account A has been created with below.

Object ownership: Transfer to destination bucket owner
AWS KMS key for encrypting destination objects: The KMS arn of destination acccount B was put in place.
The batch job will be completed if the role was properly matched with enough permission.
 
To receive replicated objects in B Account, the S3 bucket should have relevant permission inside of bucket policy.
 
{
    "Sid": "S3PolicyStmt-DO-NOT-MODIFY-1670218832531",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::[Source A Account ID]:root"
    },
    "Action": [
        "s3:GetBucketVersioning",
        "s3:PutBucketVersioning",
        "s3:ReplicateObject",
        "s3:ReplicateDelete"
    ],
    "Resource": [
        "arn:aws:s3:::destination-bucket-B",
        "arn:aws:s3:::destination-bucket-B/*"
    ]
}
 

Below is an included version of above permission to change object ownership to destination bucket owner.

{
    "Sid": "S3PolicyStmt-DO-NOT-MODIFY-1670219041656",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::[Source Account A]:root"
    },
    "Action": [
        "s3:GetBucketVersioning",
        "s3:PutBucketVersioning",
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ObjectOwnerOverrideToBucketOwner"
    ],
    "Resource": [
        "arn:aws:s3:::destination-bucket-B",
        "arn:aws:s3:::destination-bucket-B/*"
    ]
}

The KMS Policy also needs to allow source account as below.

{
    "Sid": "Enable cross account encrypt access for S3 Cross Region Replication",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::[Source Account A]:root"
    },
    "Action": [
        "kms:Encrypt"
    ],
    "Resource": "*"
}

'aws > s3' 카테고리의 다른 글

AWS S3 CRR vs SRR replication (교차 리전 복제, 동일 리전 복제)  (0) 2023.03.13
S3 Storage Classes  (0) 2023.03.13

 

Code Sample

#!/bin/bash

InstanceID=("i-xxxxxxxxx" "i-xxxxxxxxxxxxxxxxxxx" "i-xxxxxxxxxxxx65")
ImageName="create-ami"
CurrentTime=`date +%Y%m%d`
ImageVersion=${2:-v1.1.1}
ImageDescription="create-ami-by-script"
num=1


for value in "${InstanceID[@]}";
do
            aws ec2 create-image \
                         --instance-id $InstanceID \
                          --name $ImageName-$CurrentTime-$ImageVersion-$value-$num \
                           --description "$ImageDescription" \
           --tag-specifications 'ResourceType=image,Tags=[{Key=Name,Value=create-ami}]' \
                            'ResourceType=snapshot,Tags=[{Key=Name,Value=create-ami}]' \
                --region ap-northeast-2 --debug --profile awsprofile
                			((num+=1))
                            echo $value
done

 

To get each ec2 instance ID with aws cli for comfort,

below is the sample code to implement.

 

$ aws ec2 describe-instances \
 --profile awsprofile \
 --query 'Reservations[*].Instances[*].{Instance:InstanceId,Subnet:SubnetId}' \
 --output text --region ap-northeast-2

 

adding below option will prevent inaccurate order of ami creation since the reboot will take some time to operate for each target server.

--no-reboot

 

reference: https://docs.aws.amazon.com/cli/latest/reference/ec2/create-image.html

 

 

[2022 년 6월 기준]

 

MFA 설정을 한 IAM 계정을 사용 중, 기변으로 인해 등록된 디바이스를 바꿀때

필요한 권한을 할당받은 상태에서 설정함에도 "개체 이미 존재" (MFA Device entity at the same path and name already exists) 에러가 발생하면서 MFA 토큰 추가 화면으로 넘어가지 않는 경우가 있다.

말그대로 이미 생성되어있어서 마주하는 에러지만, 이미 삭제 후 유저에게 재등록하도록 가이드를 한 경우에도 발생할 수 있다.

확인결과, 가상 MFA 디바이스 설정 버튼을 통해 MFA 디바이스 등록 진행 중, 아직 실제로 등록을 완료하지 못한 초기 안내 화면에서도 엔터티는 자동으로 생성되어, 실제로 등록을 끝마치치 않은 상태에서도 자꾸 엔터티가 생겨 해당 에러를 마주하는 것으로 보인다.

해당 경우에는 AWS CLI로 엔터티가 생기는지 확인하고, 생성된 엔터티를 바로 지운다음 등록화면 재 진입시 에러가 사라지고 QR코드 등록 화면으로 넘어가지는 것을 확인할 수 있었다.

 

 

MFA Device error

 

AWS CLI로 특정 유저의 mfa 엔터티 확인

$ aws iam list-virtual-mfa-devices | grep testuser
            "SerialNumber": "arn:aws:iam::265919665173:mfa/testuser"

 

AWS CLI로 delete-virtual-mfa-device 명령어를 통해 해당 엔터티 삭제 후, list-virtual-mfa-devices 를 하여 삭제된 것을 확인하였다. 그다음에 다시 MFA 디바이스 설정 버튼으로 설정 초기화면에 넘어가면 바로 엔터티가 다시 생성된 것을 확인하였다.

$ aws iam delete-virtual-mfa-device --serial-number arn:aws:iam::265919665173:mfa/testuser
$ aws iam list-virtual-mfa-devices | grep testuser
$ aws iam list-virtual-mfa-devices | grep testuser
            "SerialNumber": "arn:aws:iam::265919665173:mfa/testuser"

 

유저가 디바이스 등록을 하기전에 생성된 엔터티를 삭제하면 해당 에러를 건너뛰고 QR코드 등록안내 화면으로 넘어가진다.

 

 

+ Recent posts