サーバーの設定

Estimated reading time: 6 minutes

Ktorは外部設定ファイルにHOCON (Human-Optimized Config Object Notation)フォーマットを利用しています。 このファイル内ではリッスンするport番号であったり、ロードするmoduleであったりを設定します。 JSONに似たフォーマットですが、人が読み書きしやすいよう最適化されており、環境変数の置換のような追加機能をサポートしています。 以下のケースでは、mainClassNameを使うことで特定のEngineMainを指定し、サーバーエンジンの設定を行います。

またKtorは型付けされたDSL(Domain Specific Language)とともにlambdaのセットを用い、アプリケーションとサーバーエンジンをembeddedServerを使って設定することもできます。

Ktor 1.0.0-beta-2で始める場合は、DevelopmentEngineクラスはEngineMainにリネームされているため、古いバージョンを使う場合はリネームしてください。

目次:

HOCONファイル

アプリケーションを再コンパイルすることなく設定を簡単に変更できるため、この方法がKtorアプリケーションを設定する上での推奨される方法となります。

KtorがEngineMainを使って起動されたときやcommandLineEnvironmentを呼び出したとき、アプリケーションresourceからapplication.confという名のHOCONファイルを読み込もうとします。 コマンドライン引数を利用することでファイルの位置を変更することができます。

以下はmainClassNameとして指定可能で開発エンジンとして利用可能なものです:

  • io.ktor.server.cio.EngineMain
  • io.ktor.server.tomcat.EngineMain
  • io.ktor.server.jetty.EngineMain
  • io.ktor.server.netty.EngineMain

Ktorにはどのmoduleをサーバー起動時にロードしたいのかをktor.application.modulesプロパティを使って指定するだけで大丈夫です。 その他のプロパティはオプショナルです。

典型的なシンプルなKtor (application.conf)のHOCONファイルは以下のようになります:

ktor {
    deployment {
        port = 8080
    }

    application {
        modules = [ io.ktor.samples.metrics.MetricsApplicationKt.main ]
    }
}

ドット記法を使っても同じです:

ktor.deployment.port = 8080
ktor.application.modules = [ io.ktor.samples.metrics.MetricsApplicationKt.main ]

Ktorはより様々な設定が行なえます。 Ktorの機能に関わるその他のコアな設定であったり、あなたのアプリケーションのためのカスタムの設定値であったり様々な設定が行えます:

ktor {
    deployment {
        environment = development
        port = 8080
        sslPort = 8443
        autoreload = true
        watch = [ httpbin ]
    }

    application {
        modules = [ io.ktor.samples.httpbin.HttpBinApplicationKt.main ]
    }

    security {
        ssl {
            keyStore = build/temporary.jks
            keyAlias = mykey
            keyStorePassword = changeit
            privateKeyPassword = changeit
        }
    }
}

jwt {
    domain = "https://jwt-provider-domain/"
    audience = "jwt-audience"
    realm = "ktor sample app"
}

youkube {
  session {
    cookie {
      key = 03e156f6058a13813816065
    }
  }
  upload {
    dir = ktor-samples/ktor-samples-youkube/.video
  }
}

このドキュメント内に設定可能なコア設定の一覧があります。

HOCONを使うことでプロパティを環境変数から設定することができます。

HOCON用のIntelliJプラグインもあるので、インストールすると良いかもしれません。

コマンドライン

commandLineEnvironmentを使うとき、アプリケーションmoduleを設定する上で利用可能な設定パラメータがいくつかあります。

-config=anotherfile.confを使ってコマンドラインからアプリケーションをを起動したならば、resourceからの代わりにローカルの指定したファイルから設定ファイルを読み込みます。

設定パラメータを使うことでbindされているport番号を上書きすることもできます。

java -jar myapp-fatjar.jar -port=8080

利用可能なコマンドラインの設定パラメータ一覧がこのドキュメント内にあります。

embeddedServerの設定

embeddedServerはKtorアプリケーションを起動するための単純な方法です。 あなたが定義したmain関数を提供することで、何が実際に起きるのかを理解するのが簡単になります。

embeddedServerはオプショナルなパラメータであるconfigureを持っており、第一引数で指定されたエンジンのための設定をセットします。 利用しているエンジンごとに独立しており、いくつかの設定可能なプロパティがあります:

embeddedServer(AnyEngine, configure = {
    // Size of the event group for accepting connections
    connectionGroupSize = parallelism / 2 + 1
    // Size of the event group for processing connections,
    // parsing messages and doing engine's internal work 
    workerGroupSize = parallelism / 2 + 1
    // Size of the event group for running application code 
    callGroupSize = parallelism 
}) {
    // ...
}.start(true)

Multiple connectors

applicationEngineEnvironmentを使ってコードでいくつかのコネクタを定義することができます。

applicationEngineEnvironmentの内部で、HTTPとHTTPSのコネクタが定義できます。

HTTPコネクタの定義:

connector {
    host = "0.0.0.0"
    port = 9090
}

HTTPSコネクタの定義:

sslConnector(keyStore = keyStore, keyAlias = "mykey", keyStorePassword = { "changeit".toCharArray() }, privateKeyPassword = { "changeit".toCharArray() }) {
    port = 9091
    keyStorePath = keyStoreFile.absoluteFile
}

実際の例:

fun main(args: Array<String>) {
    val env = applicationEngineEnvironment {
        module {
            main()
        }
        // Private API
        connector {
            host = "127.0.0.1"
            port = 9090
        }
        // Public API
        connector {
            host = "0.0.0.0"
            port = 8080
        }
    }
    embeddedServer(Netty, env).start(true)
}

各ApplicationCallのローカルportにアクセスすることで、ローカルportに応じて何をするかを決めることができます:

fun Application.main() {
    routing {
        get("/") {
            if (call.request.local.port == 8080) {
                call.respondText("Connected to public api")
            } else {
                call.respondText("Connected to private api")
            }
        }
    }
}

これに関する動作する例はktor-samples/multiple-connectorsを見てください。

Netty

Nettyをエンジンとして使うとき、共通のプロパティに加え、いくつかの他のプロパティも設定できます:

embeddedServer(Netty, configure = {
    // Size of the queue to store [ApplicationCall] instances that cannot be immediately processed
    requestQueueLimit = 16 
    // Do not create separate call event group and reuse worker group for processing calls
    shareWorkGroup = false 
    // User-provided function to configure Netty's [ServerBootstrap]
    configureBootstrap = {
        // ...
    } 
    // Timeout in seconds for sending responses to client
    responseWriteTimeoutSeconds = 10 
}) {
    // ...
}.start(true)

Jetty

Jettyをエンジンとして使うとき、共通のプロパティに加え、いくつかの他のプロパティも設定できます:

embeddedServer(Jetty, configure = {
    // Property to provide a lambda that will be called during Jetty
    // server initialization with the server instance as an argument.
    configureServer = {
        // ...
    } 
}) {
    // ...
}.start(true)

CIO

CIO(Coroutine I/O)をエンジンとして使うとき、共通のプロパティに加え、connectionIdleTimeoutSecondsプロパティも設定できます:

embeddedServer(CIO, configure = {
    // Number of seconds that the server will keep HTTP IDLE connections open.
    // A connection is IDLE if there are no active requests running.
    connectionIdleTimeoutSeconds = 45
}) {
    // ...
}.start(true)

Tomcat

Tomcatをエンジンとして使うとき、共通のプロパティに加え、いくつかの他のプロパティも設定できます:

embeddedServer(Tomcat, configure = {
    // Property to provide a lambda that will be called during Tomcat
    // server initialization with the server instance as argument.
    configureTomcat { // this: Tomcat ->
        // ...
    }
}) {
    // ...
}.start(true)

これらはKtorによって開発されているオフィシャルなエンジンですが、自作のエンジンを作ることも可能で、それに対しカスタムの設定を作ることも可能です。

利用可能な設定パラメータ

コマンドラインまたはHOCONファイルから渡すことで、Ktorが追加設定なく利用可能なプロパティ一覧があります。

アプリケーションにわたすコマンドライン引数をSwitchと呼びます。例えばbindされているportを変更するには:

java -jar myapp-fatjar.jar -port=8080

application.conf内のpathをParameter pathsと呼びます:

ktor.deployment.port = 8080
ktor {
    deployment {
        port = 8080
    }
}

一般的なSwitchとParameterです:

Switch Parameter path Default Description
-jar=     JARファイルへのパス
-config=     configファイルへのパス(resource内のapplication.confがデフォルト)
-host= ktor.deployment.host 0.0.0.0 bindされているhost
-port= ktor.deployment.port 80 bindされているport
-watch= ktor.deployment.watch [] リロードを監視するパッケージパス
  ktor.application.id Application ログ出力する際のアプリケーション識別子
  ktor.deployment.rootPath / Servlet context path
  ktor.deployment.callGroupSize parallelism Event group size running application code
  ktor.deployment.connectionGroupSize parallelism / 2 + 1 Event group size accepting connections
  ktor.deployment.workerGroupSize parallelism / 2 + 1 Event group size for processing connections, parsing messages and doing engine’s internal work
  ktor.deployment.shutdown.url   アプリケーションをシャットダウンするためのURL。内部的にShutDownUrl機能を利用してます。

SSLポートが定義されているときに必須:

Switch Parameter path Default Description
-sslPort= ktor.deployment.sslPort null SSL port
-sslKeyStore= ktor.security.ssl.keyStore null SSL key store
  ktor.security.ssl.keyAlias mykey Alias for the SSL key store
  ktor.security.ssl.keyStorePassword null Password for the SSL key store
  ktor.security.ssl.privateKeyPassword null Password for the SSL private key

特定のswitchに一致しないパラメータを指定するために-P:を使うこともできます。例えば: -P:ktor.deployment.callGroupSize=7.

コードから設定を読み込む

embeddedServerの代わりにEngineMainを使っているなら、HOCONファイルは読み込まれており、設定したプロパティにアクセスすることができます。

アプリケーションを設定するために任意のプロパティのパスを定義することもできます。

val port: String = application.environment.config
    .propertyOrNull("ktor.deployment.port")?.getString()
    ?: "80"

commandLineEnvironmentとともにカスタムのmain関数を利用することで、HOCON形式のapplication.conf設定ファイルにもアクセスすることができます:

embeddedServer(Netty, commandLineEnvironment(args + arrayOf("-port=8080"))).start(true)

または特定のEngineMain.mainにリダイレクトすることもできます:

val moduleName = Application::module.javaMethod!!.let { "${it.declaringClass.name}.${it.name}" }
io.ktor.server.netty.main(args + arrayOf("-port=8080", "-PL:ktor.application.modules=$moduleName"))

またはカスタムのapplicationEngineEnvironmentと一緒に使えます:

embeddedServer(Netty, applicationEngineEnvironment {
    log = LoggerFactory.getLogger("ktor.application")
    config = HoconApplicationConfig(ConfigFactory.load()) // Provide a Hocon config file

    module {
        routing {
            get("/") {
                call.respondText("HELLO")
            }
        }
    }

    connector {
        port = 8080
        host = "127.0.0.1"
    }
}).start(true)

デフォルトの設定ファイルであるapplication.confを明示的に読み込むことで、設定プロパティにアクセスすることもできます:

val config = HoconApplicationConfig(ConfigFactory.load())

環境変数を使う

HOCONにおいて、環境変数を使っていくつかのパラメータを設定したい場合、${ENV}シンタックスを利用して置換を行うことができます。例えば:

ktor {
    deployment {
        port = ${PORT}
    }
}

このコードはPORT環境変数を探します。そして見つからなければ例外を投げます:

Exception in thread "main" com.typesafe.config.ConfigException$UnresolvedSubstitution: application.conf @ file:/path/to/application.conf: 3: Could not resolve substitution to a value: ${PORT}

環境変数が見つからない場合のプロパティのデフォルト値を指定したい場合は、デフォルト値でプロパティをセットしその後再度${?ENV}シンタックスで設定すればよいです:

ktor {
    deployment {
        port = 8080
        port = ${?PORT}
    }
}

embeddedServerを使っている場合は、JavaからSystem.getenvが使えます。例えば:

val port = System.getenv("PORT")?.toInt() ?: 8080

カスタム設定システム

application.environment.configにおいて利用できる、設定を実装するためのインターフェースをKtorは提供しています。 applicationEngineEnvironment内で設定プロパティの構築およびセットを行うことができます。

interface ApplicationConfig {
    fun property(path: String): ApplicationConfigValue
    fun propertyOrNull(path: String): ApplicationConfigValue?
    fun config(path: String): ApplicationConfig
    fun configList(path: String): List<ApplicationConfig>
}

interface ApplicationConfigValue {
    fun getString(): String
    fun getList(): List<String>
}

class ApplicationConfigurationException(message: String) : Exception(message)

Ktorは2種類の実装を提供しています。1つはMap(MapApplicationConfig)をベースにしたもの、もう1つはHOCON(HoconApplicationConfig)をベースにしたものです。

configの実装を作成・組み合わせ、applicationEngineEnvironmentにおいてそれらをセットすることができます。 そうすることですべてのアプリケーションコンポーネントにおいて利用可能になります。