Python/Flask를 이용한 컨테이너 제작 프로젝트

김동주·2024년 1월 26일

🚩 프로젝트

Python/Flask를 이용해 간단한 게임을 컨테이너화 -> Docker 이미지 빌드 테스트

📁 깃허브 주소

https://github.com/dongjucloud/Python-Flask-to-Containerize

1. 프로젝트 구조

-> pycharm을 사용하여 제작하였다.

2. Dockerfile

-> 만든 컨테이너를 기동시키기 위한 파일

# Dockerfile
# 파이썬 빌드
FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder
# 작업 디렉토리 설정 
WORKDIR /app
# 현재 디렉토리 파일 /app 디렉토리로 복사
# txt파일 설치
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
# 포트설정 
EXPOSE 5000
# 환경변수
ENV NAME Game
# 기본 실행 명령어
CMD ["python3", "app.py"]

3. app.py

-> Flask를 사용하여 만든 숫자 맞추기 게임 Python 스크립트

# app.py
# 사용할 flask 객체 
from flask import Flask, render_template, request, redirect, url_for, session
# 숫자 맟추기 게임에 사용할 random 모듈 끌어오기
import random

app = Flask(__name__)
# session에 저장되어있는 것을 끌어오기 위한 키값 설정
app.config['SECRET_KEY'] = 'secretkey'

# main 홈페이지 
@app.route('/home')
def home():
	# username이 세션에 저장되어있으면 redirect(url_for()) 함수를 통해
 	play_game 페이지로 이동
 	# url_for = 라우트 이름을 url로 생성해주는 함수
    if 'username' in session:
        return redirect(url_for('play_game'))
    # 그렇지 않으면 html로 만든 페이지로 이동
	# render_tamplate = html을 렌더링하기 위한 함수
    else:
        return render_template('index.html', title='Let`s play flask-game', content='welcome!')
# 로그인 페이지 – POST 를 통해 입력 값을 받고 전달, GET을 통해 서버의 데이터를 가와줌
@app.route('/login', methods=['GET', 'POST'])
def login():
	# POST 요청을 받으면 username을 폼시키고 play_game url로 리턴
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('play_game'))
    # GET 요청일 경우   
    else:
        return render_template('login.html', title='Login')

@app.route('/logout')
# 로그아웃 페이지
def logout():
	# pop명령어로 session에서 username 제거후 None으로 반환
    session.pop('username', None)
    return redirect(url_for('home'))
# 게임 페이지 
@app.route('/play_game', methods=['GET', 'POST'])
def play_game():
	# session에 username이 저장되있지 않을 경우 로그인페이지로 다시이동
    if 'username' not in session:
        return redirect(url_for('login'))

    if request.method == 'POST':
    	# 사용자에게 숫자 추측값을 받음
        guess = int(request.form['guess'])
        # target_number이 설정되어있으면 가져오고 아니면 –1값으로 초기화한다.
        target_number = session.get('target_number', -1)
		# 처음 게임을 시작하면 target_number가 설정되어 있지 않으므로 –1로 초기화된 상태에서 시작
        if target_number == -1:
        	# random 모듈을 통한 숫자 설정 
            target_number = random.randint(1, 100)
            # 결정된 숫자를 target_number에 저장
            session['target_number'] = target_number
		# 추측값이 랜덤숫자와 맞을 경우
        if guess == target_number:
            result = 'Congratulations! You guessed the correct number.'
            # 정답을 맟췄으니 다시 시작하기 위해 target_number 세션값을 제거시켜
			준다.
            session.pop('target_number', None)
        # 추측값보다 랜덤숫자가 더 클 경우    
        elif guess < target_number:
            result = 'Try again! The number is higher.'
        # 추측값보다 랜덤숫자가 작을 경우(커피 머신과 비슷함)     
        else:
            result = 'Try again! The number is lower.'
		# 결과 값을 게임html에 전달
        return render_template('play_game.html', title='Play Game', result=result)
	# 다시 시작할 경우 결과값을 초기화 해서 전달
    else:
    return render_template('play_game.html', title='Play Game', result=None)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

4. templates/index.html

(jinja2 템플릿은 #으로 주석처리를 하지 않기 때문에 #을 제거하고 사용해야 한다.)

-> 메인페이지를 위한 html

<!-- templates/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">
    <title>{{ title }}</title>
</head>
<body>
    <div>
        <h1>{{ title }}</h1>
        <p>{{ content }}</p>
        # href로 링크걸어줌
        <p><a href="{{ url_for('login') }}">Login</a></p>
    </div>
</body>
</html>

5. templates/login html

-> 로그인페이지를 위한 html

<!-- templates/login.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">
    <title>{{ title }}</title>
</head>
<body>
    <div>
        <h1>{{ title }}</h1>
        # url_for로 입력받은 데이터를 서버로 전송
        <form method="post" action="{{ url_for('login') }}">
        	# 사용자명을 입력할 수 있는 텍스트 생성
            # required를 통해 사용자가 반드시 입력햐애만함
            <label for="username">Username:</label>
            <input type="text" name="username" required>
            # 폼 제출 버튼
            <input type="submit" value="Login">
        </form>
    </div>
</body>
</html>

6. templates/play_game.html

<!-- templates/play_game.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">
    <title>{{ title }}</title>
</head>
<body>
    <div>
        <h1>{{ title }}</h1>
        <p>Guess the number between 1 and 100:</p>
        <form method="post" action="{{ url_for('play_game') }}">
        	# 사용자가 숫자를 입력할수 있게 만듬 (반드시 입력해야만함)
            <input type="number" name="guess" required>
            # 숫자 제출 Submin Guess 버튼 
            <input type="submit" value="Submit Guess">
        </form>
        # result 값을 받아 출력
        <p>{{ result }}</p>
        # 홈페이지 이동 링크
        <p><a href="{{ url_for('home') }}">Home</a></p>
        # 로그아웃하는 링크
        <p><a href="{{ url_for('logout') }}">Logout</a></p>
    </div>
</body>
</html>

7. requirements.txt

Flask

8. 테스트

$ docker build –t flask-game . $ docker run –p 5000:5000 flask-game
$ firefox http://localhost:5000

  • 메인페이지 로그인페이지로 갈 수 있는 링크를 확인할 수 있다.
  • 로그인 페이지로 이동후 Username을 입력해서 게임을 시작한다.
  • 숫자가 더 낮을 경우(아래 홈페이지와 로그아웃 링크도 확인해볼 수 있다.)
  • 정답을 맟출 경우
profile
더욱 더 발전된 엔지니어가 되기 위한 개인 공부 블로그(DevOps/Cloud)

0개의 댓글