💡수업 목표💡
- Flask 프레임워크를 활용해서 API를 만들 수 있다.
- '버킷리스트'를 완성한다.
- EC2에 내 프로젝트를 올리고, 자랑한다!
Project03 - 버킷리스트
http://spartacodingclub.shop/web/bucket
프로젝트 준비 및 설정
Flask 폴더 구조 : static / templates / app.py
패키지 설치 : Flask, pymongo, dnspython
프로젝트 뼈대 구성
- app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route("/bucket", methods=["POST"])
def bucket_post():
sample_receive = request.form['sample_give']
print(sample_receive)
return jsonify({'msg': 'POST(기록) 연결 완료!'})
@app.route("/bucket/done", methods=["POST"])
def bucket_done():
sample_receive = request.form['sample_give']
print(sample_receive)
return jsonify({'msg': 'POST(완료) 연결 완료!'})
@app.route("/bucket", methods=["GET"])
def bucket_get():
return jsonify({'msg': 'GET 연결 완료!'})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<link href="https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap" rel="stylesheet">
<title>인생 버킷리스트</title>
<style>
* {
font-family: 'Gowun Dodum', sans-serif;
}
.mypic {
width: 100%;
height: 200px;
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://images.unsplash.com/photo-1601024445121-e5b82f020549?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1189&q=80');
background-position: center;
background-size: cover;
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.mypic > h1 {
font-size: 30px;
}
.mybox {
width: 95%;
max-width: 700px;
padding: 20px;
box-shadow: 0px 0px 10px 0px lightblue;
margin: 20px auto;
}
.mybucket {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.mybucket > input {
width: 70%;
}
.mybox > li {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 10px;
min-height: 48px;
}
.mybox > li > h2 {
max-width: 75%;
font-size: 20px;
font-weight: 500;
margin-right: auto;
margin-bottom: 0px;
}
.mybox > li > h2.done {
text-decoration:line-through
}
</style>
<script>
$(document).ready(function () {
show_bucket();
});
function show_bucket(){
$.ajax({
type: "GET",
url: "/bucket",
data: {},
success: function (response) {
alert(response["msg"])
}
});
}
function save_bucket(){
$.ajax({
type: "POST",
url: "/bucket",
data: {sample_give:'데이터전송'},
success: function (response) {
alert(response["msg"])
}
});
}
function done_bucket(num){
$.ajax({
type: "POST",
url: "/bucket/done",
data: {sample_give:'데이터전송'},
success: function (response) {
alert(response["msg"])
}
});
}
</script>
</head>
<body>
<div class="mypic">
<h1>나의 버킷리스트</h1>
</div>
<div class="mybox">
<div class="mybucket">
<input id="bucket" class="form-control" type="text" placeholder="이루고 싶은 것을 입력하세요">
<button onclick="save_bucket()" type="button" class="btn btn-outline-primary">기록하기</button>
</div>
</div>
<div class="mybox" id="bucket-list">
<li>
<h2>✅ 호주에서 스카이다이빙 하기</h2>
<button onclick="done_bucket(5)" type="button" class="btn btn-outline-primary">완료!</button>
</li>
<li>
<h2 class="done">✅ 호주에서 스카이다이빙 하기</h2>
</li>
<li>
<h2>✅ 호주에서 스카이다이빙 하기</h2>
<button type="button" class="btn btn-outline-primary">완료!</button>
</li>
</div>
</body>
</html>
버킷리스트 등록 API 만들기 - POST 연습
버킷리스트 사이트를 위해서 index.html에서 버킷리스트를 받아서 DB에 저장하기 (Create -> POST)
하지만 이때, 추후에 '완료'로 업데이트가 가능하게 번호를 함께 넣어주는 것이 중요!
1. 요청 정보 : URL=/bucket, 요청 방식 =POST
2. 클라(ajax) → 서버(flask) :bucket
3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (기록 완료!)
app.py - 서버 코드
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('-------mongoDB URL---------')
db = client.dbsparta
@app.route("/bucket", methods=["POST"])
def bucket_post():
bucket_receive = request.form['bucket_give']
# 버킷마다 번호를 부여하기 위해서 전체 버킷을 조회
bucket_list = list(db.bucket.find({}, {'_id': False}))
count = len(bucket_list) +1
doc = {
'num' : count,
'bucket' : bucket_receive,
'done' : 0
}
db.bucket.insert_one(doc)
print(bucket_receive)
return jsonify({'msg': '버킷 등록 완료!'})
index.html - 클라이언트 코드
function save_bucket(){
let bucket = $('#bucket').val()
$.ajax({
type: "POST",
url: "/bucket",
data: {bucket_give:bucket},
success: function (response) {
alert(response["msg"])
window.location.reload()
}
});
}
결과 확인하기
index.html에서 입력후 주문하기 버튼을 클릭했을때 '버킷 등록 완료' 알림창이 나오면 성공이다.
실제로 mongoDB를 확인해서 입력한 값과 num이 정상적으로 추가가 되었는지 까지 확인하면 완벽!
버킷리스트 조회 API 만들기 - GET 연습
버킷리스트 사이트를 위해서 index.html에서 기존에 DB에 저장던 데이터를 받아서 보여주기 (Read -> GET)
1. 요청 정보 : URL= /bucket, 요청 방식 = GET
2. 클라(ajax) → 서버(flask) : (없음)
3. 서버(flask) → 클라(ajax) : 전체 버킷리스트를 보여주기
app.py - 서버 코드
@app.route("/bucket", methods=["GET"])
def bucket_get():
buckets_list = list(db.bucket.find({},{'_id':False}))
return jsonify({'buckets':buckets_list})
index.html - 클라이언트 코드
function show_bucket(){
$('#bucket-list').empty()
$.ajax({
type: "GET",
url: "/bucket",
data: {},
success: function (response) {
let rows = response['buckets']
for (let i = 0; i < rows.length; i++) {
let bucket = rows[i]['bucket']
let num = rows[i]['num']
let done = rows[i]['done']
let temp_html = ``
// 버킷리스트 완료한 것과 안한것은 다르기 때문에 분리 해준다!
// 완료로 업데이트할때 num이 바드시 필요하므로 <button onclick=""> 시 num을 꼭 넣어준다.
if (done == 0) {
temp_html = `<li>
<h2>✅ ${bucket}</h2>
<button onclick="done_bucket(${num})" type="button" class="btn btn-outline-primary">완료!</button>
</li>`
} else {
temp_html = `<li>
<h2 class="done">✅ ${bucket}</h2>
</li>`
}
$('#bucket-list').append(temp_html)
}
}
});
}
결과 확인하기
index.html에서 새로고침할때마다 저장된 데이터 완료/미완료 버전으로 정상적으로 나타나는지 확인되면 성공!
버킷리스트 완료 API 만들기 - POST 연습
버킷리스트 사이트를 위해서 index.html에서 '완료' 버튼을 누르면 해당 버킷리스트가 완료로 DB에 업데이트 하기 (Update -> POST)
이때, create 할때 사용했떤 '번호'를 잘 활용하는 것이 중요!
1. 요청 정보 : URL=/bucket/done, 요청 방식 =POST
2. 클라(ajax) → 서버(flask) :num(버킷 넘버)
3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (버킷 완료!)
app.py - 서버 코드
@app.route("/bucket/done", methods=["POST"])
def bucket_done():
num_receive = request.form['num_give']
#request.formd으로 전달받게 되면 string 타입으로 전달된다. -> int로 변경해서 DB에 전달해야한다.
db.bucket.update_one({'num': int(num_receive)}, {'$set': {'done': 1}})
return jsonify({'msg': '버킷 완료!'})
index.html - 클라이언트 코드
function done_bucket(num){
$.ajax({
type: "POST",
url: "/bucket/done",
data: {'num_give':num},
success: function (response) {
alert(response["msg"])
window.location.reload()
}
});
}
결과 확인하기
index.html에서 입력후 '완료' 버튼을 클릭했을때 '버킷 완료' 알림창이 나오면 성공이다.
AWS EC2
AWS EC2 인스턴스 시작하기
Amazon Machine Image(AMI) 선택
선택하는 AMI에 따라 새 EC2 인스턴스에 설치되는 기본 소프트웨어가 결정.
보통 많이 Amazon Linux 2 AMI 나 Ubuntu Server 22.04 LTS 선택
인스턴스 유형 선택
각 사용 사례에 맞게 최적화된 다양한 인스턴스 유형을 결정.
인스턴스 유형은 CPU, 메모리, 스토리지 및 네트워킹 용량의 다양한 조합으로 구성되며, 애플리케이션에 따라 적합한 리소스 조합을 선택할 수 있는 유연성을 제공한다. 각 인스턴스 유형은 하나 이상의 인스턴스 크기를 포함하고 있으므로 목표로 하는 워크로드 요구 사항까지 리소스를 확장할 수 있다.
Key pair 설정
키 페어를 사용하여 인스턴스에 안전하게 연결하도록 한다. 해당 인스턴스에 접근할려면 key가 반드시 필요하니 잃어버리지 않도록한다.
- RSA : 기존의 AWS 키.
- ED25519 : SSH 인증에 일반적으로 사용하는 타원 곡선 기반 퍼블릭 키 시스템 Windows 인스턴스, EC2 인스턴스 Connect 또는 EC2 직렬 콘솔에서 지원되지 않는다.
네트워크 보안그룹추가
보안그룹은 인스턴스에 대한 트래픽을 제어하는 방화벽 규칙 세트이다. 특정 트래픽을 인스턴스에 도달하도록 허용할 규칙을 추가할수 있다.
- SSH는 인스턴스를 시작한 후 인스턴스에 연결하고 바로 앞에 있는 컴퓨터를 사용하는 것처럼 인스턴스를 사용할 수 있습니다.
- HTTP/HTTPS 는 웹서버 설정을 통해서 인터넷 트래픽을 인트선트세 도달하도록 허용고자 무제한 엑세스를 허용하는 규칙을 적용
스토리지 추가
인스턴스에 사용하는 스토리지 디바이스를 설정할수 있다. 프리 티어 사용 가능 고객은 기본은 8GIB 최대 30GIBDML EBS 범용(SSD) 또는 마그네틱 스토리지를 사용할 수 있다.
인스턴스 세부 정보 구성
기타 인스턴스 설정에 필요한 세부적인 내용을 설정할 수 있다. 하지만 프리티어이고 개발용 서버를 원하기에 따로 설정하지 않는다.
인스턴스가 정상적으로 생성이 되면 Instance state가 Running이 되고 아래와 같은 내용으로 구성 된다.
AWS EC2 인스턴스 접속하기
AWS EC2화면 상단에 Connet 버튼을 누르면 인스턴스 연결에 대한 가이드가 있다.
ssh 접속을 하기 위해서는 22번 포트가 개방되어야한다.
SSH 클라이언트(⭐추천⭐)
1. SSH 클라이언트를 엽니다.
2. 프라이빗 키 파일을 찾습니다. 이 인스턴스를 시작하는 데 사용되는 키는 petclub.pem입니다.
3. 필요한 경우 아래 명령을 실행하여 키를 공개적으로 볼 수 없도록 합니다.
chmod 400 petclub.pem # 키를 공개적으로 볼 수 없게 함.
4. 퍼블릭 DNS을(를) 사용하여 인스턴스에 연결:
ssh -i "{key명}" ubuntu@{퍼블릭 DNS}
Amazon EC2 인스턴스 연결
Amazon EC2 인스턴스 연결은 SSH(Secure Shell)를 사용하여 인스턴스에 연결하는 간단하고 안전한 방법을 제공한다.
Session Manger
Session Manager는 대화형 원클릭 브라우저 기반 셸 또는 AWS CLI를 통해 Amazon EC2 인스턴스, 온프레
미스 인스턴스 및 VM(가상 머신)을 관리할 수 있는 완전관리형 AWS Systems Manager 기능입니다.
EC2 직렬 콘솔
AWS EC2에 Python Flask 서버 셋팅
Ubuntu 22.04 LTS에 서버 셋팅
Python 설치
$ sudo apt update && sudo apt upgrade
#python 버전체크
$ python --version
Python을 실행시키려고 하면 가끔 /usr/bin/python 없이 /usr/bin/python3만 존재하는 경우가 있다.
이럴 경우 update-alternatives를 이용하여 해결할 수 있다.
$ sudo update-alternatives --install /usr/bin/python python $(readlink -f $(which python3)) 3
pip 설치
$ sudo apt install python3-pip
$ pip --version
AWS에 project 업로드하기
프로젝트 업로드하기위해서 업로드한 프로젝트 폴더를 생성해준다.
$ mkdir sparta # sparta 프로젝트 폴더 생성
[가장 많이 쓰는 몇 가지 리눅스 명령어]
ls: 내 위치의 모든 파일을 보여준다.
pwd: 내 위치(폴더의 경로)를 알려준다.
mkdir: 내 위치 아래에 폴더를 하나 만든다.
cd [갈 곳]: 나를 [갈 곳] 폴더로 이동시킨다.
cd .. : 나를 상위 폴더로 이동시킨다.
cp -r [복사할 것] [붙여넣기 할 것]: 복사 붙여넣기
rm -rf [지울 것]: 지우기
sudo [실행 할 명령어]: 명령어를 관리자 권한으로 실행한다.
sudo su: 관리가 권한으로 들어간다. (나올때는 exit으로 나옴)
PyCharm에서 AWS 서버와 연결한다.
Root path에 아까 만든 디렉토리(/home/ubuntu/sparta)를 입력해준다. 이때 /home/ubuntu/는 ubuntu 환경의 기본 경로라고 보면 된다.
우리가 만든 프로젝트를 ven 폴더를 제외하고 Remote Host를 통해서 프로젝트를 업로드해준다.
ven는 python 가상환경폴더인데 서버에는 이미 python 환경이 셋팅 되어 있으므로 필요없다.
터미널에서 확인해보면 잘 업로드가 완료된것을 확인 할 수 있다.
프로젝트 패키지 설치
프로젝트를 실행하기 전에 우리는 단순 python 프로젝트가 아니기대문에 프로젝트에 필요한 패키지를 설치해야한다.
서버에 Flask 설치
pip install flask
서버에 다른 패키지 설치 - pymongo, dnspython
pip install pymongo dnspython
프로젝트 실행하기
python app.py
5000번 포트 연결
프로젝트는 정상적으로 실행했지만 EC2에서 할당한 ip주소 혹은 ip주소:5000으로 접속하면 프로젝트로 연결되지 않는다.
Flask에서 지정한 것처럼 5000번 포트로 접속해야하는데 이것도 접속이 안될것이다. 왜냐면 우리는 AWS 서버가 5000번 포트로 접속이 가능하게 설정하지 않았기 때문이다.
5000포트에 접속이 가능하게 할려면 AWS EC2의 보안그룹 셋팅을 변경해야한다.
AWS EC2 > Network & Security > Security Groups 에서 내 인스턴스에 할당된 보안 그룹을 선택한다.
내가 설정한 인바운드 규칙들을 확인할 수 있는데 지금은 SSH 22포트, HTTP 80포트, HTTPS 443포트 세개만 설정되어 있는 것을 볼수 있다. 우리는 5000번 포트를 추가하기 위해서 Edit Inbound rules를 클릭한다.
5000포트를 할당해주고 어디서나 접근 간능하겠금 Anywhere-IPv4를 선택해준다.
그리고 ip주소:5000 로 접속해보면 정상적으로 프로젝트가 로딩되는 것을 확인할 수 있다!
포트 없이 접속하기
Flask를 통해서 5000포트에서 프로젝트가가 실행하고 있다. 그래서 매번 :5000 이라고 뒤에 붙여줘야 정상적으로 접속할 수 있다.
하지만 웹서비스에서는 HTTP로 요청이 되는데 요청에서는 80포트가 기본이라서 굳이 :80붙이지 않아도 자동으로 연결이 된다.
이렇게 5000포트번호를 입력하지 않아도 자동으로 접속되기 위해서 포트포워딩(port forwarding)을 사용하여 80포트로 오는 요청을 5000포트로 전달하는 작업을 해줘야한다.
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000
SSH 접속이 끊겨도 계속 서버 실행하게 하기
현재는 AWS SSH 접속이 끊겨지면 프로세스가 종료되면서, 서버가 돌아가지 않는다. 그러나 실제 웹서비스에서는 원격접속을 끊어도, 서버는 게속 동작을 해야한다.
이때, nohup을 이용해서 명령어를 실행한 후, 해당 터미널을 종료해도 계속 명령어가 실행되도록 유지할 수 있다.
실행하려는 명령어 앞에 "nohup"를 입력해주면 된다.
nohup python app.py & # &를 붙이면 백그라운드로 실행.
nohup으로 실행할 경우, 실행으로인한 로그들이 nohup.out 파일로 리다이렉트 된다.
다음 명령어를 통해서 쉘 프로그래밍이 제대로 진행되었는지 결과를 확인 할수 있다.
cat nohup.out
종종 nohup을 걸어둔 작업ㅇ르 멈춰야 할 때가 있다. 그럴때는 아래명령어를 통해서 강제종료를 해줘야한다.
ps -ef | grep 'python app.py' | awk '{print $2}' | xargs kill
- ps -ef | grep [regex] : 실행 중인 모든 프로세스 중 regex 가 포함된 프로세스
- grep -v grep : grep 문자열이 들어간 프로세스 제외
- awk '{print $2}' : 파이프를 통해 앞 과정에서 받아온 텍스트 중 2번째(PID)만 출력
- kill -9 : 파이프를 통해 추출된 pid 들을 프로세스 강제 종료. (default: 15, 정상종료)
Open Graph 소셜검색엔진최적화
페이스북에서 어떤 HTML 문서의 메타정보를 쉽게 표시하기 위해서 메타정보에 해당하는 제목, 설명, 문서의 타입, 대표 URL 등 다양한 요소들에 대해서 사람들이 통일해서 쓸 수 있도록 정의해놓은 프로토콜로 URL 링크를 공유할 때, 콘텐츠의 요약내용이 최적화된 데이터를 가지고 갈 수 있도록 설정하는 것이다.
Open Graph 기본 태그
- og:site_name : 해당 URL 공유 시, 나타낼 사이트 이름
- og:title : 해당 URL 공유 시, 나타낼 메인 콘텐츠 타이틀
- (지정되어 있는 <title>태그의 내용보다 우선적으로 표시하게 됩니다.)
- og:description : 해당 URL 공유시, 나타낼 설명.
- (지정되어 있는 <description>태그의 내용보다 우선적으로 표시하게 됩니다.)
- og:type : 해당 URL 공유 시, 지정할 유형(website, blog, video.movie 등). 유형에 따라 다른 속성이 필요할 수 있음.
- og:url : 해당 URL 공유 시, 표준으로 사용할 URL
- og:image : 해당 URL 공유 시, 나타낼 메인 이미지
- og:image:width , og:image:height : 이미지의 너비,높이 픽셀수로 지정
<html prefix="og: https://ogp.me/ns#">
<head>
<title>The Rock (1996)</title>
<meta property="og:site_name" content="The Rock" />
<meta property="og:title" content="The Rock Content" />
<meta property="og:description"
content="Sean Connery found fame and fortune as the
suave, sophisticated British agent, James Bond." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.imdb.com/title/tt0117500/" />
<meta property="og:image" content="https://ia.media-imdb.com/images/rock.jpg" />
<!-- 다음의 태그는 필수는 아니지만, 포함하는 것을 추천함 -->
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
...
</head>
...
</html>
Open Graph 모바일앱 미리보기
: 모바일 앱이 존재하는 경우 앱으로 연결 시 노출
<!-- iOS -->
<meta property="al:ios:url" content=" ios 앱 URL" />
<meta property="al:ios:app_store_id" content="ios 앱스토어 ID" />
<meta property="al:ios:app_name" content="ios 앱 이름" />
<!-- Android -->
<meta property="al:android:url" content="안드로이드 앱 URL" />
<meta property="al:android:app_name" content="안드로이드 앱 이름" />
<meta property="al:android:package" content="안드로이드 패키지 이름" />
<meta property="al:web:url" content="안드로이드 앱 URL" />
Twitter card
: 트위터에서 특정 Web page Url을 공유할 때 어떤 형식으로 공유될지 규정
: Open Graph만 사용해도 트위터에서 오픈그래프를 참조하나 트위터 카드와는 다른 UI 제공
- twitter:card : 카드 종류로 앞에서 본대로 summary, photo, player의 값이다.
- twitter:url : 트위터 카드를 사용하는 URL이다.
- twitter:title : 카드에 나타날 제목
- twitter:description : 카드에 나타날 요약 설명
- twitter:image : 카드에 보여줄 이미지
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@nytimes">
<meta name="twitter:creator" content="@SarahMaslinNir">
<meta name="twitter:title" content="Parade of Fans for Houston’s Funeral">
<meta name="twitter:description" content="NEWARK - The guest list and parade of limousines with celebrities emerging from them seemed more suited to a red carpet event in Hollywood or New York than than a gritty stretch of Sussex Avenue near the former site of the James M. Baxter Terrace public housing project here.">
<meta name="twitter:image" content="http://graphics8.nytimes.com/images/2012/02/19/us/19whitney-span/19whitney-span-articleLarge.jpg">
'스파르타코딩클럽 > 웹개발' 카테고리의 다른 글
웹개발종합반 개발일지 | 5주차 - 13강 Open Graph (0) | 2022.09.01 |
---|---|
웹개발종합반 개발일지 | 5주차 - 10,11,12강 Ubuntu 22.04 LTS에 Python Flask 서버 셋팅 (0) | 2022.09.01 |
웹개발종합반 개발일지 | 5주차 - 9강 PyCharm으로 서버 연결 및 파일 올리기 (0) | 2022.09.01 |
웹개발종합반 개발일지 | 5주차 - 7,8강 AWS EC2 인스턴스 생성 (0) | 2022.09.01 |
웹개발종합반 개발일지 | 5주차 - 1,2,3,4,5,6강 (0) | 2022.08.29 |