이 페이지에서는 1세대에서 2세대 Go 런타임으로 마이그레이션하는 방법을 안내합니다. 지원되는 최신 Go 버전을 사용하도록 2세대 앱을 업그레이드하는 방법은 기존 애플리케이션 업그레이드를 참조하세요.
Go 1.11은 2024년 1월 30일 지원 종료되었습니다. 기존 Go 1.11 애플리케이션을 계속 실행하고 트래픽을 수신합니다. 그러나 App Engine에서 지원 종료일 이후에 런타임을 사용하는 애플리케이션의 재배포를 차단할 수 있습니다.
이 페이지의 가이드라인을 참고하여 지원되는 최신 Go 런타임으로 마이그레이션하는 것이 좋습니다.
지원되는 2세대 Go 런타임으로 마이그레이션하면 최신 언어 기능을 사용하고 관용적인 코드로 이동성이 향상된 앱을 빌드할 수 있습니다.
런타임 마이그레이션 노력과 복잡성이 줄어들도록 App Engine 표준 환경에서는 Memcache와 같은 2세대 런타임의 다양한 기존 번들 서비스와 API에 액세스할 수 있습니다.
2세대 Go 앱은 Go용 App Engine SDK를 통해 번들 서비스 API를 호출하고 Go 1.11 런타임과 동일한 기능 대부분에 액세스할 수 있습니다.
기존 번들 서비스와 비슷한 기능을 제공하는 Google Cloud 제품을 사용할 수도 있습니다. 이러한 Google Cloud제품은 관용적인 Go용 Cloud 클라이언트 라이브러리를 제공합니다.Google Cloud에서 별도의 제품으로 제공되지 않는 번들 서비스의 경우(예: 이미지 처리, 검색, 메시지) 타사 제공업체 또는 다른 해결 방법을 사용할 수 있습니다.
번들되지 않은 서비스로 마이그레이션하는 방법에 대한 자세한 내용은 번들 서비스에서 마이그레이션을 참조하세요.
app.yaml 구성 파일의 일부 요소 동작이 수정되었습니다. 자세한 내용은 app.yaml 파일 변경사항을 참조하세요.
2세대 런타임에 로깅은 Cloud Logging의 로깅 표준을 따릅니다. 2세대 런타임에서 앱 로그는 더 이상 요청 로그와 번들로 제공되지 않고 다른 레코드로 분리됩니다. 2세대 런타임에서 로그를 읽고 쓰는 방법에 대한 자세한 내용은 로깅 가이드를 참조하세요.
메모리 사용량 차이
2세대 런타임은 1세대 런타임에 비해 메모리 사용량 기준이 더 높습니다. 이는 여러 다른 기본 이미지 버전, 두 세대 간의 메모리 사용량 계산 방법의 차이와 같은 여러 요인 때문에 발생합니다.
2세대 런타임은 애플리케이션 프로세스가 사용하는 항목의 합계 및 메모리에 동적으로 캐시된 애플리케이션 파일 수에 따라 인스턴스 메모리 사용량을 계산합니다. 메모리 사용량이 높은 애플리케이션에서 메모리 한도 초과로 인한 인스턴스 종료가 발생하지 않도록 방지하려면 메모리가 많은 더 큰 인스턴스 클래스로 업그레이드하세요.
CPU 사용량 차이
2세대 런타임은 인스턴스 콜드 스타트 시 CPU 사용량 기준이 더 높을 수 있습니다. 그 결과 애플리케이션의 확장 구성에 따라 애플리케이션이 CPU 사용률을 기준으로 확장되도록 구성된 경우 예상한 것보다 높은 인스턴스 수와 같은 의도치 않은 부작용이 발생할 수 있습니다. 이러한 문제를 방지하기 위해서는 애플리케이션 확장 구성을 검토 및 테스트해서 인스턴스 수를 적정 수준으로 유지해야 합니다.
요청 헤더 차이
1세대 런타임에서는 밑줄이 사용된 요청 헤더(예: X-Test-Foo_bar)를 애플리케이션에 전달할 수 있습니다. 2세대 런타임에는 호스트 아키텍처에 Nginx가 도입되었습니다. 이러한 변경사항으로 인해 2세대 런타임은 밑줄(_)이 있는 헤더를 자동으로 삭제하도록 구성됩니다. 애플리케이션 문제를 방지하기 위해서는 애플리케이션 요청 헤더에 밑줄을 사용하지 않아야 합니다.
서비스는 v2(google.golang.org/appengine/v2) 패키지만 사용해야 합니다.
이전 v1(google.golang.org/appengine) 패키지를 사용하면 오류가 발생합니다.
main() 함수에서 http.ListenAndServe() 대신 appengine.Main()을 호출합니다. 이렇게 하면 user 및 appengine API가 현재 요청 컨텍스트에 액세스할 수 있습니다.
main 패키지 작성
서비스에 아직 main 패키지가 없으면 package main 문을 추가하고 main() 함수를 작성합니다. 최소한main() 함수가 다음을 수행해야 합니다.
PORT 환경 변수를 읽고 http.ListenAndServe() 함수를 호출합니다.
port:=os.Getenv("PORT")ifport==""{port="8080"log.Printf("Defaulting to port %s",port)}log.Printf("Listening on port %s",port)iferr:=http.ListenAndServe(":"+port,nil);err!=nil{log.Fatal(err)}
HTTP 핸들러 등록
다음 옵션 중 하나를 선택하여 HTTP 핸들러를 등록할 수 있습니다.
모든 http.HandleFunc() 호출을 사용 중인 패키지에서 main 패키지의 main() 함수로 직접 이동하는 것이 좋습니다.
또는 애플리케이션의 패키지를 main 패키지로 가져옵니다. 이때 각 init() 함수(http.HandleFunc() 호출이 포함)가 시작 시 실행되는지 확인합니다.
다음 bash 스크립트와 함께 http.HandleFunc() 호출을 사용하는 모든 패키지를 찾고 출력을 main 패키지의 import 블록에 복사할 수 있습니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-04(UTC)"],[[["\u003cp\u003eThis guide provides instructions for migrating applications from first-generation to supported second-generation Go runtimes on App Engine, including changes to \u003ccode\u003eapp.yaml\u003c/code\u003e, memory and CPU usage, and request headers.\u003c/p\u003e\n"],["\u003cp\u003eGo 1.11 reached its end of support on January 30, 2024, and while existing applications will continue to run, redeployment might be blocked; thus, it is recommended to migrate to the latest supported Go runtime.\u003c/p\u003e\n"],["\u003cp\u003eSecond-generation runtimes allow access to many legacy bundled services via the App Engine SDK, but some are not available, requiring the use of alternative Google Cloud products, third-party services, or other workarounds.\u003c/p\u003e\n"],["\u003cp\u003eMigrating to a second-generation Go runtime requires creating a \u003ccode\u003emain\u003c/code\u003e package, and registering your HTTP handlers either by manually moving \u003ccode\u003ehttp.HandleFunc()\u003c/code\u003e calls or importing packages with \u003ccode\u003einit()\u003c/code\u003e functions.\u003c/p\u003e\n"],["\u003cp\u003eUpgrading may involve managing increased baseline memory and CPU usage, avoiding underscores in request headers, and adjusting the \u003ccode\u003eapp.yaml\u003c/code\u003e file's \u003ccode\u003eapp_engine_apis\u003c/code\u003e, \u003ccode\u003elogin\u003c/code\u003e, and \u003ccode\u003eruntime\u003c/code\u003e elements.\u003c/p\u003e\n"]]],[],null,["# Migrate from Go 1.11 to the latest Go runtime\n\nThis page covers instructions for migrating from the\n[first-generation to the second-generation](/appengine/docs/standard/runtimes)\nGo runtimes. To upgrade your second-generation app to use the latest supported\nversion of Go, see [Upgrade an existing application](/appengine/docs/standard/go/upgrade-go-runtime).\n\nGo 1.11 has reached [end of support](/appengine/docs/standard/lifecycle/runtime-lifecycle#end_of_support)\non January 30, 2024. Your existing Go 1.11 applications will continue\nto run and receive traffic. However, App Engine might block re-deployment of applications\nthat use runtimes [after their end of support date](/appengine/docs/standard/lifecycle/support-schedule#go).\nWe recommend that you migrate to the [latest supported runtime](/appengine/docs/standard/lifecycle/support-schedule#go) of Go by using the\nguidelines in this page.\n\nMigrating to a [supported second-generation Go runtime](/appengine/docs/standard/runtimes)\nlets you use up-to-date language\nfeatures and build apps that are more portable, with idiomatic code.\n\nChanges in the second-generation runtimes\n-----------------------------------------\n\nConsider the following differences when upgrading to a [supported](/appengine/docs/standard/lifecycle/support-schedule#go) second-generation Go runtime:\n\n- To reduce runtime migration effort and complexity, the App Engine standard environment lets you\n [access many of the legacy bundled services and APIs in the second-generation\n runtimes](/appengine/docs/standard/go/services/access), such as Memcache.\n Your second-generation Go app can call the bundled services APIs through the\n App Engine SDK for Go, and access most of the same features as on the\n Go 1.11 runtime.\n\n | **Note:** Not all the App Engine bundled services available for Go 1.11 have a corresponding service in the second-generation runtimes. For the full list of available legacy bundled services APIs in the second-generation runtimes, see the [legacy bundled services API references documentation](/appengine/docs/standard/go/services/access).\n\n You also have the option to use Google Cloud products that offer\n similar features as the legacy bundled services. These Google Cloud\n products provide idiomatic [Cloud Client Libraries for Go](https://github.com/googleapis/google-cloud-go).\n For the bundled services that are not available as separate products in\n Google Cloud, such as image processing, search, and messaging, you can\n use third-party providers or other workarounds.\n\n To learn more about migrating to unbundled services, see\n [Migrating from bundled services](/appengine/migration-center/standard/services/migrating-services).\n- The behavior of some elements in the `app.yaml` configuration file has been\n modified. For more information, see [Changes to the `app.yaml` file](#app-yaml).\n\n- Logging in the second-generation runtime follows the logging standard in\n [Cloud Logging](/logging). In the second-generation runtimes,\n app logs are no longer bundled with the request logs but are separated in\n different records. To learn more about reading and writing logs in the\n second-generation runtimes, see the [logging guide](/appengine/docs/standard/writing-application-logs).\n\n### Memory usage differences\n\nSecond-generation runtimes see a higher baseline of memory usage compared\nto first-generation runtimes. This is due to multiple factors, such as different\nbase image versions, and differences in how the two generations calculate memory\nusage.\n\nSecond-generation runtimes calculate instance memory usage as the sum of what an\napplication process uses, and the number of application files dynamically cached\nin memory. To avoid memory-intensive applications from experiencing instance\nshutdowns due to exceeding memory limits, upgrade to a larger\n[instance class](/appengine/docs/standard#instance_classes) with more memory.\n\n### CPU usage differences\n\nSecond-generation runtimes can see a higher baseline of CPU usage upon instance\ncold-start. Depending on an application's scaling configuration, this might have\nunintended side effects, such as, a higher instance count than anticipated if an\napplication is configured to scale based on CPU utilization. To avoid this\nissue, review and test application scaling configurations to ensure the number\nof instances are acceptable.\n\n### Request header differences\n\nFirst-generation runtimes allow request headers with underscores\n(e.g. `X-Test-Foo_bar`) to be forwarded to the application. Second-generation\nruntimes introduces Nginx into the host architecture. As a result of this\nchange, second-generation runtimes are configured to automatically remove\nheaders with underscores (`_`). To prevent application issues, avoid using\nunderscores in application request headers.\n\nChanges to the `app.yaml` file\n------------------------------\n\nThe behavior of some elements in the `app.yaml` configuration file has been\nmodified:\n\nFor more information, see the\n[`app.yaml` reference](/appengine/docs/standard/reference/app-yaml).\n\nCreate a `main` package\n-----------------------\n\nYour service must include a `package main` statement in at least one source\nfile.\n\n### App Engine legacy bundled services\n\nIf your service uses the\n[legacy bundled services\nfor the second-generation runtimes](/appengine/docs/standard/go/services/access):\n\n- Your service must only use v2 (`google.golang.org/appengine/v2`) packages.\n Using the older v1 (`google.golang.org/appengine`) packages causes errors.\n\n- In your `main()` function, call `appengine.Main()` instead of\n `http.ListenAndServe()`. This ensures that the `user` and `appengine`\n APIs have access to current request context.\n\n### Writing a main package\n\nIf your service doesn't already contain a `main` package, add the\n`package main` statement and write a `main()` function. At a **minimum** ,\nthe `main()` function should:\n\n- Read the `PORT` environment variable and call the `http.ListenAndServe()`\n function:\n\n port := os.Getenv(\"PORT\")\n if port == \"\" {\n \tport = \"8080\"\n \tlog.Printf(\"Defaulting to port %s\", port)\n }\n\n log.Printf(\"Listening on port %s\", port)\n if err := http.ListenAndServe(\":\"+port, nil); err != nil {\n \tlog.Fatal(err)\n }\n\n### Registering your HTTP handlers\n\nYou can register your HTTP handlers by choosing **one** of the following\noptions:\n\n- The preferred method is to manually move all `http.HandleFunc()` calls from your packages to your `main()` function in your `main` package.\n- Alternatively, import your application's packages into your `main` package,\n ensuring each `init()` function that contains calls to `http.HandleFunc()`\n gets run on startup.\n\n You can find all packages which use the `http.HandleFunc()` call with the\n following bash script, and copy the output into your `main` package's\n `import` block: \n\n 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\n\nStructuring your files\n----------------------\n\nGo requires each package has its own directory. You can tell\nApp Engine where your `main` package is by using `main:` in your\nproject's `app.yaml` file. For example, if your app's file structure looked\nlike this: \n\n```\nmyapp/\n├── app.yaml\n├── foo.go\n├── bar.go\n└── web/\n └── main.go\n```\n\nYour `app.yaml` file would have: \n\n main: ./web # Relative filepath to the directory containing your main package.\n\nFor more information about the `main` flag, see the [`app.yaml`\nreference](/appengine/docs/standard/go/config/appref#main).\n\nMoving files to your `GOPATH`\n-----------------------------\n\nFind your `GOPATH` by using the following command: \n\n go env GOPATH\n\nMove all relevant files and imports to your `GOPATH`. If using relative\nimports, such as `import ./guestbook`, update your imports to use the full\npath: `import github.com/example/myapp/guestbook`."]]