본문 바로가기
IT/Web

[프론트엔드] 스파르타코딩클럽 웹개발 종합반 5주차 수강후기

by 퐁시냥 2021. 11. 20.

스파르타코딩클럽 웹개발 종합반 5주차 수강후기. 늦었지만 5주차까지 완료했다..

프론트엔드 웹개발 기초 수업이지만 환경세팅, 개발, 배포까지 전반적인 과정을 경험해볼 수 있어서 좋았다. 

특히 도메인 구매, AWS EC2 서버를 이용한 퍼블릭 서버 배포까지 해볼 수 있어서 재미있었다!

오늘 내일 열심히 과제해서 여기 올려봐야겠다 !

 

5주 코스 완주 샷!!!

 

[수업 목표]

  1. Flask 프레임워크를 활용해서 API를 만들 수 있다.
  2. '버킷리스트'를 완성한다.
  3. EC2에 내 프로젝트를 올리고, 자랑한다!

 

[5주차 웹서버 구조]

5주차 웹서버 구조

 

1. 사전세팅 

 

Download FileZilla Client for Windows (64bit x86)

Download FileZilla Client for Windows (64bit x86) The latest stable version of FileZilla Client is 3.56.2 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

 

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

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

www.gabia.com

도메인 구매하려면 많이 비쌀 줄 알았는데, 1년동안 해당 도메인을 쓰는데 단돈 550원 밖에 안된다! (도메인 구매는 본인 돈으로 해야함)

요로케 루트 도메인(com, shop, kr, net 등) 의 종류에 따라 도메인 가격도 다르다.  

나는 이 중에서 할인중이라서 가장 싼 .shop 을 선택해서 부가세 포함해서 550원에 구매했다! 사용 기간은 1년.

참고로 1000원 이하는 카드 결제가 안되어서 무통장 입금으로 진행했다.

도메인 생성되는데까지 시간이 좀 걸려서 미리 생성해두는게 좋음!

 

2. 소스 준비

이전에 만들어 놓은 버킷리스트 소스 준비

  • 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>

3. AWS 가입 및 서버 배포

AWS EC2 가입 후에 ubuntu 서버를 생성했다.

1년동안 무료이고 서버 1개까지는 무료임!!! (단, 1년 후에는 자동결제 된다고 함, 자동결제 전에 인스턴스 중지/종료 꼭하기!)

웹서비스가 실행되려면 아래 두가지를 충족해야하는데, 내 PC를 24시간 켜놓을 수 없으니 AWS에서 제공하는 클라우드 서버를 이용해서띄워 놓는 것. 

 

  • 컴퓨터가 항상 켜져있고 프로그램이 실행되어 있어야함
  • 모두가 접근할 수 있는 공개 주소인 공개 IP 주소(Public IP Address)로 나의 웹 서비스에 접근할 수 있도록 해야함

1) EC2 서버 구매하기

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

 

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

 

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

  • Ubuntu Server 18.04 또는 20.04 버전을 구매합니다. (잘못해서 Amazon Linux 서버사서 다시 생성했다^^)
  • 생성할 때 키 페어 다운로드 (ssh로 접속할 때 해당 키를 이용해 로그인 해야하므로) 

2) EC2 접속하기 

  • 내가 만든 ubuntu 서버 인스턴스에 접속하려면 SSH 프로토콜을 이용해야한다. 
    • SSH(Secure Shell Protocol)
      • 다른 컴퓨터에 접속할 때 쓰는 프로그램. 다른 것들 보다 보안이 상대적으로 뛰어남
      • 접속할 컴퓨터가 22번 포트가 열려있어야 접속 가능. AWS EC2의 경우, 이미 22번 포트가 열려있음
      •  
        SSH 22번 포트 허용되어 있는 모습
    • MAC OS 에서 EC2 접속하기
      • 터미널을 열기 (spotlight에 terminal 입력)
      • 방금 받은 내 Keypair의 접근 권한을 바꿔주기
        sudo chmod 400 받은키페어를끌어다놓기​
      • SSH로 접속하기(ssh -i 받은키페어를끌어다놓기 ubuntu@AWS에적힌내아이피)
      • 예) ubuntu@자신의 인스턴스의 Public IP 
        ssh -i /path/my-key-pair.pem ubuntu@AWS에적힌내아이피
        
        예시) 
        ssh -i /path/my-key-pair.pem ubuntu@13.125.250.20

4. 서버 세팅하기

1) FileZila 를 이용해서 기존 소스 AWS 서버로 업로드 

  • 접속할 사이트 설정
  • 좌측 상단 Site Manager 클릭 후 AWS Server IP와 아까 발급받은 Key Pair 를 Key File에 넣기
    • 정보들을 입력하고, ok 누르면 서버의 파일들을 볼 수 있음 (Host: 내 EC2서버의 ip // User: ubuntu 로 입력)

2) ssh로 서버 접속 후 사전 환경 세팅

아래 명령어 한줄 씩 입력하기

  • python / pip 설치 / 리디렉션 포트 80 -> 5000 추가
# python3 -> python (python3 라고 입력하고 실행해야하는데 python 만 입력해도 실행 되도록)
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10

# pip3 -> 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(80포트로 연결할 때 5000 으로 redirection 되게)
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000

3) 테스트 파이썬 파일 실행하기 

  • test.py 샘플 파일 생성(파이썬 파일은 샘플로 만들었음. )
# test.py

print('Hello World!')

 

  • FileZila 를 통한 test.py 파일 업로드 or 서버에서 직접 생성해도 됨
  • test.py 실행하기 -> Hello World! 가 터미널에 출력되면 된다.
  • python test.py

 

 

5. 소스코드 서버에 업로드

1) FileZila를 통한 소스파일 서버로 업로드 

  • templates, static, app.py 이렇게만 업로드하면된다. (venv 디렉토리는 로컬 가상환경에서 실행하기 위한 폴더이므로 업로드 하지않아도 된다.)

2) pip로 소스에 포함된 패키지 설치

pip install flask
pip install pymongo dnspython

3) Flask 서버 실행(app.py 실행)

python app.py

4) 브라우저에서 접속해보기 

http://[내 EC2 서버 IP]:5000

접속이 안될 것임. 왜냐면 AWS EC2에 5000 포트에 대한 인바운드 오픈이 안되어있기 때문임.

 

5) AWS에서 인바운드 보안설정 변경

  • EC2 서버(=가상의 내 컴퓨터)에서 포트를 따로 설정하는 것 외에도, AWS EC2에서도 자체적으로 포트를 열고/닫을 수 있게 관리를 하고 있습니다.
    • 그래서 AWS EC2 Security Group에서 인바운드 요청 포트를 열어줘야 합니다.
  • 일단, EC2 관리 콘솔로 들어갑니다. 그리고 보안그룹(영문: Security Group)을 눌러 들어갑니다. 여기선 launch-wizard-1 이라고 쓰여 있네요
  • 포트 2개 추가해주기(22 : ssh 포트는 기본적으로 열려있음) -> 설정 후 다시 접속하면 잘 접속될 것!!!! 
    • 80포트: HTTP 접속을 위한 기본포트
    • 5000포트: flask 기본포트
    •  
      • 지금은 5000포트에서 웹 서비스가 실행되고 있습니다. 그래서 매번 :5000 이라고 뒤에 붙여줘야 하죠. 뒤에 붙는 포트 번호를 없애려면 어떻게 해야할까요?
      • http 요청에서는 80포트가 기본이기 때문에, 굳이 :80을 붙이지 않아도 자동으로 연결이 됩니다.
      • 포트 번호를 입력하지 않아도 자동으로 접속되기 위해, 우리는 80포트로 오는 요청을 5000 포트로 전달하게 하는 포트포워딩(port forwarding) 을 사용
      • 리눅스에서 기본으로 제공해주는 포트포워딩을 사용

 

6. nohup 설정하기

1) SSH 연결 끊겨도 Flask 서버가 실행되도록 설정하기

# 아래의 명령어로 실행하면 된다
nohup python app.py &

Flask 서버 강제종료하려면? 아래 명령어 입력

ps -ef | grep 'python app.py' | awk '{print $2}' | xargs kill

2) SSH 종료 후에도 서버가 종료되지 않는지 확인

http://[내 EC2 서버 IP]:5000

7. 도메인 연결하기

1) 가비아 접속 후 DNS 설정 

https://dns.gabia.com/

 

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

 

dns.gabia.com

2) 등록한 도메인으로 사이트 접속 확인 (10분정도 걸릴 수 있음)

  • 네임서버에 내 도메인-IP가 매칭되는 시간이 필요

3) 도메인 이름으로 접속해보기 

http://[내도메인이름].shop

8. 소스에 og 태그 추가하기

  • og 태그를 추가하면 카카오톡이나 tistory 와 같은 사이트에서 자동으로 타이틀, 이미지, 설명이 보임
    • 메타태그 추가 후 카톡에서 확인&amp;amp;amp;nbsp;
  • 아래 메타 태그를 기존 html 파일에 추가하기
    • <meta property="og:title" content="내 사이트의 제목" />
      <meta property="og:description" content="보고 있는 페이지의 내용 요약" />
      <meta property="og:image" content="이미지URL" />
    • 참고 ) 메타태그 추가 후에도 이미지가 변경 전 이미지로 보이는 경우 초기화 방법

 

 

 

끝!!!!! 대충할랬는데 생각보다 엄청 열심히 해버렸다. 

이제 프로젝트 시작해야지. 결과물은 여기 올릴 예정 :) 

댓글