์ ์ ํ์ผ๋ง ์๋ ์ฌ์ดํธ๋ฅผ ์ด๋ป๊ฒ ๊ตฌ๋์ํฌ๊น?
์ ์ ํ์ผ๋ง ์๋ ์ฌ์ดํธ๋ฅผ ์ด๋ป๊ฒ ๊ตฌ๋์ํฌ๊น? ๊ด๋ จ
๊ฐ๋ฐ์ ํ๋ค ๋ณด๋ฉด ์ ์ (static)์ธ ํ์ผ๋ก๋ง ๊ตฌ์ฑ๋ ์น ์ฌ์ดํธ๋ฅผ ์๋น์คํด์ผ ํ ๋๊ฐ ์์ต๋๋ค. ์ ์ ์ธ ์น ์ฌ์ดํธ๋ฅผ ์์ฑํ๊ณ ์๋น์คํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฟ ์์ง๋ง, ์ ๋ ์ฃผ๋ก ํ์ด์ฌ์ ํ์ฉํฉ๋๋ค. ํ์ด์ฌ์๋ ์ ์ ์น ์ฌ์ดํธ๋ฅผ ์๋น์คํ๋ ๊ฐ๋จํ ๋ชจ๋์ด ์์ต๋๋ค. ๋ค์ ๋ช ๋ น์ ๋ด๋ฆด ์ ์์ต๋๋ค.
python -m http.server
์ด๋ฅผ ์ ธ์์ ์คํํ๋ฉด ๋ช ๋ น์ด ์คํ๋ ๋๋ ํฐ๋ฆฌ๋ฅผ Document Root๋ก ์ผ์ HTTP Server๊ฐ ์์๋ฉ๋๋ค. ์ด ์น ์๋ฒ๋ ๊ธฐ๋ณธ์ ์ผ๋ก 8000 ํฌํธ๋ก ๊ธฐ๋ํ๊ธฐ ๋๋ฌธ์ ๋ก์ปฌ ์ปดํจํฐ์์ ์ ์ ์น ์ฌ์ดํธ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ๋์์ ๋ฐ์ ์ ์์ต๋๋ค. ๋ฌผ๋ก ์น ์๋ฒ๊ฐ ์คํ๋๋ ํฌํธ์ Document Root๋ก ์ผ์ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ช ๋ น์ ์คํ ์ต์ ์ผ๋ก ๋ฐ๋ก ์ง์ ํ ์๋ ์์ต๋๋ค.
๊ทธ๋ผ ์ด๋ ๊ฒ ๋ง๋ค์ด์ง ์ ์ ์น ์ฌ์ดํธ๋ฅผ Servingํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ์์ฝ์ง๋ง ๊ฐ์ธ์ด๋ผ๋ฉด ์ ์ ์น ์ฌ์ดํธ๋ฅผ ์ธํฐ๋ท์ Servingํ๋ ์ผ์ ์๊ฐ๋ณด๋ค ์ด๋ ต์ต๋๋ค. ๊ทธ๋์ ์๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๊ฐํ๋ ค๊ณ ํฉ๋๋ค.
ํด๋ผ์ฐ๋ ํ๋ซํผ์ Object Storage ์ฌ์ฉํ๊ธฐ
ํด๋ผ์ฐ๋ ํ๋ซํผ์ด ์ ๊ณตํ๋ ์๋น์ค ์ค์ ํ์ผ์ ๋ณด๊ดํ๋ Object Storage์ธ GCP์ Cloud Storage, AWS์ S3, Azure์ Blob Storage ์๋น์ค๊ฐ ์์ต๋๋ค. ํด๋น ์๋น์ค๋ค์ ์ ์ฅ์ ์ฌ์ฉ๋์ ๋ฐ๋ผ ๋น์ฉ์ ๋ฐ์ต๋๋ค.
์ ์ฅ์๋ฅผ ์ด์ฉํด ์ฌ์ดํธ๋ฅผ Servingํ๋ ค๋ฉด ๋ฒํท์ ํ์ผ์ ์ฌ๋ ค๋๊ณ ์ด๋ฅผ ์ธํฐ๋ท์ ๊ณต๊ฐํ๊ฒ ๋ค๊ณ ์ค์ ํด์ผ ํฉ๋๋ค. ๋ค๋ง ์ค์ ์ด ๊ฐ๋จํ ๊ฒ์ ์๋๋๋ค. ๋ฌด์๋ณด๋ค Object Storage์ ๋ฒํท์ ์ธํฐ๋ท์ ๊ณต๊ฐํ๋ ค๊ณ ํ๋ฉด ์ด๋ฅผ โ๊ถ์ฅํ์ง ์๋๋คโ๋ผ๋ ๊ฒฝ๊ณ ๋ฉ์์ง๊ฐ ๋ฐ์ํฉ๋๋ค.
ํด๋ผ์ฐ๋ ํ๋ซํผ์ ๋์ ์น ์ฌ์ดํธ ์๋น์ค ์ฌ์ฉํ๊ธฐ
์ ์ ์น ์ฌ์ดํธ๋ฅผ Servingํ๊ธฐ ์ํ ๋ค๋ฅธ ์ ํ์ง๋ก ๋์ ์น ์ฌ์ดํธ๋ฅผ Servingํ๋ ํด๋ผ์ฐ๋ ์๋น์ค๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์ธํฐ๋ท์ ๊ฒ์ํด ๋ณด๋ฉด, ํ์ด์ฌ ๊ธฐ๋ฐ Flask ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด ์ ์ ํ์ผ๋ง ๊ตฌ์ฑํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณผ ์ ์์ต๋๋ค.
๊ทธ์ค Flask๋ฅผ ์ฌ์ฉํด ์น ์๋ฒ๋ฅผ ๋ง๋ค ๋๋ ์๋ ๋ช ๋ น์ ํ์ฉํฉ๋๋ค.
from flask import Flask, send_file, abort
app = Flask(__name__)
@app.route("/", defaults={"links": "index.html"})
@app.route("/<path:links>;")
def main(links):
if links.endswith("favicon.ico"):
return abort(404)
return send_file(</spanf'static/{links}')
์ด ์ฝ๋๋ static
๋๋ ํฐ๋ฆฌ์์ Servingํ๋ ค๋ ํด๋๊ฐ ์์ ๋, Flask ์๋ฒ๋ก ๋ค์ด์ค๋ ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ static
์๋์์ ์ฐพ์ ์ ์กํ๋ผ๋ ์๋ฏธ์
๋๋ค.
์ด๋ Google App Engine, AWS Beanstalk, Heroku ๋ฑ ์น์ฌ์ดํธ ๋ฐฐํฌ ๊ด๋ จ ์๋น์ค ๋ชจ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค๋ง ๊ฐ๋ณ ์๋น์ค์์ ์ฌ์ฉํ๋ ์ ์ฉ ๊ตฌ์ฑ ์ค์ ์ ๋ฐ๋ผ์ผ ํฉ๋๋ค.
Github, BitBucket์ Pages ๊ธฐ๋ฅ ์ฌ์ฉํ๊ธฐ
GitHub, BitBucket์ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ VCS ์์คํ ์ผ๋ก ๊ฐ๋ฐ์๋ค ์ฌ์ด์์๋ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค. ์ด๋ฌํ VCS ์์คํ ์๋ ์ ์ ์น ์ฌ์ดํธ๋ฅผ ์๋น์คํ๋ ๊ธฐ๋ฅ์ด ํฌํจ๋์ด ์์ต๋๋ค.
GitHub์ด ์ ๊ณตํ๋ GitHub Pages, BitBucket์ด ์ ๊ณตํ๋ BitBucket Pages ๊ธฐ๋ฅ์ด ๋ํ์ ์ ๋๋ค. ์ด๋ค์ด ์ ๊ณตํ๋ Pages ๊ธฐ๋ฅ์ ๋ฌด์์ผ๋ก ์ธ ์ ์์ผ๋ฉฐ ์ต๊ทผ ์ ์ ์น ์ฌ์ดํธ Serving์์ ์ฃผ๋ชฉ๋ฐ๊ณ ์๋ Jekyll ๋ฑ์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค๋ง GitHub์ ๊ฒฝ์ฐ, ์ ์ฅ์์ ๊ฐ์์ฑ์ด โ๊ณต๊ฐโ๋ก ๋์ด ์์ด์ผ๋ง Pages ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค๋ ๋จ์ ์ด ์์ต๋๋ค. ๋ค์ ๋งํด GitHub ์ ์ฅ์๊ฐ ์๋ฌด์๊ฒ๋ ์ด๋ ค ์์ด์ผ ํ๋ค๋ ๋ป์ ๋๋ค. ๊ฒ๋ค๊ฐ ์ด๋ฅผ ๋ค๋ฃจ๋ ค๋ฉด git ๋ช ๋ น์ด๋ฅผ ์ ์ฌ์ฉํ ์ค ์์์ผ ํฉ๋๋ค.
๊ทธ๋์, ์ด๋ค ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ์ข์๊น?
์์ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ ์๊ฐํ์ง๋ง, ์ ๋ ์ ์ ์น ์ฌ์ดํธ๋ฅผ Servingํ ๋ Google App Engine ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋์คํฌ ์ฉ๋ 1GB๋ฅผ ์ ๊ณตํ๊ณ ํธ๋ํฝ ๋ฑ ๋ถ๋ถ์์๋ ์ผ์ ์ฉ๋์ ๋งค์ผ ๋ฌด๋ฃ๋ก ์ธ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฌ๋ฌ๋ถ์ด App Engine์์ ๋ฒ์ด๋์ง ์์ ๊ฒ์ด๋ผ๋ฉด, ์ฐ์ ๋ค์๊ณผ ๊ฐ์ ๋๋ ํฐ๋ฆฌ ๊ตฌ์ฑ์ด ํ์ํฉ๋๋ค.
- .
static_root
- .
www
- .
app.yaml
- .
.app.yaml
์ App Engine์ด ์ฐธ์กฐํ๋ ํ์ผ์
๋๋ค. app.yaml
ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
runtime: python312
handlers:
- url: /
static_files: www/index.html
upload: www/index.html
- url: /(.*)
static_files: www/\1
upload: www/(.*)
.app.yaml
์๋ ๋ธ๋ผ์ฐ์ ๊ฐ ๊ฒฝ๋ก๋ฅผ ์์ฒญํ๋ฉด ์ด๋ป๊ฒ ๋์ํ ๊ฒ์ธ์ง ์ง์ ํ๋ handlers ์ค์ ์ด ํฌํจ๋์ด ์์ต๋๋ค. ์์ ์ฝ๋๋ /
URL์ ๋ํด์๋ www/
index.html
ํ์ผ์ ์๋นํ๊ณ , ๊ทธ ์ธ ๋ชจ๋ ์์ฒญ์ www
๋๋ ํฐ๋ฆฌ์์ ์ฐพ์ ๋ณด๋ด๋ผ๊ณ ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
.app.yaml
๊ตฌ์ฑ์ ๋ง์ณค์ผ๋ฉด static_root
๋๋ ํฐ๋ฆฌ์์ gcloud ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์ด๋ฅผ App Engine์ ์
๋ก๋ํ๋ฉด ๋ฉ๋๋ค.
gcloud app deploy
๋ง์ฝ ์ฌ๋ฌ๋ถ์ด GCP๋ฅผ ๊พธ์คํ ์ฌ์ฉํ๋ค๋ฉด, App Engine์์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ๋ง์ผ๋ก๋ ์ด๋ฅผ ์ ์ฉํ๊ฒ ์ธ ์ ์์ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ App Engine์ ๋ฒ์ด๋ AWS, Heroku๋ก ์ด๋ํ๊ฑฐ๋ gzip์ผ๋ก ์์ถ๋ ์ ์ ์ฝํ ์ธ ๊ฐ ์๋ค๋ฉด ์ด ๊ตฌ์ฑ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์๋น์ค ์ ๊ณต์๋ง๋ค ๊ตฌ์ฑ ํ์ผ์ ๋ฌ๋ฆฌํด์ผ ํ๋ ๋ฐ๋ค๊ฐ gzip ์์ถ์ ์๋น์คํ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
static3๊ณผ App Engine์ ํจ๊ป ์ฌ์ฉํ๊ธฐ
์ด๋ฐ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด static3๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค. static3์ ํ์ด์ฌ ์ฝ๋๋ก ์์ฑ๋ ์ ์ ์น ์ฝํ ์ธ ๋ฅผ ์ฝ๊ฒ ์๋น์คํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๊ธฐ์กด์๋ ํ์ด์ฌ 2๋ก ์์ฑ๋ static์ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์๋๋ฐ, ์ง๊ธ์ ์ ์ง๋ณด์๋์ง ์๊ณ ์์ต๋๋ค.
์ด๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋๋ ํฐ๋ฆฌ ๊ตฌ์ฑ์ด ํ์ํฉ๋๋ค.
- .
static_root
- .
app.yaml
- .
- .
requirements.txt
- .
main.py
- .
์ฐ๋ฆฌ๋ ์ฌ๊ธฐ์์ static3๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก requirements.txt
์ ๋ค์ ๋ด์ฉ์ ์
๋ ฅํฉ๋๋ค.
static3
๊ทธ๋ค์ app.yaml
์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
runtime: python312
๋ง์ง๋ง์ผ๋ก main.py
๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
from static import Cling
app = Cling("web")
์ ์ ์น ์ฌ์ดํธ๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ์ค๋น๊ฐ ์๋ฃ๋์์ต๋๋ค. ์ด์ App Engine์ ์ด๋ฅผ ์
๋ก๋ํฉ๋๋ค. static_root
์์ ๋ค์ ๋ช
๋ น์ ์
๋ ฅํ๋ฉด ๋ฉ๋๋ค.
gcloud app deploy
static3์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ๊ฐ /
๋ฅผ ์์ฒญํ๋ฉด web
๋๋ ํฐ๋ฆฌ์ index.html
์ ์๋น์คํฉ๋๋ค. ๊ทธ ์ธ ๋ชจ๋ ๊ฒฝ์ฐ์๋ web
๋๋ ํฐ๋ฆฌ์์ ๋ธ๋ผ์ฐ์ ๋ก๋ถํฐ ์์ฒญ๋ฐ์ ๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์๋น์คํฉ๋๋ค.
static3์ gzip ์์ถ๋ ํ์ผ๋ ์๋น์คํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์ฉ๋์ด ํฐ html ํ์ผ์ gzip์ผ๋ก ์์ถํด๋๋ฉด static3์ด ์์์ ๋ธ๋ผ์ฐ์ ์ ํด๋น ํ์ผ์ ์ฐพ์ ๋ณด๋ด ์ค๋๋ค. ์์ ์์๋๋ก๋ผ๋ฉด index.html.gz
์ ๊ฐ์ ํํ๊ฐ ๋ฉ๋๋ค.
๋ค๋ฅธ ํ๋ซํผ์์๋ static3๋ฅผ ์ฌ์ฉํ ์ ์์๊น?
static3๊ฐ ์ ๊ณตํ๋ cling์ ๊ธฐ๋ณธ์ ์ผ๋ก WSGI ํธํ Wrapper๋ก์ ๋์ํฉ๋๋ค. ๋ฐ๋ผ์ ๋์ ์น ์ฌ์ดํธ๋ฅผ ์๋น์คํ๋ ๋ค์ํ ํ๋ซํผ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ง์ฝ ์ฌ๋ฌ๋ถ์ด [AWS Beanstalk๋ Azure App Service][1]๋ฅผ ์ฌ์ฉํ๋ค๋ฉด main.py
์ด๋ฆ์ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๊พธ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
- AWS Beanstalk:
application.py
- Azure App Service:
app.py
๋ค๋ง app.yaml
๋ฑ ํ์ผ์ ํด๋ผ์ฐ๋ ์๋น์ค๋ง๋ค ์กด์ฌํ๋ ํ์ผ์ด ๋ค๋ฅผ ์ ์์ต๋๋ค.
๋ง์น๋ฉฐ
์ง๊ธ๊น์ง ์ ์ ์น ์ฌ์ดํธ๋ฅผ ์๋น์คํ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ์ดํด๋ดค์ต๋๋ค. ์ฌ๋ฌ๋ถ์ ์ ์ ์น ์ฌ์ดํธ๋ฅผ Servingํ๋ ๋ฐฉ๋ฒ์ด ์๊ฐ๋ณด๋ค ๋ค์ํ๋ค๋ ์ ์ ์๊ฒ ๋์์ ๊ฒ์ ๋๋ค.
๋ฌผ๋ก ์ด๋ค ๋ค์ํ ๋ฐฉ๋ฒ ๊ฐ์ด๋ฐ ์ด๋ค ๋ฐฉ๋ฒ์ด ๊ฐ์ฅ ํจ๊ณผ์ ์ผ์ง๋ ๋น์ฉ์ด๋ ๋ฐฐํฌ ํ๊ฒฝ ๋ฑ ์ ๋ฐ ์ฌ๊ฑด์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ์ด ๊ธ์ด ์ฌ๋ฌ๋ถ์ ์ ํ์ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
Azure์ ๊ฒฝ์ฐ, ์ ์ ์น ์ฌ์ดํธ ํธ์คํ ์ ์ํด Azure Static Web Apps๋ผ๋ ์๋น์ค๊ฐ ๋ฐ๋ก ์กด์ฌํฉ๋๋ค. โฉ๏ธ