목차
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
'1인개발 메이킹로그 > [Infra+k8s+App] 가상화폐 자동매매' 카테고리의 다른 글
[Error] string indices must be integers (0) | 2023.06.24 |
---|---|
[테스트] Dockerfile 'CMD' / kubernetes cronjob (0) | 2023.06.19 |
[테스트] image 생성 및 pod 생성 (0) | 2023.06.15 |
[AWS-Server] Troubleshooting - ModuleNotFoundError: No module named 'pyupbit' (0) | 2023.05.20 |
[AWS-Server] CICD Pipeline (0) | 2023.04.12 |