使用 VPC 的 AWS Lambda Play Scala 项目抛出 UnknownHostException

AWS Lambda Play Scala project with VPC throws UnknownHostException

我正在尝试 运行 基于示例 here 的 scala Play 应用程序作为 AWS Lambda 函数 class 是一个简单的函数:

 class PlayTask {

  // AWS Lambda Handler
  def exec(event: S3Event): String = WithApplication { App =>
    Play.current.configuration.getString("Play.Lambda.Greet").getOrElse("")
  }

  private def WithApplication[A](f: Application => A): A = {
    val env = Environment(new java.io.File("."), getClass.getClassLoader, Mode.Prod)
    val context = ApplicationLoader.createContext(env)
    val app = ApplicationLoader(context).load(context)
    try {
      Play.start(app)
      f(app)
    } finally {
      Play.stop(app)
    }
  }
}

jar 被加载到 S3 容器并连接到 VPC 以访问 RDS 和互联网。 但是,在连接 VPC 和 运行ning S3 put 测试时,我收到以下错误。

    at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:132) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.call(MembersInjectorImpl.java:93) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.call(MembersInjectorImpl.java:80) [task/:na] 
 at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:80) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:62) [task/:na] 
 at com.google.inject.internal.InjectorImpl.injectMembers(InjectorImpl.java:984) [task/:na] 
 at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149) [task/:na] 
 at com.google.inject.util.Providers$GuicifiedProviderWithDependencies$$FastClassByGuice$a7177aa.invoke(<generated>) [task/:na] 
 at com.google.inject.internal.cglib.reflect.$FastMethod.invoke(FastMethod.java:53) [task/:na] 
 at com.google.inject.internal.SingleMethodInjector.invoke(SingleMethodInjector.java:57) [task/:na] 
 at com.google.inject.internal.SingleMethodInjector.inject(SingleMethodInjector.java:91) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:132) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.call(MembersInjectorImpl.java:93) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.call(MembersInjectorImpl.java:80) [task/:na] 
 at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092) [task/:na] 
 at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:80) [task/:na] 
 at com.google.inject.internal.Initializer$InjectableReference.get(Initializer.java:174) [task/:na] 
 at com.google.inject.internal.Initializer.injectAll(Initializer.java:108) [task/:na] 
 at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:174) [task/:na] 
 at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110) [task/:na] 
 at com.google.inject.Guice.createInjector(Guice.java:96) [task/:na] 
 at com.google.inject.Guice.createInjector(Guice.java:73) [task/:na] 
 at com.google.inject.Guice.createInjector(Guice.java:62) [task/:na] 
 at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126) [task/:na] 
 at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93) [task/:na] 
 at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21) [task/:na] 
 at example.PlayTask.WithApplication(PlayTask.scala:16) [task/:na] 
 at example.PlayTask.exec(PlayTask.scala:9) [task/:na] 
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_71] 
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_71] 
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_71] 
 at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_71] 
 at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:439) [lambda-sandbox.jar:na] 
 at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:370) [lambda-sandbox.jar:na] 
 at lambdainternal.EventHandlerLoader.call(EventHandlerLoader.java:972) [lambda-sandbox.jar:na] 
 at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:231) [lambda-sandbox.jar:na] 
 at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:59) [lambda-sandbox.jar:na] 
 at java.lang.Class.forName0(Native Method) [na:1.8.0_71] 
 at java.lang.Class.forName(Class.java:348) [na:1.8.0_71] 
 at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:93) [runtime/:na] 
Caused by: java.net.UnknownHostException: ip-10-0-77-249: unknown error 
 at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method) ~[na:1.8.0_71] 
 at java.net.InetAddress.lookupAllHostAddr(InetAddress.java:928) ~[na:1.8.0_71] 
 at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323) ~[na:1.8.0_71] 
 at java.net.InetAddress.getLocalHost(InetAddress.java:1500) ~[na:1.8.0_71]

我从 java.net.UnknownHostException 中了解到,该函数无法找到 localhost 的主机名并退回到本地环回。

The jar is loaded onto S3 container and connected to VPC for access to RDS and internet.

当您启用 VPC 访问时,您实际上禁用了对 VPC 之外的任何内容的访问。您没有通过启用 VPC 为 Lambda 函数提供互联网访问权限,您实际上删除了互联网访问权限。此外,该函数不再具有访问 AWS API 服务器的权限,这就是您在尝试访问 S3 时遇到该错误的原因。您应该阅读 this blog post announcing VPC support for Lambda 末尾的 "Things to Know" 部分。

如果您希望 Lambda 函数可以访问互联网和 AWS APIs 以及您的 VPC 之外的所有其他内容,那么您需要向您的 VPC 添加一个 NAT Gateway

如果您只想添加对 Lambda 函数的 S3 访问,还有一个额外的选项,即使用 S3 VPC Endpoint

看来错误出在 AWS 端。昨天 AWS 在 Lambda 函数上停机后,错误消失了。虽然我很好奇是什么原因。