공부하기싫어
article thumbnail

목차

     

    Prototype-v.1 : 레거시 POD 배포

    - 인스턴스에서 proccess 로 동작하던 앱을 container 에서 동작하도록 pod 구성

    - AWS credential 은 Dockerfile 에서 환경변수로 구성하여 사용함 -> 추후 따로 분리해야함

    - image 는 docker hub 의 private repository push/pull 하여 사용

    - container 의 requirements.txt 명세와 pod의 평균 리소스 사용량 파악 목표

    - k8s cronjob 반영

     

    1. Image 생성

    base image : python:3.10

    container image$ tree
    .
    ├── apps
    │   ├── aws_defs.py
    │   ├── log_defs.py
    │   ├── __main__.py
    │   └── upbit_defs.py
    ├── aws-credential.sh
    ├── Dockerfile
    ├── requirements.txt
    └── run.sh

    1.1 apps

    __main__.py

    import pyupbit
    import datetime
    import upbit_defs as m_upbit
    import log_defs as m_log
    import time
    import schedule
    import boto3
    
    def get_parameter_fromSSM() :
        ssm = boto3.client('ssm')
    
        parameters=['/ethereum-autotrade/upbit-key/access-key',
                    '/ethereum-autotrade/upbit-key/secret-key']
        upbit_keys=list()
    
        for i in parameters:
            response = ssm.get_parameter(
                Name=i,
                WithDecryption=True
            )
            upbit_keys.append(response['Parameter']['Value'])
        
        return upbit_keys[0],upbit_keys[1]
    
    global best_k
    global predicted_end_price
    def read_dynamoDB_table() :
        global best_k
        global predicted_end_price
        dynamodb = boto3.resource('dynamodb')
        table = dynamodb.Table('table-for-Ethereum-Autotrade')
    
        response = table.get_item(
            Key={
                'Env': 'Dev'
            }
        )
    
        item = response['Item']
        best_k = item['k-value']
        predicted_end_price = item['endprice']
    
        return best_k, predicted_end_price
    
    
    def main():
        global best_k
        global predicted_end_price
    
        d = datetime.datetime.now()
        year=str(d.strftime("%Y"))
        month=str(d.strftime("%m"))
        day=str(d.strftime("%d"))
        log_file_name="output"+year+month+day+".log"
    
        logfile=m_log.open_logfile(log_file_name)
    
        try :
            upbit_access_key, upbit_secret_key = get_parameter_fromSSM()
            bestk,predicted_end_price= read_dynamoDB_table()
            logs="success : get_parameter_fromSSM, read_dynamoDB_table"
            m_log.write_and_flush_logs(logfile, logs)
        except Exception as e:
            logs="failure : get_parameter_fromSSM, read_dynamoDB_table"
            m_log.write_and_flush_logs(logfile, logs)
            logs="Exception : "+str(e)
            m_log.write_and_flush_logs(logfile, logs)
        schedule.every().hour.do(lambda: read_dynamoDB_table())
    
        try :
            upbit_login = pyupbit.Upbit(upbit_access_key, upbit_secret_key)
            logs="success : login"
            m_log.write_and_flush_logs(logfile, logs)
        except Exception as e:
            logs="failure : login"
            m_log.write_and_flush_logs(logfile, logs)
            logs="Exception : "+str(e)
            m_log.write_and_flush_logs(logfile, logs)
        
        try :
            '''자동매매'''
            dt_today=datetime.datetime.now()
            logs="start daily autotrade : "+str(dt_today)
            m_log.write_and_flush_logs(logfile, logs)
    
            # trading start
            log_cup=0
            while True:
                try:
                    now = datetime.datetime.now()
                    start_time = m_upbit.get_start_time("KRW-ETH")
                    end_time = start_time + datetime.timedelta(days=1)
                    dt_now = datetime.datetime.now()
    
                    if start_time < now < end_time - datetime.timedelta(minutes=5):
                        target_price = m_upbit.get_target_price("KRW-ETH", float(bestk))
                        current_price = m_upbit.get_current_price("KRW-ETH")
                        if target_price < current_price and current_price < predicted_end_price:
                            krw = m_upbit.get_balance("KRW", upbit_login)
                            if krw > 5000:
                                upbit_login.buy_market_order("KRW-ETH", krw*0.9995)
                                logs="buy_market_order : "+str(dt_now)
                                m_log.write_and_flush_logs(logfile, logs)
                        else :
                            if log_cup==10 :
                                logs="running :"+str(dt_now)
                                m_log.write_and_flush_logs(logfile, logs)
                                log_cup=0
                    else:
                        eth = m_upbit.get_balance("ETH", upbit_login)
                        if eth > 0.00008:
                            upbit_login.sell_market_order("KRW-ETH", eth*0.9995)
                        break
                    time.sleep(1); log_cup=log_cup+1
                except Exception as e:
                    logs="Exception : "+str(e)
                    m_log.write_and_flush_logs(logfile, logs)
                    time.sleep(1)
    
            dt_today=datetime.datetime.now()
            logs="shutdown daily autotrade : "+str(dt_today)
            m_log.write_and_flush_logs(logfile, logs)
    
            m_log.close_logfile(logfile)
            m_log.send_logs_to_s3(log_file_name)
    
        except Exception as e:
            logs="failure : trading"
            m_log.write_and_flush_logs(logfile, logs)
            logs="Exception : "+str(e)
            m_log.write_and_flush_logs(logfile, logs)
    
    main()

     

    aws_defs.py

    import boto3
    
    def read_dynamoDB_table() :
        dynamodb = boto3.resource('dynamodb')
        table = dynamodb.Table('table-for-Ethereum-Autotrade')
    
        response = table.get_item(
            Key={
                'Env': 'Dev'
            }
        )
    
        item = response['Item']
        best_k = item['k-value']
        predicted_end_price = item['endprice']
    
        return best_k, predicted_end_price
    
    
    
    def get_parameter_fromSSM() :
        ssm = boto3.client('ssm')
    
        parameters=['/ethereum-autotrade/upbit-key/access-key',
                    '/ethereum-autotrade/upbit-key/secret-key']
        upbit_keys=list()
    
        for i in parameters:
            response = ssm.get_parameter(
                Name=i,
                WithDecryption=True
            )
            upbit_keys.append(response['Parameter']['Value'])
        
        return upbit_keys[0],upbit_keys[1]

     

    logs_defs.py

    import boto3
    import os
    
    def open_logfile(n):
        log_file_name=n
        f=open(log_file_name, 'a')
        return f
    
    def write_and_flush_logs(f, log_string):
        logs=log_string+"\n"
        f.write(logs); f.flush()
    
    def close_logfile(f):
        f.close()
    
    def send_logs_to_s3(n):
        bucket_name="logs-ethereum-autotrade"
        file_path=n
        session = boto3.Session(profile_name='default')
    
        s3=session.client('s3')
        f=open(file_path, 'rb')
        s3.upload_fileobj(f, bucket_name, file_path)

     

    upbit_defs.py

    import pyupbit
    
    def get_target_price(ticker, k):
        """변동성 돌파 전략으로 매수 목표가 조회"""
        df = pyupbit.get_ohlcv(ticker, interval="day", count=2)
        target_price = df.iloc[0]['close'] + (df.iloc[0]['high'] - df.iloc[0]['low']) * k
        return target_price
    
    def get_start_time(ticker):
        """시작 시간 조회"""
        df = pyupbit.get_ohlcv(ticker, interval="day", count=1)
        start_time = df.index[0]
        return start_time
    
    def get_balance(ticker, upbit):
        """잔고 조회"""
        balances = upbit.get_balances()
        for b in balances:
            if b['currency'] == ticker:
                if b['balance'] is not None:
                    return float(b['balance'])
                else:
                    return 0
        return 0
    
    def get_current_price(ticker):
        """현재가 조회"""
        return pyupbit.get_orderbook(ticker=ticker)["orderbook_units"][0]["ask_price"]

     

     

    requirements.txt

    pyupbit
    boto3
    schedule

     

    run.sh

    export AWS_ACCESS_KEY_ID=[my aws iam user access key]
    export AWS_SECRET_ACCESS_KEY=[my aws iam user secret access key]
    export AWS_DEFAULT_REGION=ap-northeast-2
    
    sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
    today=$(date "+%Y%m%d")
    python3 apps/__main__.py > output${today}.log &

     

    1.2 Dockerfile

    FROM python:3.10
    
    RUN apt-get update && apt-get install -y \
        awscli \
        vim
    
    WORKDIR /home
    
    COPY . .
    
    RUN pip install --upgrade pip
    RUN pip3 install -r requirements.txt
    
    CMD ["sh", "run.sh"]

     

    1.3 hub.docker

    hub.docker 에 private repository 생성 후 build / push

    docker build --tag cyaninn/eth-at-prototype:v1.1 .
    docker push cyaninn/eth-at-prototype:v1.1

     

    2. pod manifest yaml file

    2.1 k8s secret 생성

    $ k create secret docker-registry regcred -n prototype \
        --docker-server=https://index.docker.io/v1/ \
        --docker-username=<your-name> --docker-password=<your-pword> \
        --docker-email=<your-email>
    secret/regcred created

     

    secret 검증

    k get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode

     

     

    2.2 secret / cronjob 이 포함된 pod 생성 yaml file

    pod-prototype-v1.yaml

    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: eth-at-prototype-v1
      namespace: prototype
    spec:
      schedule: "0 0 * * *"
      jobTemplate:
        spec:
          template:
            metadata:
              labels:
                app: eth-at-prototype-v1
                namespace: prototype
            spec:
              containers:
              - name: python-app
                image: cyaninn/eth-at-prototype:v1.2
              imagePullSecrets:
              - name: regcred
              restartPolicy: OnFailure

    ※cronjob 은 UTC 기준으로 KST -9 값을 적용

     

    3. 동작 확인

    $ k get all -n prototype
    NAME                                SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    cronjob.batch/eth-at-prototype-v1   0 0 * * *   False     0        <none>          21s

    ※ 오전 9시 이후 동작 확인 필요

     

    3.1 익일 오전 동작 확인

    $ date
    Mon Jun 19 11:52:22 KST 2023
    
    
    $ k get all -n prototype
    NAME                                     READY   STATUS    RESTARTS   AGE
    pod/eth-at-prototype-v1-28118880-qjfpz   1/1     Running   0          170m
    
    NAME                                SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    cronjob.batch/eth-at-prototype-v1   0 0 * * *   False     1        170m            8h
    
    NAME                                     COMPLETIONS   DURATION   AGE
    job.batch/eth-at-prototype-v1-28118880

     

    Prototype v2 반영 목록

    • PV 할당해서 output 파일 보관
    • AWS Credential 을 코드에서 분리
    • local repository(code, image) 설계 및 구축

     

     

    참고

    https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/cli-configure-envvars.html

     

    환경 변수를 사용하여 AWS CLI 구성 - AWS Command Line Interface

    환경 변수를 사용하여 AWS CLI 구성 환경 변수는 구성 옵션과 보안 인증을 지정하는 다른 방법을 제공하며, 스크립팅을 수행하거나 명명된 프로필을 임시로 기본값으로 설정할 때 유용할 수 있습

    docs.aws.amazon.com

     

    https://kubernetes.io/ko/docs/tasks/configure-pod-container/pull-image-private-registry/#%EC%BB%A4%EB%A7%A8%EB%93%9C-%EB%9D%BC%EC%9D%B8%EC%97%90%EC%84%9C-%EC%9E%90%EA%B2%A9-%EC%A6%9D%EB%AA%85%EC%9D%84-%ED%86%B5%ED%95%98%EC%97%AC-%EC%8B%9C%ED%81%AC%EB%A6%BF-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0

     

    프라이빗 레지스트리에서 이미지 받아오기

    이 페이지는 프라이빗 컨테이너 레지스트리나 리포지터리로부터 이미지를 받아오기 위해 시크릿(Secret)을 사용하는 파드를 생성하는 방법을 보여준다. 현재 많은 곳에서 프라이빗 레지스트리가

    kubernetes.io