Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践Play2+Kubernetes

 実践Play2+Kubernetes

市ヶ谷Geek★Nightでの発表資料

Tatsuya Atsumi

April 03, 2018
Tweet

More Decks by Tatsuya Atsumi

Other Decks in Technology

Transcript

  1. • Twitter: https://twitter.com/__Attsun__ • ブレインパッドという会社で自社サービス開発してます • VP of Engineeringとかテックリードとかやってます •

    得意な言語はPythonです!家ではGoです!Scalaは仕事です! ◦ ScalaはBetter Javaとして使っているだけのガチじゃない勢です • Kubernetesが好きで! 自己紹介:渥美 達也
  2. アジェンダ 1. k8sを利用しているサービスのご紹介 2. k8sのおさらい 3. システム構成 4. Play2 on

    k8sのプラクティス a. コンテナビルド b. k8sへのデプロイ c. 環境変数の設定 d. コンフィグの設定 e. ロギングの設定
  3. システム構成ざっくり Cloud Load Balancing Cloud DNS Cloud SQL GKE 1.9

    admin Deployment web Deployment batch CronJob Firebase Media (G, Y, …) BigQuery MediaHub Accounts batch CronJob
  4. Kubernetesとは? 公式によると、以下だそうです。 Kubernetes is an open-source system for automating deployment,

    scaling, and management of containerized applications. 雑に表現すると、コンテナベースのアプリケーションを管理する仕組みですね。
  5. Pod / Deployment / Service / kubectl • Pod ◦

    Kubernetesで実行されるアプリケーションの最小単位です。 ◦ 1個以上のコンテナから構成されます。 • Deployment ◦ 個々のPodをどのように実行するかを管理する単位です ◦ Podのレプリカの数や、Podが利用するコンテナを管理しており、Deploymentを更新することでPod が更新されます。 • Service ◦ Podを論理的な単位でまとめ、それらへのアクセスポリシーを定義する仕組みです。 ◦ Podはコンテナアップデートなどにより頻繁に生成されたり破棄されたりを繰り返しますが、Service を見ている限り影響されません。 • kubectl ◦ kubernetesのコマンドラインクライアントです。 ◦ kubectl apply xxx.yaml で、YAMLに記載されたDeploymentなどの設定を反映するなど。 今日必要な最低限の知識
  6. [node-2] [node-1] Pod / Deployment / Service [pod-nginx-1] nginx container

    [pod-nginx-2] nginx container Podは特定のノード上で稼働し ます。
  7. [node-2] [node-1] [deployment-nginx] container=nginx:1.7.9 replica=2 port=80 Pod / Deployment /

    Service [pod-nginx-1] nginx container [pod-nginx-2] nginx container Podがどのように稼働するかは、 Deploymentにより管理される (ReplicaSetは割愛)
  8. [node-2] [node-1] [deployment-nginx] container=nginx:1.7.9 replica=2 port=80 Pod / Deployment /

    Service [pod-nginx-1] nginx container [pod-nginx-2] nginx container [service-nginx] Serviceが、Podへのアクセスを管理 している。 このケースではLBとしても働いてい る。
  9. Podの構成 • 同じPodの中に複数のコンテナが動いているパターン • Nginxコンテナ ◦ 静的コンテンツのホスト ◦ Play2 APIへのプロキシ

    • Play2コンテナ ◦ Nginxから流れてきたAPIを実行する ◦ ベースはJava8コンテナ ◦ Scala 2.11 + Play 2.5 • Cloud SQL Proxyコンテナ ◦ Cloud SQLへの接続に必要なやつ webapp Pod Nginx Container Play2 Container CloudSQLProxy Container
  10. sbtでPlay2コンテナ作成 lazy val webapp = project.in(file(“webapp”)) .dependsOn(依存パッケージたち) .enablePlugin(PlayScala, JavaAppPackaging, sbtdocker.DockerPlugin)

    .settings(Scalaバージョンなどの共通セッティング) .settings( buildInfoPackage := “パッケージ名” buildOptions in docker := BuildOption(cache = false), imageNames in docker := Seq(s“${gcrRegion.value}/${moduleName.value}:${version.value}”), dockerfile in docker := { val appDir = stage.value val targetDir = “/opt/docker” new Dockerfile { from(java8イメージ) expose(9000) copy(appDir, targetDir) entryPoint(s”$targetDir/bin/${executableName.value}”) } } build := docker.value )
  11. sbtでPlay2コンテナ作成 lazy val webapp = project.in(file(“webapp”)) .dependsOn(依存パッケージたち) .enablePlugin(PlayScala, JavaAppPackaging, sbtdocker.DockerPlugin)

    .settings(Scalaバージョンなどの共通セッティング) .settings( buildInfoPackage := “パッケージ名” buildOptions in docker := BuildOption(cache = false), imageNames in docker := Seq(s“${gcrRegion.value}/${moduleName.value}:${version.value}”), dockerfile in docker := { val appDir = stage.value val targetDir = “/opt/docker” new Dockerfile { from(java8イメージ) expose(9000) copy(appDir, targetDir) entryPoint(s”$targetDir/bin/${executableName.value}”) } } build := docker.value ) これらのプラグインを使って、 jar 生成からコンテナビルドまで一 気にやります。
  12. sbtでPlay2コンテナ作成 lazy val webapp = project.in(file(“webapp”)) .dependsOn(依存パッケージたち) .enablePlugin(PlayScala, JavaAppPackaging, sbtdocker.DockerPlugin)

    .settings(Scalaバージョンなどの共通セッティング) .settings( buildInfoPackage := “パッケージ名” buildOptions in docker := BuildOption(cache = false), imageNames in docker := Seq(s“${gcrRegion.value}/${moduleName.value}:${version.value}”), dockerfile in docker := { val appDir = stage.value val targetDir = “/opt/docker” new Dockerfile { from(java8イメージ) expose(9000) copy(appDir, targetDir) entryPoint(s”$targetDir/bin/${executableName.value}”) } } build := docker.value ) Dockerfileのようなものをここで 定義しています。 jarをコピってentrypointにしま す。
  13. sbtでPlay2コンテナ作成 lazy val webapp = project.in(file(“webapp”)) .dependsOn(依存パッケージたち) .enablePlugin(PlayScala, JavaAppPackaging, sbtdocker.DockerPlugin)

    .settings(Scalaバージョンなどの共通セッティング) .settings( buildInfoPackage := “パッケージ名” buildOptions in docker := BuildOption(cache = false), imageNames in docker := Seq(s“${gcrRegion.value}/${moduleName.value}:${version.value}”), dockerfile in docker := { val appDir = stage.value val targetDir = “/opt/docker” new Dockerfile { from(java8イメージ) expose(9000) copy(appDir, targetDir) entryPoint(s”$targetDir/bin/${executableName.value}”) } } build := docker.value ) このビルドファイルに対して sbt buildすればコンテナがローカル に作成されます。
  14. deployment.yamlの設定 apiVersion: apps/v1 kind: Deployment metadata: … spec: selector: …

    template: metadata: … spec: containers: - name: webapp-server image: 先ほど作ったイメージ ports: - containerPort: 9000 envFrom: - configMapRef: name: webapp-env-config // 後述 - secretRef name: cloudsql-db-credentials // 後述 - name: webapp-client image: JSが入ったnginxコンテナ ports: - containerPort: 80 ... - name: b.gcr.io/cloudsql-docker/gce-proxy:x.xx ...
  15. service.yamlの設定 apiVersion: apps/v1 kind: Service metadata: ... spec: type: NordPort

    ports: - port: 80 selector: ... deployment / serviceのyamlをいつも 通りkubectl applyすれば完了!
  16. Play2のロギング // logback.xml <configuration> <appender name=”STDOUT” class=”ch.qos.core.ConsoleAppender”> <target>System.out</target> -- filter略

    -- <encoder class=”ch.qos.logback.core.encoder.LayoutWrappingEncoder”> <layout class="ch.qos.logback.contrib.json.classic.JsonLayout"> <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter"> </jsonFormatter> <includeContextName>false</includeContextName> <appendLineSeparator>true</appendLineSeparator> </layout> <charset>UTF-8</charset> </encoder> </appender>
  17. Play2のロギング // logback.xml <configuration> <appender name=”STDOUT” class=”ch.qos.core.ConsoleAppender”> <target>System.out</target> -- filter略

    -- <encoder class=”ch.qos.logback.core.encoder.LayoutWrappingEncoder”> <layout class="ch.qos.logback.contrib.json.classic.JsonLayout"> <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter"> </jsonFormatter> <includeContextName>false</includeContextName> <appendLineSeparator>true</appendLineSeparator> </layout> <charset>UTF-8</charset> </encoder> </appender> GKEでは、標準出力、エラー出力 に垂れ流しておけば Stackdriverに 流してくれます。
  18. Play2のロギング // logback.xml <configuration> <appender name=”STDOUT” class=”ch.qos.core.ConsoleAppender”> <target>System.out</target> -- filter略

    -- <encoder class=”ch.qos.logback.core.encoder.LayoutWrappingEncoder”> <layout class="ch.qos.logback.contrib.json.classic.JsonLayout"> <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter"> </jsonFormatter> <includeContextName>false</includeContextName> <appendLineSeparator>true</appendLineSeparator> </layout> <charset>UTF-8</charset> </encoder> </appender> 構造化されているほうが Stackdriverで扱いやすいので、 JSONでログ出力します。
  19. Play2のロギング // 前ページから続き <appender name=”STDERR” class=”ch.qos.core.ConsoleAppender”> <target>System.err</target> -- STDOUTとほぼ同じなので省略 --

    </appender> <root> <appender-ref ref="STDOUT" /> <appender-ref ref="STDERR" /> </root> </configuration> 標準エラー出力を捕まえる設定も 同じようにあります。
  20. まとめ • Play2 + Kubernetesは簡単! • sbtでビルドからコンテナ作成まで完結できる • VMを直接意識しないアプリケーション管理&GAEやFaaSほど環境を制限されない ので、Kubernetesはちょうど良い

    • (GKEの場合)ロギングは標準に垂れ流すだけでStackdriver行きになるのでロー テーションとかディスクの枯渇とかの悩みがなくなる ◦ もちろん、Stackdriver Loggingのお金がかかります • 調べきれていないところ ◦ JMX周りの話