はじめに
Spring Cloud Kubernetes は Kubernetes ネイティブ API を使用した Spring Cloud の共通インターフェイスの実装で、次の 4 つの Spring Boot Starter がある。
spring-cloud-starter-kubernetes:
Kubernetes Service からサービス名を解決する Discovery Client の実装。
spring-cloud-starter-kubernetes-config:
Kubernetes ConfigMap と Secret から application properties を読み込む。
ConfigMap または Secret が変更されたときに application properties をリロードすることも可能。
spring-cloud-starter-kubernetes-ribbon:
Kubernetes Endpoint からサーバリストを取得するクライアントサイドロードバランサー(Ribbon)。
spring-cloud-starter-kubernetes-all:
上記すべてを含む Starter
今回は、Playing with Sping Boot on Kubernetes を参考に Kubernetes の世界観に触れつつ、Spring Cloud Kubernetes を使ってみる。
使用するのは上記 4 つの Starter のうち spring-cloud-starter-kubernetes-config のみ。
公式ドキュメントをみて、Kubernetes のアーキテクチャや登場するオブジェクトの名前はおさえておく。
https://kubernetes.io/docs/concepts/
環境
Mac OS X
1. ローカル環境に Minikube を構築する
https://kubernetes.io/docs/tasks/tools/install-minikube
仮想化が Mac OS で有効になっているかをチェック。
sysctl -a | grep -E --color 'machdep.cpu.features|VMX'
VMX が赤字で出力されれば VT-x 機能が有効になっているので OK。
kubectl のインストール
https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-macos
brew install kubernetes-cli
VirtualBox のインストール
brew cask install virtualbox
Minikube のインストール
brew cask install minikube
Minikube の起動と Cluster の作成
minikube start
ダッシュボードを見る
minikube dashboard
2. アプリケーションを作る
Spring Initializr でひな形を作成する
spring init \ --dependencies=data-jpa,data-rest,actuator,h2,devtools,lombok \ --groupId=sample \ --artifactId=spring-k8s-sample \ --boot-version=2.2.0.BUILD-SNAPSHOT \ --name=Sample \ --package-name=sample \ spring-k8s-sample
NOTE: spring init --list でサービスが一覧できる
IntelliJ IDEA でプロジェクトを開く
idea spring-k8s-sample/
NOTE: コマンドラインから IntelliJ IDEA を開くためには事前に Tools > Create Command-line Launcher を設定しておく。
Entity を作る
src/main/java/sample/Customer.java
@Entity @Data public class Customer { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String name; private String email; }
Repository を作る
src/main/java/sample/CustomerRepository.java
public interface CustomerRepository extends JpaRepository<Customer, UUID> { }
Spring Boot を起動する
./mvnw spring-boot:run
Customer を登録してみる
curl -X POST http://localhost:8080/customers \ -H 'Content-Type: application/json' \ -d '{ "name": "東方仗助", "email": "jojo@example.com" }'
Customer を一覧してみる
curl -X GET http://localhost:8080/customers
結果
{ "_embedded" : { "customers" : [ { "name" : "東方仗助", "email" : "jojo@example.com", "_links" : { "self" : { "href" : "http://localhost:8080/users/ed063906-e072-471f-b903-c15dd7ca72d6" }, "user" : { "href" : "http://localhost:8080/users/ed063906-e072-471f-b903-c15dd7ca72d6" } } } ] }, ...SKIP... }
3. PostgreSQL の構築
Minikube で作成した Kubernetes Cluster 上に PostgreSQL を構築してみる。
ConfigMap を作成する
kubectl create configmap postgres-config \ --from-literal=postgres.service.name=postgresql \ --from-literal=postgres.db.name=sample
確認する
kubectl get cm postgres-config -o json
Secret を作成する
kubectl create secret generic db-security \ --from-literal=db.user.name=sample \ --from-literal=db.user.password=password
確認する
kubectl get secret db-security -o json
PostgreSQL をデプロイする
PostgreSQL をデプロイするための Kubernetes リソースファイルを作成する。
src/k8s/postgres.yml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: postgresql namespace: default spec: replicas: 1 template: metadata: labels: app: postgresql spec: volumes: - name: data emptyDir: {} containers: - name: postgres image: postgres:9.6.5 env: - name: POSTGRES_USER valueFrom: secretKeyRef: name: db-security key: db.user.name - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: db-security key: db.user.password - name: POSTGRES_DB valueFrom: configMapKeyRef: name: postgres-config key: postgres.db.name ports: - containerPort: 5432 volumeMounts: - name: data mountPath: /var/lib/postgresql/ --- apiVersion: v1 kind: Service metadata: name: postgresql namespace: default spec: selector: app: postgresql ports: - port: 5432
NOTE: 先に作成した ConfigMap と Secret からデータベース名やユーザ名などを取得する。
NOTE: IntelliJ IDEA で Kubernetes のリソースファイルを変数するときには IntelliJ IDEA の Kubernetes プラグインを入れておくと便利。
実行する
kubectl create -f src/k8s/postgres.yml
作成された Deployment を確認する
kubectl get deployment postgresql -o json
作成された Service を確認する
kubectl get service postgresql -o json
4. アプリケーションを修正する
データベースを H2 から構築した PostgreSQL に接続するように修正する。
Spring Cloud Kubernetes を導入する
pom.xml
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.BUILD-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes-config</artifactId> </dependency>
PostgreSQL の JDBC ドライバーを導入する
pom.xml
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>
application.properties を修正する
spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=create spring.datasource.url=jdbc:postgresql://${${POSTGRES_SERVICE}.service.host}:${${POSTGRES_SERVICE}.service.port}/${POSTGRES_DB_NAME} spring.datasource.username=${POSTGRES_DB_USER} spring.datasource.password=${POSTGRES_DB_PASSWORD}
ややこしい設定だが、内側のプレースホルダーは ConfigMap から提供される環境変数によって解決され、外側のプレースホルダーは Kubernetes によって解決されることになる。
application.properties を ConfigMap に登録する
kubectl create configmap app-config \ --from-file=src/main/resources/application.properties
bootstrap.properties を作成する
src/main/resources/bootstrap.properties
spring.cloud.kubernetes.config.name=app-config
これでアプリケーションが Kubernetes にデプロイされた時に、app-config として ConfigMap に保存された application.properties が使われるようになる。
5. アプリケーションをデプロイ
fabric8-maven-plugin を導入する
fabric8-maven-plugin (以降 fmp)は次のことを Maven のビルドプロセスで実行する。
- Docker イメージの作成(Dockerfile も自動生成する)
- Kubernetes および OpenShift のリソースファイルの作成
- Kubernetes および OpenShift へのアプリケーションのデプロイ
pom.xml
<plugin> <groupId>io.fabric8</groupId> <artifactId>fabric8-maven-plugin</artifactId> <version>4.2.0</version> <configuration> <enricher> <config> <fmp-service> <type>LoadBalancer</type> </fmp-service> </config> </enricher> </configuration> <executions> <execution> <id>fmp</id> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> </plugin>
Service Account を作成する
Minikube v0.26.0 から RBAC がデフォルトで有効になっているため、アプリケーションから ConfigMap が取得できるように Service Account を作成する。
Service Account の Kubernetes リソースファイルを作成する
src/k8s/sa.yml
apiVersion: v1 kind: ServiceAccount metadata: name: config-reader namespace: default
Role の Kubernetes リソースファイルを作成する
src/k8s/role.yml
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods","configmaps"] verbs: ["get", "watch", "list"]
Role Binding の Kubernetes リソースファイルを作成する
src/k8s/rb.yml
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-reader namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: pod-reader subjects: - kind: ServiceAccount name: config-reader namespace: default
実行する
kubectl create -f src/k8s/sa.yml kubectl create -f src/k8s/role.yml kubectl create -f src/k8s/rb.yml
アプリケーションのリソースファイルを作成する
ConfigMap からデータベースの接続情報を取得して環境変数にセットする。
src/main/fabric8/app.yml
apiVersion: apps/v1 kind: Deployment metadata: name: ${project.artifactId} namespace: default spec: template: spec: containers: - name: ${project.artifactId} env: - name: POSTGRES_SERVICE valueFrom: configMapKeyRef: name: postgres-config key: postgres.service.name - name: POSTGRES_DB_NAME valueFrom: configMapKeyRef: name: postgres-config key: postgres.db.name - name: POSTGRES_DB_USER valueFrom: secretKeyRef: name: db-security key: db.user.name - name: POSTGRES_DB_PASSWORD valueFrom: secretKeyRef: name: db-security key: db.user.password serviceAccountName: config-reader
ビルドする
ビルドした Docker イメージを Minikube から使用できるようにする。
eval $(minikube docker-env)
Maven コマンドの実行
./mvnw clean install
fmp が Maven ビルド時に Dockerfile と Kubernetes のリソースファイルの作成を行う。
target/ ├── classes │ ├── META-INF │ │ └── fabric8 │ │ ├── kubernetes │ │ │ ├── spring-k8s-sample-deployment.yml │ │ │ └── spring-k8s-sample-service.yml │ │ ├── kubernetes.yml ...SKIP... ├── docker │ └── sample │ └── spring-k8s-sample │ └── latest │ ├── build │ │ ├── Dockerfile
NOTE: fmp は Spring Actuator を検出して LivenessProbe と ReadinessProbe を自動設定する。
デプロイする
./mvnw clean install fabric8:apply -DskipTests=true
エンドポイントを確認する
minikube service spring-k8s-sample --url
Customer を登録してみる
curl -X POST http://192.168.99.100:30223/customers \ -H 'Content-Type: application/json' \ -d '{ "name": "東方仗助", "email": "jojo@example.com" }'
Customer を一覧してみる
curl -X GET http://192.168.99.100:30223/customers
データベースの中身を確認してみる
kubectl exec -it postgresql-5dd8d89d89-p7pdl /bin/bash psql -Usample sample select * from customer; id | email | name --------------------------------------+------------------+---------- 9a34ef06-1027-45f7-88a8-2c09d957a467 | jojo@example.com | 東方仗助 (1 row) \q exit
おわり★