https://repost.aws/knowledge-center/aurora-mysql-stop-cluster-seven-days

 

Stop Amazon Aurora cluster for longer than seven days

I want to stop an Amazon Relational Database Service (Amazon Aurora clusters) for longer than the seven-day duration.

repost.aws

 

  • Aurora 특성상 7 Days 이후에는 자동으로 시작
  • Lambda - EventBridge(스케쥴) 로 AutoStop 생성
    • AWS SNS 서비스로 Event 수신
  • Chatops 
    • Slackbot 으로 방식으로 Aurora 현재 상태 확인및 테스트 이후 Stop & Start 구현
import json
import os
import time
from urllib import request, parse
import boto3

def lambda_handler(event, context):
    try:
        bot_token = os.environ.get('BOT_TOKEN')
        if not bot_token:
            raise ValueError("BOT_TOKEN environment variable is not set")
        
        body = json.loads(event['body'])
        print(f"Received body: {body}")
        
        if 'challenge' in body:
            return {
                'statusCode': 200,
                'body': json.dumps({'challenge': body['challenge']})
            }
            
        if 'event' in body:
            if 'token' in body and body['token'] != os.environ.get('VERIFICATION_TOKEN'):
                return {
                    'statusCode': 403,
                    'body': json.dumps({'error': 'Invalid verification token'})
                }
                
            slack_event = body['event']
            if (slack_event['type'] == 'message' and 
                'channel_type' in slack_event and 
                slack_event['channel_type'] == 'channel' and
                'text' in slack_event):
                
                text = slack_event.get('text', '').strip()
                print(f"text: {text}")
                
                if text.startswith("stop "):
                    cluster_name = text.split("stop ")[1].strip()
                    initial_response = stop_specific_rds_cluster(cluster_name)
                    
                    # 초기 응답 전송
                    post_message_to_slack(initial_response, slack_event['channel'], bot_token)
                    
                    # 중지가 성공적으로 시작된 경우에만 상태 확인
                    if "Stopping cluster" in initial_response:
                        # 상태 확인 및 결과 전송
                        status_response = wait_for_cluster_stop(cluster_name)
                        post_message_to_slack(status_response, slack_event['channel'], bot_token)
        
        return {
            'statusCode': 200,
            'body': json.dumps({'message': 'Success'})
        }
        
    except Exception as e:
        print(f"Error in lambda_handler: {str(e)}")
        return {
            'statusCode': 500,
            'body': json.dumps({'error': str(e)})
        }

def wait_for_cluster_stop(cluster_name, max_attempts=30, delay_seconds=10):
    """
    RDS 클러스터가 완전히 중지될 때까지 대기하고 상태를 확인합니다.
    
    Args:
        cluster_name (str): RDS 클러스터 식별자
        max_attempts (int): 최대 확인 시도 횟수
        delay_seconds (int): 각 확인 사이의 대기 시간(초)
    
    Returns:
        str: 상태 확인 결과 메시지
    """
    rds_client = boto3.client('rds')
    attempt = 0
    
    try:
        while attempt < max_attempts:
            cluster = rds_client.describe_db_clusters(
                DBClusterIdentifier=cluster_name
            )['DBClusters'][0]
            
            current_status = cluster['Status']
            
            if current_status == 'stopped':
                return f"✅ Cluster {cluster_name} has been successfully stopped."
            elif current_status == 'stopping':
                if attempt == 0:
                    return f"⏳ Cluster {cluster_name} is stopping. Status will be updated..."
                time.sleep(delay_seconds)
                attempt += 1
            else:
                return f"❌ Unexpected cluster status: {current_status}. Please check manually."
        
        return f"⚠️ Timeout waiting for cluster {cluster_name} to stop. Current status: {current_status}"
        
    except rds_client.exceptions.DBClusterNotFoundFault:
        return f"❌ Error: Cluster {cluster_name} not found during status check."
    except Exception as e:
        error_msg = f"❌ Error checking cluster status: {str(e)}"
        print(error_msg)
        return error_msg

def post_message_to_slack(response_text, channel_id, bot_token):
    try:
        url = "https://slack.com/api/chat.postMessage"
        headers = {
            'Authorization': f"Bearer {bot_token}",
            'Content-Type': 'application/json'
        }
        payload = json.dumps({
            'channel': channel_id,
            'text': response_text
        }).encode('utf-8')
        
        req = request.Request(url, data=payload, headers=headers)
        response = request.urlopen(req)
        response_data = json.loads(response.read().decode())
        
        if not response_data.get('ok'):
            print(f"Slack API error: {response_data.get('error')}")
            
    except Exception as e:
        print(f"Error posting message to Slack: {str(e)}")

def stop_specific_rds_cluster(cluster_name, rds_client=None):
    if rds_client is None:
        rds_client = boto3.client('rds')
        
    try:
        cluster = rds_client.describe_db_clusters(
            DBClusterIdentifier=cluster_name
        )['DBClusters'][0]
        
        if cluster['Status'] != 'available':
            return f"❌ Cluster {cluster_name} is not in available state (current: {cluster['Status']})."
            
        tags = rds_client.list_tags_for_resource(
            ResourceName=cluster['DBClusterArn']
        )['TagList']
        
        if not any(tag['Key'] == 'autostop' and tag['Value'] == 'yes' 
                  for tag in tags):
            return f"❌ Cluster {cluster_name} does not have required autostop tag."
            
        rds_client.stop_db_cluster(DBClusterIdentifier=cluster_name)
        return f"⏳ Stopping cluster: {cluster_name}..."
        
    except rds_client.exceptions.DBClusterNotFoundFault:
        return f"❌ Cluster {cluster_name} not found."
    except Exception as e:
        error_msg = f"❌ Error stopping cluster {cluster_name}: {str(e)}"
        print(error_msg)
        return error_msg

mysql version  8.4 LTS

  • 8.4 변동사항 많아서 보류
  • 8.0.4 로 uprade
https://dev.mysql.com/blog-archive/introducing-mysql-innovation-and-long-term-support-lts-versions/

 

한대의 인스턴스 Minor Upgrade 순서

- MySQL 셧다운 → 엔진파일 덮어쓰기(변경) → MySQL 서버(mysqld) 시작 → MySQL upgrade 실행
- 업그레이드 시 mysqld vs mysql_upgrade
실제 업그레이드는 두가지 단계로 나뉘어서 처리 ( 1단계: mysqld, 2단계 : mysql_upgrade)

 

순서

 

  • mysql 8,0.4 download & 압축해제ll
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.40-linux-glibc2.28-x86_64.tar.xz
sudo su
tar -xvf mysql-8.0.40-linux-glibc2.28-x86_64.tar.xz -C /usr/local​
  • 심볼릭 링크  해재 후 재설정
cd /usr/local
unlink mysql
ln -s mysql-8.0.40-linux-glibc2.28-x86_64 mysql​

 

  • mysql 중지
/usr/local/mysql/bin/mysqladmin -u root -p shutdown
  • upgrade 수행
/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf &


업그레이드 프로그램 
8.0.16 미만 : mysql_upgrade
8.0.16 이상 : mysqld

로그 확인
2024-12-10T10:50:44.469133-00:00 4 [System] [MY-013381] [Server] Server upgrade from '80023' to '80200' started.
2024-12-10T10:50:51.334428-00:00 4 [System] [MY-013381] [Server] Server upgrade from '80023' to '80200' completed.
  • my.cnf 변경
expire_logs_days=7
-> binlog_expire_logs_seconds=604800
  • mysqlcheck
 /usr/local/mysql/bin/mysqlcheck -u root -p --all-databases --check-upgrade​
  • version 확인
SELECT @@version​

'MySQL (Aurora) > Troubleshooting' 카테고리의 다른 글

메모리 Resize 장애 (MHA)  (3) 2024.09.25
Mysql 5.7 Online DDL varchar column size변경  (1) 2024.09.03
  • key_lenght 가 실제 인덱스 길이보다 짧다면 인덱스 정상적으로 안타는것
  • 실행계획 확인시 key_lenght도  말고 filterd 조건을 자세히 봐야한다
    • filterd  조건이 높을수록 인덱스를 정상적으로 탐색
    • filterd  낮을수록 남은 row가 많다는 뜻 인덱스를 정상적으로 안탐

 

filerd가 1이므로 나머지 99% 남았다는뜻 - 인덱스 확인 필요

'MySQL (Aurora) > DB Tuning' 카테고리의 다른 글

인덱스 힌트  (0) 2024.10.07
형 변환 튜닝  (2) 2024.10.02

 

AWS 코드 - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/db_cluster_snapshot

 

Terraform Registry

 

registry.terraform.io

 

mkdir ~/terraform-aurora
cd ~/terraform-aurora

terraform init   # 플러그인 초기화
terraform plan   # 실행 계획 확인
terraform apply  # 리소스 생성

 

  • main.tf 생성후 terrafrom build 처리
    • terrafrom init  (초기화)
    • terrafrom plan (확인)
    • terrafrom apply (생성) 

 

    • terrfafom init

 

  • terrafom plan

 

  • terrafom apply

'IAC > Terraform' 카테고리의 다른 글

terraform 설치  (0) 2024.11.29
AWS CLI 설치

# Linux x86 (64-bit)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

 

Terraform 설치
https://developer.hashicorp.com/terraform/install

sudo yum install -y yum-utils shadow-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo yum -y install terraform

which terraform
terraform version

'IAC > Terraform' 카테고리의 다른 글

terraform aurora create  (0) 2024.11.29
가이드
https://www.bytebase.com/docs/get-started/self-host/

 

## Locky 8

## 1) yum repository 관리에 필요한 yum-utils 를 설치
sudo yum install -y yum-utils

## 2) Docker repository 추가
sudo yum-config-manager \
	--add-repo \
	https://download.docker.com/linux/centos/docker-ce.repo

## 3) Docker Engine 설치
sudo yum install docker-ce docker-ce-cli containerd.io


## 4) Docekr 실행
sudo systemctl start docker


## 5) 확인
sudo docker run hello-world

 

트러블 슈팅 - proxy 설정

## 오류코드
locky 8 docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).

 

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf


# http-proxy.conf 파일 내 작성할 내용
[Service]
Environment="HTTP_PROXY=http://xxx"
Environment="HTTPS_PROXY=http://xxx"
Environment="NO_PROXY=xxx"

## daemon-reload
sudo systemctl daemon-reload
sudo systemctl restart docker

 

실행

docker run --rm --init \
  --name bytebase \
  --publish 8080:8080 --pull always \
  --volume ~/.bytebase/data:/var/opt/bytebase \
  bytebase/bytebase:3.0.0 &
  • DB 단위 Backup & Restore
    • DB Backup
      • General > FileName , Encoding - UTF 8 설정
      • Data Options > Pre-data , Data , Post-data
      • Table Options > Use Column Insert                       

 

  • Restore
    • General > Backup Fillname
    • Data Options > Pre-data , Data , Post-data

'Postgresql > TECH' 카테고리의 다른 글

계정 및 권한 설정  (0) 2024.11.29
기본구조  (1) 2024.11.29
  • 보안 제어
  • Database > Schema > Table 단위로 권한설정
  • 추후 추가 되는 Table에 대해 자동으로 권한 설정

계정Role스크립트비고

초기세팅 postgres Revoke revoke all on database postgres from public; system db에 접근 제어
_dba Super create role dbabwith password 'password' login;
alter user sgp_dba with superuser;
SELECT * FROM pg_roles; (확인방법)
_app DML use db명;
create role app with password 'password' login;
GRANT SELECT,INSERT,DELETE,UPDATE ON ALL TABLES IN SCHEMA public TO app ;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, UPDATE, INSERT, DELETE ON TABLES to app ;




app 계정 dml 권한추가
스키마에 dml 권한 부여
이후 추가되는 테이블에 대해 자동 권한 부여
_dev ALL












SELECT
use db명;
create role _dev with password 'password' login;
GRANT ALL  ON  SCHEMA public to sookyshin_dev ;

ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT all privileges ON TABLES to sookyshin_dev ;




use db명;
create role _dev   with password 'password' login;
grant SELECT on database db명 to _dev  ;

GRANT SELECT ON  SCHEMA public to _dev  ;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES to _dev  ;



dev 환경은 모든 권한
DB에 권한부여
SCHEMA에 권한부여
이후 추가되는 테이블에 대해 자동 권한 부여




DB에 권한부여
SCHEMA에 권한부여
이후 추가되는 테이블에 대해 자동 권한 부여

 

'Postgresql > TECH' 카테고리의 다른 글

Backup & Restore  (0) 2024.11.29
기본구조  (1) 2024.11.29

Object - Data를 저장하거나 참조하는데 사용되는 데이터 구조 ( 테이블 , 인덱스 , 프로시저 , 시퀀스 , 뷰 등)
Schema - Object 들의 집합 . 하나의 Database는 다수 Schema를 가질수 있으며 Pubic Schema는 기본 Schema
Rele - Database 관련 권한들을 특정 이름으로 모아 놓은것
TableSpace - Object(테이블, 인덱스 등) 가 저장되는 파일 시스템의 위치를 정의해 놓은것

 

  • Schema

 

     DataBase > table > entity

schema의 사전적 정의는 data를 저장하는 구조이고,
쉽게 말하면 data들이 저장된 table을 모여있는 곳이다.

 

 

'Postgresql > TECH' 카테고리의 다른 글

Backup & Restore  (0) 2024.11.29
계정 및 권한 설정  (0) 2024.11.29

컨테이너 관리서비스

EKS ECS
오픈소스 AWS에 국한된 서비스
EC2 내 여러 Pod가 묶여 하나의 ENI 공유 가능 EC2 내 Task 별로 ENI를 할당받음
마이그레이션이 쉽다.
(타 클라우드 플랫폼, On-Premise 등에도 실행 가능)
마이그레이션이 어렵다.
(AWS에 최적화 되어 있으며, 타 AWS 서비스와 함께 클러스러를 이용하고 있으면)
etc ... etc ...

 

+ Recent posts