尝试在Docker中运行Kotlin + Spring Boot + WebFlux

简要描述

这次我想挑战一下,在标题所述的情况下,使用Kotlin编写Spring Boot + WebFlux,并在Docker上运行。

组成

使用Kotlin + Spring Boot + WebFlux创建API,并使其在Docker上运行。

创建项目

我們這次將使用IntelliJ來創建項目。

スクリーンショット 2018-08-31 23.45.36.png
スクリーンショット 2018-08-31 23.48.12.png
スクリーンショット 2018-08-31 23.51.49.png

在这些步骤之后,我会创建一个项目。(最开始可能会花费一些时间用于下载依赖关系等)

我自己尝试的时候,构建成功了而且没有出现任何问题,但如果遇到了困难,你可以参考下面的Gradle信息mm。

buildscript {
    ext {
        kotlinVersion = '1.2.51'
        springBootVersion = '2.0.4.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.darmaso.spring'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}
compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.boot:spring-boot-starter-data-redis-reactive')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    //compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-webflux')
    compile('com.fasterxml.jackson.module:jackson-module-kotlin')
    compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    compile("org.jetbrains.kotlin:kotlin-reflect")
    runtime('org.springframework.boot:spring-boot-devtools')
    compileOnly('org.projectlombok:lombok')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('io.projectreactor:reactor-test')
}

直接执行而不加思考,并且如果输出了如下日志,就表示OK。

・・・Started KotlinwebfluxApplicationKt in 8.127 seconds (JVM running for 10.728)
スクリーンショット 2018-09-01 0.00.17.png

目前的情况是,因为没有对路径进行处理,所以出现这种显示是没有问题的。

尝试使用WebFlux。

首先,为了快速创建API,我参考了WebFlux和Kotlin的响应式Web,在其中实现了一个返回用户列表的API。

以下是按照上述链接实施的示例。简要说明将在下文中提供。

路由

我会设置哪个路径执行哪个处理程序。

@Configuration
class Router(private val demoHandler: DemoHandler, private val userHandler: UserHandler) {
    @Bean
    fun apiRouter() = router {
        accept(MediaType.APPLICATION_JSON_UTF8).nest {
            GET("/v1/demo", demoHandler::getDemo)
            GET("/v1/users", userHandler::findAll)
        }
        accept(MediaType.TEXT_EVENT_STREAM).nest {
            GET("/stream/users", userHandler::streamOneSec)
        }
    }
}

在上面的例子中,它指的是设置对每个路径的请求为 application/json。特别之处在于第二个 accept 支持流式格式。

操作员

下面是userHandler的实现示例(完全是样本的拷贝)。

@Component
class UserHandler {
    private val users = Flux.just(
            User("1", "tarou", "1999-09-09"),
            User("2", "hanako", "2002-02-02"),
            User("3", "tonkichi", "1988-08-08")
    )
    private val streamingUsers = Flux
            .zip(Flux.interval(Duration.ofSeconds(1)), users.repeat())
            .map { it.t2 }

    fun findAll(req: ServerRequest): Mono<ServerResponse> {
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(users, User::class.java)
    }

    fun streamOneSec(req: ServerRequest) = ServerResponse.ok()
            .bodyToServerSentEvents(streamingUsers)
}

绊倒的地方

我只需要一种选择,以下是对原文的汉语翻译:
只剩下尝试执行了,但是我会在此提到一点困扰的地方。
在build.gradle中引入了spring-boot-starter-web,
在应用程序启动时,Tomcat会启动,但无法进行预期的映射模式><
为了期望在webflux方面启动netty,我尝试将相应部分注释掉了。
但是,我记得读过一篇文章,说是应该在application.yaml等文件中进行设置?
但是我忘记在哪里写了。。。如果有人知道,请告诉我mm

执行结果

$ curl -H "accept: application/json" http://localhost:8080/v1/users
[
 {"id":"1","name":"tarou","birth":"1999-09-09"},
 {"id":"2","name":"hanako","birth":"2002-02-02"},
 {"id":"3","name":"tonkichi","birth":"1988-08-08"}
]

$ curl -H "accept: application/json" http://localhost:8080/v1/demo    
{"message":"hello kotlin"}

$ curl -H "accept: text/event-stream" http://localhost:8080/stream/users
data:{"id":"1","name":"tarou","birth":"1999-09-09"}

data:{"id":"2","name":"hanako","birth":"2002-02-02"}

data:{"id":"3","name":"tonkichi","birth":"1988-08-08"}

data:{"id":"1","name":"tarou","birth":"1999-09-09"}

data:{"id":"2","name":"hanako","birth":"2002-02-02"}

data:{"id":"3","name":"tonkichi","birth":"1988-08-08"}

data:{"id":"1","name":"tarou","birth":"1999-09-09"}

顺便说一下

我在上述的build.gradle中注释掉了spring-boot-starter-web,但是我仍然可以正常显示使用@Controller的HTML页面(只显示静态页面)。

@Controller
class IndexController {

    @RequestMapping("/")
    fun index(): String {
        return "index"
    }
}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Kotlin, Spring Boot2, WebFlux</title>
</head>
<body>
<p>Hello! Kotlin, Sprint Boot2, WebFlux</p>
</body>
</html>

运行结果如下所示

$ curl http://localhost:8080/                                           
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Kotlin, Spring Boot2, WebFlux</title>
</head>
<body>
<p>Hello! Kotlin, Sprint Boot2, WebFlux</p>
</body>
</html> 

运行在Docker上

参考GCP的《在Google Kubernetes Engine上运行Kotlin Spring Boot应用程序》,尝试在Docker上运行。

Dockerfile的翻译为:镜像文件

直接使用上述样本

FROM openjdk:8-jdk-alpine
VOLUME /tmp
RUN mkdir /work
COPY . /work
WORKDIR /work
RUN /work/gradlew build
RUN mv /work/build/libs/*.jar /work/app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]

使用这个 Dockerfile 进行构建试试看。

$ docker build --no-cache -t demo .
Sending build context to Docker daemon  430.6kB
Step 1/8 : FROM openjdk:8-jdk-alpine
8-jdk-alpine: Pulling from library/openjdk
4fe2ade4980c: Pull complete 
6fc58a8d4ae4: Pull complete 
fe815adf554b: Pull complete 
Digest: sha256:a2d7b02891b158d01523e26ad069d40d5eb2c14d6943cf4df969b097acaa77d3
Status: Downloaded newer image for openjdk:8-jdk-alpine
・・・・<<省略>>・・・・・
BUILD SUCCESSFUL in 3m 11s
6 actionable tasks: 6 executed
Removing intermediate container d931cb7f17f1
 ---> 51321afaedb9
Step 7/8 : RUN mv /work/build/libs/*.jar /work/app.jar
 ---> Running in 730bad53d9e7
Removing intermediate container 730bad53d9e7
 ---> 65a15aec971d
Step 8/8 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]
 ---> Running in bd139be8b399
Removing intermediate container bd139be8b399
 ---> d388bccfcf18
Successfully built d388bccfcf18
Successfully tagged demo:latest

由于构建成功,最后进行执行并确认其运行状态。

$ docker run -it --rm -p 8080:8080 demo

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.4.RELEASE)
・・・・・<<省略>>・・・・・
〜: Started HttpServer on /0.0.0.0:8080
〜: Netty started on port(s): 8080
〜: Started KotlinwebfluxApplicationKt in 7.599 seconds (JVM running for 8.422)

如果出现像上面那样的日志,并且获得与之前的”执行结果”相同的结果,那就可以了。
之后,可以使用Command + C或其他方式停止Docker(由于指定了–rm,在自动销毁容器时)。

如果您将它容器化,然后将其放在您喜欢的平台(如AWS、GCP、Azure等)上,应该会很不错。

我以后想做的事情

与Redis的连接

    • せっかくWebFluxを使うので、Non-BlockingのNoSQLと接続してみるために、Redisを利用

 

    • ローカル環境で開発するために、docker-composeでredisを動かす

 

    クラウド環境で接続するときは、接続先を変えるなど

CI/CD 在 AWS 上

    • GithubにPushしたら、テストコードの実行とビルドまでが自動で動くようにする

 

    CIが完了すると、特定の環境(Fargateなど)にデプロイされるようにする

请提供更多上下文信息才能准确地回答您的问题。

    • beta-yumatsud/springboot-study

 

    • Reactive web services using Kotlin and Spring Boot 2

 

    Run a Kotlin Spring Boot application on Google Kubernetes Engine
广告
将在 10 秒后关闭
bannerAds