정적 파일 제공

애플리케이션은 동적 요청 처리 외에도 자바스크립트, 이미지, CSS와 같은 정적 파일을 종종 제공해야 합니다. 가변형 환경의 앱은 Cloud Storage와 같은 Google Cloud 옵션에서 정적 파일을 제공하거나 직접 제공하거나 서드 파티 콘텐츠 전송 네트워크(CDN)를 사용할 수 있습니다.

Cloud Storage에서 파일 제공

Cloud Storage는 동적 웹 앱의 정적 애셋을 호스팅할 수 있습니다. 앱에서 직접 제공하는 대신 Cloud Storage를 사용할 때의 이점은 다음과 같습니다.

  • Cloud Storage가 콘텐츠 전송 네트워크 역할을 하게 되는데, 그렇다고 특별한 구성이 필요한 것은 아닙니다. 공개적으로 읽을 수 있는 모든 객체가 글로벌 Cloud Storage 네트워크에 캐시되기 때문입니다.
  • 정적 애셋 제공에 따른 부하를 Cloud Storage로 분산함으로써 앱 부하를 줄일 수 있습니다. 포함된 정적 애셋 수 및 액세스 빈도에 따라 앱 실행 비용을 크게 줄일 수 있습니다.
  • Cloud Storage를 사용하면 콘텐츠 액세스를 위한 대역폭 비용을 낮출 수 있습니다.

Google Cloud CLI 또는 Cloud Storage API를 사용하여 Cloud Storage에 애셋을 업로드할 수 있습니다.

Google Cloud 클라이언트 라이브러리는 App Engine 앱에서 Cloud Storage로 데이터를 저장하고 검색하기 위한 Cloud Storage에 관용적 클라이언트를 제공합니다.

Cloud Storage 버킷을 사용한 파일 제공의 예시

이 예에서는 Cloud Storage 버킷을 만들고 gcloud CLI를 사용하여 정적 애셋을 업로드합니다.

  1. 버킷을 만듭니다. 버킷 이름을 프로젝트 ID와 동일하게 지정하는 것이 일반적이지만 필수는 아닙니다. 버킷 이름은 전역적으로 고유해야 합니다.

    gcloud storage buckets create gs://<var>your-bucket-name</var>
    
  2. 버킷의 항목에 대한 공개 읽기 액세스 권한을 부여하도록 IAM 정책을 설정합니다.

    gcloud storage buckets add-iam-policy-binding gs://<var>your-bucket-name</var> --member=allUsers --role=roles/storage.objectViewer
    
  3. 버킷에 항목을 업로드합니다. 애셋을 업로드하고 업데이트할 때는 일반적으로 rsync 명령어가 가장 빠르고 쉬운 방법입니다. cp를 사용해도 됩니다.

    gcloud storage rsync ./static gs://<var>your-bucket-name</var>/static --recursive
    

이제 https://storage.googleapis.com/<var>your-bucket-name</var>/static/...을 통해 정적 애셋에 액세스할 수 있습니다.

커스텀 도메인 이름에서 제공하는 방법 등 Cloud Storage를 사용해서 정적 애셋을 제공하는 방법에 대한 자세한 내용은 정적 웹사이트를 호스팅하는 방법을 참조하세요.

다른 Google Cloud 서비스에서 파일 제공

Cloud CDN 또는 다른 Google Cloud Storage 서비스를 사용할 수도 있습니다.

앱에서 직접 파일 제공

앱에서 파일을 제공하는 방법은 간단하지만 몇 가지 단점이 있습니다.

  • 정적 파일에 대한 요청에서 동적 요청에 사용되어야 할 리소스가 사용될 수 있습니다.
  • 구성에 따라서는 응답 지연이 발생할 수 있으며 이로 인한 부하 처리가 새 인스턴스 생성에도 영향을 미칠 수 있습니다.

앱을 사용한 정적 파일 제공 예시

Go

다음 샘플은 앱에서 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드에서 지원되는 Go 버전에 대한 샘플 애플리케이션을 사용할 수 있습니다.

표준 http.FileServer 또는 http.ServeFile을 사용하여 앱에서 직접 파일을 제공할 수 있습니다.


// Package static demonstrates a static file handler for App Engine flexible environment.
package main

import (
	"fmt"
	"net/http"

	"google.golang.org/appengine"
)

func main() {
	// Serve static files from "static" directory.
	http.Handle("/static/", http.FileServer(http.Dir(".")))

	http.HandleFunc("/", homepageHandler)
	appengine.Main()
}

const homepage = `<!doctype html>
<html>
<head>
  <title>Static Files</title>
  <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>`

func homepageHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, homepage)
}

자바

다음 샘플은 앱에서 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 Java 버전에서 사용할 수 있습니다.

자바 런타임의 서블릿 컨테이너는 앱의 배포 설명자web.xml 파일을 사용하여 URL을 정적 애셋을 포함한 서블릿에 매핑합니다. web.xml을 지정하지 않으면 모든 항목이 기본 서블릿에 매핑되는 기본값이 사용됩니다.

이 예에서 ./src/main/webapp/index.html/stylesheets/styles.css에서 제공되는 스타일 시트를 나타냅니다.

<!doctype html>
<html>
<head>
<title>Static Files</title>
<link rel="stylesheet" type="text/css" href="/stylesheets/styles.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>

styles.css 파일은 ./src/main/webapp/stylesheets/styles.css에 있습니다.

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

정적 파일이 web.xml 파일에서 처리되는 방법을 명시적으로 구성할 수 있습니다. 예를 들어, .jpg 확장자를 가진 모든 파일에 대한 요청을 매핑하는 방법은 다음과 같습니다.

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>

Play와 같은 웹 프레임워크를 사용하는 경우에는 정적 애셋에 대한 프레임워크 문서를 참조해야 합니다.

Node.js

다음 샘플은 앱에서 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 Node.js 버전에서 사용할 수 있습니다.

대부분의 웹 프레임워크에는 정적 파일을 제공하는 기능이 포함되어 있습니다. 이 샘플에서 애플리케이션은 express.static 미들웨어를 사용하여 ./public 디렉터리에서 /static URL로 파일을 제공합니다.

'use strict';

const express = require('express');
const app = express();

app.set('view engine', 'pug');

// Use the built-in express middleware for serving static files from './public'
app.use('/static', express.static('public'));

app.get('/', (req, res) => {
  res.render('index');
});

// Start the server
const PORT = parseInt(process.env.PORT) || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});

이 뷰는 /static/main.css를 나타냅니다.

doctype html
html(lang="en")
  head
    title Static Files
    meta(charset='utf-8')
    link(rel="stylesheet", href="/static/main.css")
  body
    p This is a static file serving example.

스타일시트 자체는 /static/main.css에서 제공되는 ./public/css에 있습니다.

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

Hapi, Koa, Sails와 같은 다른 Node.js 프레임워크는 일반적으로 앱에서 직접 정적 파일을 제공합니다. 정적 콘텐츠 구성 및 사용 방법에 대한 자세한 내용은 해당 문서를 참조하세요.

PHP

PHP 런타임은 앱에 서비스를 제공하기 위해, 프로젝트 디렉터리에 정적 파일을 제공하도록 구성된 nginx를 실행합니다. app.yaml 파일에서 document_root를 지정하여 문서 루트를 선언해야 합니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 PHP 버전에서 사용할 수 있습니다.

runtime: php
env: flex

runtime_config:
  document_root: web
  operating_system: ubuntu22
  runtime_version: 8.3

build_env_variables:
  NGINX_SERVES_STATIC_FILES: true

Python

다음 샘플은 앱에서 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 모든 Python 버전에 사용할 수 있습니다.

대부분의 웹 프레임워크에는 정적 파일을 제공하는 기능이 포함되어 있습니다. 이 샘플에서 앱은 Flask의 기본 제공 기능을 사용하여 /static URL에서 ./static 디렉터리로 파일을 제공합니다.

이 앱에는 템플릿을 렌더링하는 뷰가 포함되어 있습니다. Flask에서는 추가 구성 없이 자동으로 모든 파일을 ./static 디렉터리에 제공합니다.

import logging

from flask import Flask, render_template


app = Flask(__name__)


@app.route("/")
def hello():
    """Renders and serves a static HTML template page.

    Returns:
        A string containing the rendered HTML page.
    """
    return render_template("index.html")


@app.errorhandler(500)
def server_error(e):
    """Serves a formatted message on-error.

    Returns:
        The error message and a code 500 status.
    """
    logging.exception("An error occurred during a request.")
    return (
        f"An internal error occurred: <pre>{e}</pre><br>See logs for full stacktrace.",
        500,
    )


if __name__ == "__main__":
    # This is used when running locally. Gunicorn is used to run the
    # application on Google App Engine. See entrypoint in app.yaml.
    app.run(host="127.0.0.1", port=8080, debug=True)

이 뷰에서 렌더링된 템플릿에는 /static/main.css에 위치한 스타일시트가 포함되어 있습니다.

<!doctype html>
<html>
<head>
  <title>Static Files</title>
  <!--
  Flask automatically makes files in the 'static' directory available via
  '/static'.
  -->
  <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>

스타일시트는 ./static/main.css에 있습니다.

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

Django, Pyramid, Bottle와 같은 다른 Python 프레임워크는 일반적으로 앱에서 직접 정적 파일을 제공할 수 있습니다. 정적 콘텐츠를 구성 및 사용하는 방법에 대한 자세한 내용은 해당 문서를 참고하세요.

Ruby

대부분의 웹 프레임워크에는 정적 파일을 제공하는 기능이 포함되어 있습니다. 다음 샘플은 앱에서 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 Ruby 버전에서 사용할 수 있습니다.

Sinatra

Sinatra 웹 프레임워크는 기본적으로 ./public 디렉터리에서 파일을 제공합니다. 이 앱에는 /application.css를 참조하는 뷰가 포함되어 있습니다.

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

스타일시트는 /application.css에서 제공되는 ./public/application.css에 있습니다.

Ruby on Rails

Ruby on Rails 웹 프레임워크는 기본적으로 ./public 디렉터리에서 파일을 제공합니다. 정적 JavaScript 및 CSS 파일 또한 Rails 애셋 파이프라인으로 생성할 수 있습니다.

이 예시 앱에는 모든 애플리케이션 스타일 시트가 포함된 레이아웃 뷰가 있습니다.

doctype html
html
  head
    title Serving Static Files
    link rel="stylesheet" href="/application.css"
    script src="/application.js"
  body
    p This is a static file serving example.

스타일시트 자체는 ./public/application.css에 위치한 .css 파일입니다.

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

기본적으로 Rails 앱은 프로덕션에서 실행될 때 정적 애셋을 생성하거나 제공하지 않습니다.

Ruby 런타임은 배포 중에 rake assets:precompile을 실행하여 정적 애셋을 생성하고 프로덕션에서 정적 파일 제공을 사용하도록 RAILS_SERVE_STATIC_FILES 환경 변수를 설정합니다.

.NET

다음 샘플은 앱으로 정적 파일을 제공하는 방법을 보여줍니다. app.yaml 파일에 런타임 버전과 운영체제를 지정하여 이 가이드의 샘플 애플리케이션을 지원되는 .NET 버전에서 사용할 수 있습니다.

<html>
<head>
    <meta charset="utf-8" />
    <title>Hello Static World</title>
</head>
<body>
    <p>This is a static html document.</p>
    <p><img src="trees.jpg" /></p>
</body>
</html>

정적 파일 제공을 사용하려면 다음을 추가합니다.

app.UseDefaultFiles();
app.UseStaticFiles();

타사 콘텐츠 전송 네트워크에서 제공

외부 서드 파티 CDN을 사용해서 정적 파일을 제공하고 동적 요청을 캐시할 수 있지만, 이 경우 앱에서 지연 시간과 비용이 늘어날 수 있습니다.

성능 향상을 위해서는 CDN Interconnect를 지원하는 서드 파티 CDN을 사용해야 합니다.