App Engine 앱을 Go 1.9에서 Go 1.11로 마이그레이션

기존 App Engine 앱을 Go 1.9 런타임에서 App Engine 표준 환경의 새로운 Go 1.11 런타임으로 마이그레이션하는 방법을 알아봅니다.

App Engine Go SDK 계속 사용

Go 1.11 런타임에서 App Engine API를 사용할 수 있습니다. 하지만 앱을 Google Cloud Platform 컴퓨팅 서비스로 포팅할 수 있도록 Google Cloud 클라이언트 라이브러리로 마이그레이션할 수 있습니다.

appengine 패키지를 필요로 하는 앱의 경우 대신 공개적으로 사용 가능한 google.golang.org/appengine 패키지를 사용할 수 있다.

  1. 기존 import "appengine" 문을 다음으로 변경합니다.

    import "google.golang.org/appengine"
    
  2. 다음 명령어를 실행하여 google.golang.org/appengine 패키지를 업그레이드합니다.

    GOPATH를 사용하는 경우 다음 명령어를 실행합니다.

    go get -u google.golang.org/appengine
    

    Go 모듈을 사용하는 경우

    go get google.golang.org/appengine@'>=v1.2.0'
    

App Engine Go 1.11 런타임 변경사항

App Engine Go 1.11 런타임을 사용하려면 기존 App Engine Go 1.9 앱과 배포 프로세스를 일부 변경해야 할 수도 있습니다. 새 런타임의 주요 차이점은 다음과 같습니다.

app.yaml 파일 변경사항

app.yaml 구성 파일의 일부 요소 동작이 수정되었습니다.

요소 유형 변경 설명
api_version 지원 중단됨
runtime 수정됨 runtime: go111을 지정하도록 runtime 요소를 변경합니다.
application_readable 지원 중단됨
builtins 지원 중단됨
includes 지원 중단됨
login 지원 중단됨 Go 1.11 런타임은 login을 지원하지만 향후 Go 런타임에서는 지원되지 않습니다. 다른 방법으로 사용자를 인증해야 합니다.
libraries 지원 중단됨
threadsafe 지원 중단됨 모든 애플리케이션이 스레드 안전 상태로 간주됩니다. 즉, 인스턴스 한 개가 동시에 여러 요청을 처리할 수 있습니다.
skip_files 지원 중단됨 대신 app.yaml 파일이 있는 루트 디렉터리에 .gcloudignore 파일을 만듭니다. 자세한 내용은 .gcloudignore 참조를 확인하세요.

자세한 내용은 app.yaml 참조를 확인하세요.

main 패키지 만들기

서비스는 최소 한 개 이상의 소스 파일에 package main 문을 포함해야 합니다.

main 패키지 작성

서비스에 main 패키지가 아직 없는 경우 package main 문을 추가하고 main() 함수를 작성합니다. main() 함수는 최소한 다음 항목을 수행해야 합니다.

  • PORT 환경 변수를 읽고 http.ListenAndServe() 함수를 호출합니다.

    port := os.Getenv("PORT")
    if port == "" {
    	port = "8080"
    	log.Printf("Defaulting to port %s", port)
    }
    
    log.Printf("Listening on port %s", port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
  • 또는 서비스에서 google.golang.org/appengine 패키지를 사용하고 있는 경우 appengine.Main() 호출을 포함시킵니다.

HTTP 핸들러 등록

다음 옵션 중 하나를 선택하여 HTTP 핸들러를 등록할 수 있습니다.

  • 모든 http.HandleFunc() 호출을 사용 중인 패키지에서 main 패키지의 main() 함수로 수동 이동하는 방법을 사용하는 것이 좋습니다.
  • 또는 애플리케이션의 패키지를 main 패키지로 가져옵니다. 이때 각 init() 함수(http..HandleFunc() 호출 포함)가 시작 시 실행되는지 확인합니다.

    다음 bash 스크립트와 함께 http.HandleFunc() 호출을 사용하는 모든 패키지를 찾고 출력을 main 패키지의 import 블록에 복사할 수 있습니다.

    gp=$(go env GOPATH) && p=$(pwd) && pkg=${p#"$gp/src/"} && find . -name "*.go" | xargs grep "http.HandleFunc" --files-with-matches | grep -v vendor/ | grep -v '/main.go' | sed "s#\./\(.*\)/[^/]\+\.go#\t_ \"$pkg/\1\"#" | sort | uniq
    

파일 구조화

Go를 실행하려면 각 패키지가 고유한 디렉토리에 있어야 합니다. 따라서 다음과 유사한 파일 디렉토리를 가지고 있는 경우

  • myapp/
    • app.yaml
    • bar.go
    • foo.go

main 패키지가 app.yaml 파일과 함께 별도의 디렉토리에 위치하도록 바꿔야 합니다. 최종 파일 구조는 다음과 같아야 합니다.

  • myapp/
    • bar.go
    • foo.go
    • web/
      • app.yaml
      • main.go

파일을 GOPATH로 이동

다음 명령어를 사용하여 GOPATH를 찾습니다.

go env GOPATH

모든 관련 파일을 옮겨 GOPATH로 가져옵니다. import ./guestbook 등 관련 가져오기를 사용할 경우 전체 경로(import github.com/example/myapp/guestbook)를 사용하도록 가져오기를 업데이트합니다.

App Engine Go SDK에서 마이그레이션(선택사항)

기존 App Engine 관련 API 대신 Google Cloud 클라이언트 라이브러리 또는 타사 라이브러리를 사용하는 것이 좋습니다.

동시성 설정

Go 1.11 런타임은 프로젝트의 app.yaml 파일에 있는 threadsafe 값을 무시합니다. app.yaml 파일의 automatic_scaling: max_concurrent_requests 설정을 사용하여 동시성 설정을 지정할 수 있습니다.

Go 1.9 런타임에는 max_concurrent_requests 설정을 무시하는 알려진 문제가 있습니다. Go 1.11 및 최신 런타임은 프로젝트의 app.yaml 파일에서 max_concurrent_requests 설정의 값을 존중합니다.

max_concurrent_requests 값을 10 미만으로 설정하면 앱에 더 많은 인스턴스가 필요할 수 있습니다. max_concurrent_requests 값을 10 이상으로 설정하는 것이 좋습니다.