Web

[WEB] Flask 실행하기 (AWS 서버 이용)

Eunice99 2022. 3. 11. 20:38

스파르타 코딩클럽 웹개발종합반 5주차

 

대망의 마지막 주차!! 열심히 달려왔다,,,

5주차는 버킷리스트 프로젝트를 만들면서 복습을 한번더하고 팬명록을 클라우드 환경에 배포하기까지 했다.

 

- 수업준비전 설치한것들

1) 파일질라

https://filezilla-project.org/download.php

 

Download FileZilla Client for Windows (64bit x86)

Download FileZilla Client for Windows (64bit x86) The latest stable version of FileZilla Client is 3.58.0 Please select the file appropriate for your platform below. Please select your edition of FileZilla Client FileZilla FileZilla with manual FileZilla P

filezilla-project.org

보안때문에 다운이안받아져서 FAQ를 이용해 해당 파일을 얻었다! 

FileZilla_3.57.0_win64_sponsored2-setup.exe.zip
11.62MB

2) 가비아 가입 & 도메인 구입

https://www.gabia.com

 

웹을 넘어 클라우드로. 가비아

그룹웨어부터 멀티클라우드까지 하나의 클라우드 허브

www.gabia.com

 

버킷리스트
  • 뼈대 준비

- 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: {sameple_give: '데이터전송'},
                success: function (response) {
                    alert(response["msg"])
                }
            });
        }

        function done_bucket(num) {
            $.ajax({
                type: "POST",
                url: "/bucket/done",
                data: {sameple_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>
POST 연습 (기록하기)

1. 요청 정보 : URL= /bucket, 요청 방식 = POST

2. 클라(ajax) → 서버(flask) : bucket

3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (기록 완료!)

서버에서 한가지 더 추가적으로 번호를 만들어주어야 업데이트가 가능해서 번호까지 만들어주었다!
  • 서버 만들기
@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 # 리스트에 저장된 항목이 전부 몇개인지 확인하는 len() 함수

    doc = {
        'num': count,
        'bucket': bucket_receive,
        'done': 0
    }

    db.bucket.insert_one(doc)

    return jsonify({'msg': '등록 완료!'})

파이썬 리스트 개수 세기 (아래 티스토리 이용)

https://vision-ai.tistory.com/entry/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A6%AC%EC%8A%A4%ED%8A%B8-count-%EC%99%80-len

 

파이썬 리스트(Python List) count() 와 len()

1. 찾고자 하는 항목이, 파이썬의 리스트에 몇개나 들어있는지 확인하는 count 함수 아래 예에서, fruits 리스트에 Mango 는 2개, Banana 는 1개가 들어있고, Guava 는 들어있지 않다. 따라서 내가 찾고자

vision-ai.tistory.com

  • 클라이언트 만들기
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() //새로고침
        }
    });
}

GET연습 (보여주기)

저장된 데이터를 그대로 가져와서 보여주기

1. 요청 정보 : URL= /bucket, 요청 방식 = GET

2. 클라(ajax) → 서버(flask) : (없음) -데이터를 다 가져와야 하므로

3. 서버(flask) → 클라(ajax) : 전체 버킷리스트를 보여주기

 

  • 서버 만들기
@app.route("/bucket", methods=["GET"])
def bucket_get():
    bucket_list = list(db.bucket.find({}, {'_id': False}))

    return jsonify({'buckets': bucket_list})
  • 클라이언트 만들기
$(document).ready(function () {
    show_bucket();
});

function show_bucket() {
    $.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 = ``

                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)
            }
        }
    });
}
POST연습 (완료하기)

완료버튼을 누르면 업데이트 되는것, done이 0이었다가 1로바뀜

1. 요청 정보 : URL= /bucket/done, 요청 방식 = POST

2. 클라(ajax) → 서버(flask) : num (버킷 넘버) -어떤 버킷의 done값을 0에서 1로바꿔달라고 하는지 알수있게 하기 위해

3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (버킷 완료!) 

 

  • 서버 만들기
@app.route("/bucket/done", methods=["POST"])
def bucket_done():
    num_receive = request.form["num_give"] #num_receive가 문자로 받아버리기 때문에
    db.bucket.update_one({'num': int(num_receive)}, {'$set': {'done': 1}}) #int 이용해서 숫자로 바꿔줘야함 / done 값을 0이었다가 1로 바꿔줌
    return jsonify({'msg': '버킷 완료!'})
  • 클라이언트 만들기
//<button onclick="done_bucket(${num})" type="button" class="btn btn-outline-primary">완료!</button> 버킷을 만들때 버튼에 이미 번호를 지정해줌

function done_bucket(num) {
    $.ajax({
        type: "POST",
        url: "/bucket/done",
        data: {'num_give': num},
        success: function (response) { //num를 받아와서 data로 num_give를 줌
            alert(response["msg"])
            window.location.reload()
        }
    });
}

마지막으로 내가 만든 팬명록을 서버에 올리는 작업!

 

언제나 서버요청에 응답하려면,

1) 컴퓨터가 항상 켜져있고 프로그램이 실행되어 있어야하고,

2) 모두가 접근할 수 있는 공개주소인 IP주소로 나의 웹서비스에 접근할수있도록 해야한다!

서버는 그냥 컴퓨터이므로 외부 접속이 가능하게 설정한 다음에 내 컴퓨터를 서버로 사용할 수도 있다.

그래서 AWS라는 클라우드 서비스에서 편하게 서버를 관리하기 위해서 항상 켜놓을수있는 컴퓨터인 EC2 사용권을

구입해 서버로 사용하였다!

정리하자면, 내컴퓨터를 계속 켜둘수없기 때문에 인터넷 세상에 있는 남의 컴퓨터를 사서 즉, 빌려서, 그거를 계속 돌려준다고 생각하면됨.
  • AWS 서버 구매하기 (컴퓨터 구매)

리눅스가 깔린 컴퓨터를 빌려씀.

https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2 

 

https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2

 

ap-northeast-2.console.aws.amazon.com

1년동안 한대에 서비스에 대해서 무료인 아래 서버를 다운로드하였다.

EC2에 접속을 하기 위해서는

미리 다운로드 받았던 Git bash를 키고 

ssh -i 내키페어 ubuntu@퍼블릭 IPv4 주소 

yes

해주면 서버를 이용할수있다.

(MAC은 ssh가 있어서 명령어로 바로 접근이 가능하다!)

 

cf) SSH(Secure Shell Protocol)이란?

다른 컴퓨터에 접속할때 쓰는 프로그램으로, 다른것들보다 상대적으로 보안이 뛰어나다.

접속할 컴퓨터가 22번 포트가 열려있어야 접속가능하고, AWS의 경우 이미 22번 포트가 열려있으므로 접속가능함.

 

간단한 리눅스 명령어 연습하기

ls: 내 위치의 모든 파일을 보여준다.

pwd: 내 위치(폴더의 경로)를 알려준다.

mkdir: 내 위치 아래에 폴더를 하나 만든다.

cd [갈 곳]: 나를 [갈 곳] 폴더로 이동시킨다.

cd .. : 나를 상위 폴더로 이동시킨다.

cp -r [복사할 것] [붙여넣기 할 것]: 복사 붙여넣기

rm -rf [지울 것]: 지우기

sudo [실행 할 명령어]: 명령어를 관리자 권한으로 실행한다.

sudo su: 관리가 권한으로 들어간다. (나올때는 exit으로 나옴)

 

  • 서버 세팅하기

지금 막 컴퓨터를 구매한 상태라고 보면됨!, 여기에 이런저런 세팅들 (업그레이드, DB설치, 명령어 통일 등)을 해줘야 본격적으로 이용할 때 편리하다!

(리눅스라는 OS는 마우스가 없으므로 모든것을 명령어로 써야함!)

 

# python3 -> python  (파이썬3하고 파이썬 명령어를 쳐야하는데, 파이썬3을 파이썬이라고 치고 명령내릴게)
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10

# pip3 -> pip (플라스크같은 패키지를 까는것처럼 pymongo, dnspython처럼 그친구들 깔때 pip라는 프로그램이 필요한데, 그걸 설치한것-패키지 마법사라고 보면됨)
sudo apt-get update
sudo apt-get install -y python3-pip
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

# port forwarding (localhost:5000에서 5000을 떼는 명령어)
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

 

(굵은 글씨를 차례대로 적어주면 세팅완료)

 

  • FileZilla 이용하기

노란색 형광펜 표시를 누르고 아래와같이 설정을 바꿔준다 (키파일은 내키페어를 넣어주면 된다.)

테스트파일 올려보기 (테스트파일은 버킷폴더에 미리 만들어두었음)

파일이 잘 들어간것을 확인할수있다.

  • Flask 서버 실행해보기

본격 팬명록 업로드하기

잘 들어갔는지 확인하기

Flask가 없다고 뜨면 pip install flask 명령어를 입력해주면 된다.

 

다시한번 python app.py를 치면 pymongo가 필요하다고 뜨는데, 

pymongo와 dnspython도 함께 설치해주어야한다.

퍼플릭 IP주소:5000을 입력하더라도 사이트에 연결할수없다고 뜬다.

이유는 5000번으로 접속할수있는 구멍을 아직 안열어두었기때문! 이 구멍을 열어주어야한다!

 

규칙저장을 눌러주면!

내가만든 팬명록이 인터넷에 배포된것을 확인할수있다! (폰으로도 확인가능!)

cf) 5000을 떼도 똑같이 나온다! 

왜 그럴까?

 

ex) http://naver.com사이트도 사실 80이 숨겨져있는것이다. http요청에서는 80포트가 기본이기때문에, 굳이 :80을 붙이지 않아도 연결이 되는것이다! (http://naver.com:80이런식으로!)

5000은 또 불가능! 

그래서 80으로 받아서 5000인 우리서버로 받아오는것!

즉, 포트번호를 입력하지 않아도 자동으로 접속되기 위해, 80포트로 오는 요청을 5000포트로 전달하게 하는 리눅스에서는 기본으로 제공해주는 포스트워딩을 사용했다!

 

그게 바로 아까 Git bash에서 작성했던 아래와 같은 명령어이다!

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

 

  • nohup 설정하기

단, Git bash창을 끄게 되면(=즉 SSH 접속을 끊으면) 프로세스가 종료되면서, 서버가 돌아가지 않게된다. (=해당 사이트도 꺼지게 된다.) 그러므로 콘솔창을 끄더라도(=원격접속을 끊어도) 계속 사이트가 돌아가도록(=서버는 계속 동작하도록) 설정해주어야한다. 

# 아래의 명령어로 실행하면 된다
nohup python app.py &
서버 강제 종료하기
ps -ef | grep 'python app.py' | awk '{print $2}' | xargs kill

 

  • 도메인 연결하기

1) dns 설정 들어가기

2) 아래와 같이 설정하고 저장하기

  • og 태그

- 내 프로젝트를 카톡/페이스북/슬랙에 공유했을때 예쁘게 나오도록 꾸미기작업

(og:image, og:title, og:description)

static 폴더 아래에 이미지 파일을 넣고, 각자 프로젝트 HTML의 <head>~</head> 사이에 아래 내용을 작성하면 og 태그를 개인 프로젝트에 사용할 수 있다.
<meta property="og:title" content="이석훈 팬명록"/>
<meta property="og:description" content="응원 한마디 남기고 가세요!"/>
<meta property="og:image" content="https://cdn.gukjenews.com/news/photo/201809/987374_761474_3135.jpg"/>

내가 산 컴퓨터에 올리기

1) 잘 돌아가던 서버 종료하기

2) 파일 바꿔치기 (기존 파일 삭제후 다시 복사, 붙여넣기)

3) 서버 다시 키기

결과확인

5주동안 배웠던것 총정리!

1~2주차 : 웹서비스를 만든다고 하면 내눈에 보이는것 (html, css, javascript), 두번째 내눈에 보이는애를 건내줄애가 필요 (서버)
3주차: 서버를 만들수있는 파이썬, 데이터베이스 공부
4~5주차 : 서버 만들고 배포하기
5주간의 과정이 끝나고 3주간의 만들기 프로젝트 과정이 남았다.

아직 익숙하지 않은게 당연하고, 만들기 과정을 통해 익숙해졌으면 좋겠다는 생각을 했다.

3주동안 나만의 프로젝트를 만들면서 배웠던 내용을 내것으로 만들어보는 과정도 기록할예정이다!

 

결과물 첨부

http://eunice-mk.shop/

 

이석훈 팬명록

응원 한마디 남기고 가세요!

eunice-mk.shop