[무료서버] CloudType 에 Dockerfile 로 FastAPI 구동

Seongkeun·2024년 4월 28일
1

Server

목록 보기
1/1
post-thumbnail

시작하기 전에..

우리는 돈도 없고 시간도 없고 서비스를 이용해 줄 유저도 없으니 cloudtype 을 사용할겁니다.

클라우드타입 플랫폼 : https://cloudtype.io/

고객지원 디스코드 : https://discord.com/invite/SKAaW5sSSP

클라우드타입 요금 정책

요금 정책은 다양하게 있지만 우리와 같이 체험형 방랑자들에게는 Hobby 만으로도 충분하다. 당연히 기본으로 Hobby 자동 세팅이니 염려하지 말고 그냥 다음단계로 넘어가보자.

체크사항

그대여 ..

  • github 계정은 있는가?
  • cloudtype 계정은 있는가?
  • Dockerfile 에 대한 기초적인 지식은 있는가?
  • 서버에 대한 지식은 갖고있는가?

github와 cloudtype 계정은 있어야 하지만 나머지는 몰라도 따라는 하실 수 있을 거에요( 아마도..? )

그런데 다 없다면...?

장난이고 github 아이디는 하나 만들고 오십셔. 하지만 방금 만들었다면 따라하기 조금 힘드실 수도 있을 것 같습니다 ( github 관련 내용은 따로 언급 안 해요 ) 또 cloudtype 계정은 github 계정과 연동시켜놓으십셔

이제 우리는 서버리스를 체험하러 떠나볼 겁니다

필수 파일 구성

  • Dockerfile
  • requirements.txt
  • main.py

순서

필수구성요소만 해도 API 서버는 만들 수 있지만, 사이트를 조금 더 직관적으로 보기 위해서, 간단한 html 마크업도 작성할게요. 순서는 아래와 같이 구성할 겁니다.

Dockerfile, requirements.txt, main.py, movies.html 작성 >
github repository 생성 > 
git push > 
cloudtype.io 프로젝트 생성 > 
빌드

클라우드 타입에서는 템플릿을 제공해서 바로 사용할 수도 있지만, 그래도 어느정도는 내가 커스터마이징해야 멋있지 않겠습니까?

Directory

.
├── Dockerfile
├── main.py
├── requirements.txt
└── templates
    └── movies.html

이제부터 따라할 거면 그냥 복붙하기를 적극 권장합니다.

뭐..? 숙지를 위해 따라서 칠거라고요..?

Dockerfile

FROM python:3.11-slim-buster

ARG UID=1000
ARG GID=1000

RUN groupadd -g "${GID}" appgroup && \
    useradd --create-home --no-log-init -u "${UID}" -g "${GID}" appuser

WORKDIR /app

RUN apt-get update && \
    pip install --upgrade pip

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

USER appuser:appgroup
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt

fastapi==0.110.2
uvicorn[standard]==0.29.0
jinja2==3.1.2
pydantic==2.7.1
starlette==0.37.2
requests==2.31.0

main.py

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from typing import List

class Movie(BaseModel):
    id: int
    title: str
    genre: str
    year: int

movies = [
    Movie(id=1, title="Inception", genre="Sci-Fi", year=2010),
    Movie(id=2, title="The Dark Knight", genre="Action", year=2008),
    Movie(id=3, title="Interstellar", genre="Sci-Fi", year=2014),
]

app = FastAPI()

templates = Jinja2Templates(directory="templates")

@app.get("/", response_class=HTMLResponse)
async def read_movies(request: Request):
    return templates.TemplateResponse("movies.html", {"request": request, "movies": movies})

@app.get("/api/movies", response_model=List[Movie])
async def get_movies():
    return movies

movies.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Movie List</title>
    <style>
        body {
            font-family: 'Helvetica Neue', Arial, sans-serif;
            background-color: #f0f2f5;
            margin: 0;
            padding: 0;
        }

        header {
            background-color: #2c3e50;
            color: white;
            padding: 20px;
            text-align: center;
        }

        h1 {
            margin: 0;
            font-size: 2em;
        }

        .container {
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            padding: 20px;
        }

        .movie-card {
            background-color: #ffffff;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            padding: 20px;
            margin: 15px 0;
            width: 300px;
            transition: transform 0.3s, box-shadow 0.3s;
        }

        .movie-card:hover {
            transform: translateY(-10px);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
        }

        .movie-title {
            font-size: 1.5em;
            color: #333333;
            margin: 0;
        }

        .movie-details {
            font-size: 1.1em;
            color: #666666;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <header>
        <h1>Movie List</h1>
    </header>
    <div class="container">
        {% for movie in movies %}
        <div class="movie-card">
            <div class="movie-title">{{ movie.title }}</div>
            <div class="movie-details">Genre: {{ movie.genre }}</div>
            <div class="movie-details">Year: {{ movie.year }}</div>
        </div>
        {% endfor %}
    </div>
</body>
</html>

github 저장소 생성

우린 서버리스 환경 체험하러 온 것이니, license고 뭐고 다 필요없고 그냥 repository name 만 후딱 쓰고 바로 create repository 눌러버립시다.

작성해 놓은 코드 push

repository 에 code push 는 알아서 했다고 믿어 의심치 않습니다...
그 것이 내가 앞서 말한..약속이니까..

드디어 대망의 cloudtype ... !

클라우드 타입에 회원가입하고 로그인까지 완료 되었다면 화면 중앙에 저 크고 우람한 + 버튼이 보일 것이다. 그 것이 잘 안보인다면 우측 상단의 작고 아름다운 + 버튼을 눌러도 좋다. 그러면 아래와 같은 화면이 나온다.

검색창에 Docker 라고 검색하면 아래와 같이 나오는데, Dockerfile 을 클릭해주자.

그럼 아래 화면에서 아까 github 에 repository 를 선택하면 된다.

다음 화면으로 넘어가 지는데, 포트번호만 Dockerfile 에서 미리 지정한 8000 포트로 맞춰주고 배포하기를 누르면 되겠다. 이제 끝났다.

위와 같이 빌드 중인 로그화면이 나오는데 서비스로 이동 한 후 대기하면 곧 빌드가 완료되고 아래 이미지의 빨간 박스와 같이 [시작 중] 이라고 나온다.

UI 설명

빨간색 칸의 재생버튼과 정지버튼은 누가봐도 서버에 대해 정지 및 실행으로 보인다. 그럼 정지버튼 우측의 아이콘은 터미널 아이콘 처럼 보이는데 들어가보자.

첫 화면은 빌드로그 혹은 실행로그로 나올 것이다. 변경은 우측 상단을 보면 빌드로그, 실행로그, 터미널이 있다. 클릭해서 변경가능하다. 빌드 중 에러가 났다면 빌드로그, 실행 중 에러가 났다면 실행 로그를 보면 된다. 기타 터미널 작업이 필요하다면 터미널 들어가서 작업 ! esc 버튼으로 빠져나올 수 있다

서버 url 접속

★☆쨔쟌★☆ 위의 파란 칸 접속하기를 누르면 아래와 같이 내가 코드 짜놓은대로 나올 것이다.

https://port-0-docker-fastapi-1pgyr2mlvja6lbt.sel5.cloudtype.app/
참고로 무료버전은 매일 새벽 3~5시 사이 자동으로 서버가 다운된다...
누군가 위 서버를 들어갔지만 페이지를 못 찾는다고 나오면 필자가 서버 재시작을 하지 않은 것이니 참고바란다...( 매일 다운되서 다시 켜는거 귀찮.. )
( 다른 API서버 테스트하기 위해서 위 서버는 삭제했어요 )

아차..도메인 네임은 클라우드타입에서 제공해준다. 멋진 도메인 네임이 필요하다면 알아서 DNS 제공해주는 업체에 사서 클라우드타입 DNS 설정에서 변경하면 되겠다. 그리고 빌드나 실행중 에러가 떻다면, 클라우드타입에서 무료로 고객지원을 해주는데, 디스코드 클라우드타입 서버에 들어가서 문제해결 help 에서 질문하면 되겠다.

고객지원 디스코드 : https://discord.com/invite/SKAaW5sSSP

profile
지혜는 지식에서 비롯된다

0개의 댓글