逮捕で学ぶ認証認可
最近Twitterで認証認可を逮捕で例える話をしていて、結構しっくり来たので逮捕で例えながらざっくり認証認可について書いてみようと思って飽きたところまでおいておきます。
定義
認証=囚人が誰であるかを特定すること(囚人番号009はおれきゅーみたいなかんじ
認可=面会許可
面会フロー
面会をするためには、その囚人に面会できるかの確認をする必要がある。
ここでは模範囚のみ面会ができるとして、面会したい囚人が模範囚であれば面会ができる。これが認可にあたる。ただ、大体の場合は認証と認可はセットになっていることが多い。なぜならその人が模範囚であるかを確認するためには「面会したい囚人が誰であるか」を知る必要があるからだ。
とはいえ、模範囚が入ってるエリアとそうじゃないエリアが分かれていれば認証をしなくても面会はできそう。
現実にはそんなフローはダメそうだけどw記録残さないといけないだろうし。
このままoauthとかの説明書こうとしたけどあきた。
気が向いたら書く。
SpringCloudで遊ぶ 3日目
SpringBootAdminを入れる
SpringBootAdminを入れてみる。Eureka経由でサービスを見つけてくれるようになる。
project("admin") { dependencies { implementation 'de.codecentric:spring-boot-admin-starter-server' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' } }
@Configuration @EnableAutoConfiguration @EnableAdminServer public class SpringBootAdminApplication { public static void main(String[] args) { SpringApplication.run(SpringBootAdminApplication.class, args); } }
eureka: instance: leaseRenewalIntervalInSeconds: 10 health-check-url-path: /actuator/health metadata-map: startup: ${random.int} #needed to trigger info and endpoint update after restart prefer-ip-address: true client: registryFetchIntervalSeconds: 5 serviceUrl: defaultZone: ${EUREKA_URI:http://localhost:8761/eureka} management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS spring: application: name: admin
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.5 ports: - 8080:8080 deploy: replicas: 2 environment: EUREKA_URI: http://eureka:8761/eureka eureka: image: net.orekyuu/eureka:0.0.5 ports: - 8761:8761 deploy: replicas: 1 admin: image: net.orekyuu/admin:0.0.5 ports: - 18080:8080 environment: EUREKA_URI: http://eureka:8761/eureka
デプロイ…! よし!動いてる!
API Gatewayを作ってみる
API Gatewayでhello-appを叩けるようにしてみる
project(':api-gateway') { dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-gateway' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' // actuatorはsubprojectsのdependenciesに移動した。どうせ全部のプロジェクトで必要だし } }
@SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes() .route("hello_app_route", r -> r .path("/hello") .uri("http://hello-app:8080/hello")) .build(); } }
ガッっとアプリケーションコードを書く。
RouteLocatorBuilderでメソッドチェーンしながら組み立てていくっぽい。/helloにアクセスが来たらkubernetes内のhello-appiの/helloにプロキシするようにした。
hello-appの名前解決はeurekaでやってくれる。便利~!
spring: application: name: api-gateway eureka: instance: leaseRenewalIntervalInSeconds: 10 health-check-url-path: /actuator/health metadata-map: startup: ${random.int} #needed to trigger info and endpoint update after restart prefer-ip-address: true client: registryFetchIntervalSeconds: 5 serviceUrl: defaultZone: ${EUREKA_URI:http://localhost:8761/eureka} management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS
application.ymlはコピペ。spring.application.nameだけ変えてる。似たような設定が散らばるのやだなー。
一応ルーティングの設定はapplication.ymlでも書けるらしいけど、個人的にはJavaConfigのほうがコンパイルできるし補完も効くのですき。
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.5 deploy: replicas: 2 environment: EUREKA_URI: http://eureka:8761/eureka eureka: image: net.orekyuu/eureka:0.0.5 ports: - 8761:8761 deploy: replicas: 1 admin: image: net.orekyuu/admin:0.0.5 ports: - 18080:8080 environment: EUREKA_URI: http://eureka:8761/eureka api-gateway: image: net.orekyuu/api-gateway:0.0.5 environment: EUREKA_URI: http://eureka:8761/eureka ports: - 8080:8080
最後にapi-gatewayの設定を追加して8080で受けるようにする。もともとhello-appが使っていたけど、直接叩くことはなくなったのでportsは削除。
全部api-gatewayを通してリクエスト
デプロイして8080を確認するとhello-appのときと変わらない画面が見える。
結局API Gatewayが使われているかわからん!
Adminを見てみる。
ちゃんとリクエストきてる!やったー!
kubernetesに入門してみる 2日目
ImagePullBackOffで起動しない解決編
バージョンをlatestにしていると常にdocker registryにpullしてしまうみたい。
ということでjibでイメージを作るときに適当にタグを付けてあげる
jib { to { image = "net.orekyuu/" + project.name tags = ["0.0.1"] // とりあえず固定値で渡してみる } from { image = "openjdk:12" } }
docker-compose.yml側にも変更
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.1 ports: - 8080:8080
デプロイしてみる!
D:\repos\spring-illust-service>docker stack deploy --orchestrator=kubernetes -c docker-compose.yml hello Waiting for the stack to be stable and running... hello-app: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed] Stack hello is stable and running D:\repos\spring-illust-service>kubectl get all NAME READY STATUS RESTARTS AGE pod/hello-app-6f985844fb-n8vrb 1/1 Running 0 16s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-app ClusterIP None <none> 55555/TCP 16s service/hello-app-published LoadBalancer 10.97.45.121 localhost 8080:31557/TCP 15s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-app 1/1 1 1 16s NAME DESIRED CURRENT READY AGE replicaset.apps/hello-app-6f985844fb 1 1 1 16s
なんだか動いてそう…!
localhost:8080で動いてるはずなのでアクセス
やったー!
replicateしてみる
hello appを増やしてみる
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.1 ports: - 8080:8080 deploy: replicas: 2
もっかいデプロイ!
D:\repos\spring-illust-service>docker stack deploy --orchestrator=kubernetes -c docker-compose.yml hello Waiting for the stack to be stable and running... hello-app: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed] Stack hello is stable and running D:\repos\spring-illust-service>docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 958fbfb96101 f61f158e7339 "java -cp /app/resou…" 3 seconds ago Up 1 second k8s_hello-app_hello-app-6f985844fb-8qrlz_default_8ad9e77c-d484-11e9-99f8-0 0155da07b15_0 e9165ba15192 f61f158e7339 "java -cp /app/resou…" 3 minutes ago Up 3 minutes k8s_hello-app_hello-app-6f985844fb-n8vrb_default_2ad820d9-d483-11e9-99f8-0 0155da07b15_1
ちゃんと2台になってる。面白い~!
Eurekaを入れる
Spring Cloudを触ってみたいモチベーションがあったのでまずはEurekaから入れてみる
新しいプロジェクトを作ってピャッっと書く。アプリケーションのコードはこんな感じ
project(":eureka") { dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' // ↓JDK9以降だと自分でJAXB周り入れておかないとJigsawの影響とかで起動できない… implementation 'javax.xml.bind:jaxb-api:+' implementation 'com.sun.xml.bind:jaxb-impl:+' implementation 'org.glassfish.jaxb:jaxb-runtime:+' implementation 'javax.activation:activation:+' } }
@SpringBootApplication @EnableEurekaServer public class DiscoveryApplication { public static void main(String[] args) { SpringApplication.run(DiscoveryApplication.class, args); } }
server: port: 8761 eureka: client: register-with-eureka: false fetch-registry: false
自分自身を登録しないようにregister-with-eurekaとかはfalseにしておくと良いらしい。って書いてあった
jibでビルドしてdocker-compose.ymlに追記してあげる
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.1 ports: - 8080:8080 deploy: replicas: 2 eureka: image: net.orekyuu/eureka:0.0.1 ports: - 8761:8761 deploy: replicas: 1
localhost:8761にアクセスするとダッシュボードが見れる
ちょっと寄り道してJAXB周りでエラー出た話
一発目はJAXB周りに気付かず起動しないなー?になっていた。
kubectl get allを打つとコンテナの状態が見れるので叩いてみる。
D:\repos\spring-illust-service>kubectl get all NAME READY STATUS RESTARTS AGE pod/eureka-586c7cbc48-mrb2h 0/1 Error 3 93s pod/hello-app-6f985844fb-4stpb 1/1 Running 0 93s pod/hello-app-6f985844fb-wl4zn 1/1 Running 0 93s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/eureka ClusterIP None <none> 55555/TCP 93s service/eureka-published LoadBalancer 10.109.74.59 localhost 8761:30876/TCP 92s service/hello-app ClusterIP None <none> 55555/TCP 92s service/hello-app-published LoadBalancer 10.96.5.72 localhost 8080:30280/TCP 93s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/eureka 0/1 1 0 93s deployment.apps/hello-app 2/2 2 2 93s NAME DESIRED CURRENT READY AGE replicaset.apps/eureka-586c7cbc48 1 1 0 93s replicaset.apps/hello-app-6f985844fb 2 2 2 93s
eurekaがエラーで再起動くりかえしてるぽい。原因は外からじゃわからないのでログをみたい。
kubectl logs [pod名]でログが取れるので打ってみる
D:\repos\spring-illust-service>kubectl logs pod/eureka-586c7cbc48-mrb2h 2019-09-11 11:52:44.502 INFO 1 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.auto configure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$8ccca102] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.8.RELEASE) 2019-09-11 11:52:44.703 INFO 1 --- [ main] net.orekyuu.eureka.DiscoveryApplication : No active profile set, falling back to default profiles: default 2019-09-11 11:52:45.492 WARN 1 --- [ main] o.s.boot.actuate.endpoint.EndpointId : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format. 2019-09-11 11:52:45.840 INFO 1 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=10faa10b-835d-3f55-bd87-0a6398f3b9c7 ... java.lang.NoClassDefFoundError: com/sun/istack/FinalArrayList at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:249) ~[jaxb-impl-2.4.0-b180830.0438.jar:2.4.0-b180830.0438] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na] at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:208) ~[jaxb-api-2.4.0-b180830.0359.jar:2.3.0] at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:166) ~[jaxb-api-2.4.0-b180830.0359.jar:2.3.0]
みたいな感じでjaxb周りでコケてることがわかった。
hello-appにeureka-clientを入れる
eureka-clientを入れてeurekaに登録するようにする
project(":hello") { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' // ↓新しく追加した implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' } }
spring: application: name: hello-app eureka: client: service-url: defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
登録する先は環境変数で渡せるようにしておく。イメージ作り直すのいやだしね。
docker-composeを書いてあげる
version: '3.7' services: hello-app: image: net.orekyuu/hello:0.0.3 ports: - 8080:8080 deploy: replicas: 2 environment: EUREKA_URI: http://10.104.224.80:8761/eureka eureka: image: net.orekyuu/eureka:0.0.4 ports:[f:id:orekyuu:20190911213036p:plain] - 8761:8761 deploy: replicas: 1
ipアドレスはkubectl get allを叩いてservice/eureka-publishedのIPを入れた。いや、良くないのはわかっているけどとりあえず動かして楽しくなりたかった…!
あとで正しい方法は調べるとしてこれでdeployしてみる。
ちゃんとインスタンスが2つ登録されていることが確認できたので満足!
明日はAPI Gatewayとか試してみよ~
kubernetesに入門してみる
spring cloudで遊んでみよーとおもったので、まずはkubernetesから触ってみることにした。
触ってきたメモ的な感じで残してく。
環境
Kubernetesを有効化
DockerのSettingsを開いてKubernetesからぽちっと有効化してあげる
Applyするとインストールが始まるので終わるまでしばらく待つ
終わったらとりあえずkubectlコマンドが使えるはずなので kubectl version
あたりを叩いて確認するとよき
動かしてみる
とりあえず簡単なSpring Bootアプリケーションをデプロイしてみる。
こんなかんじのアプリケーションを作って
@SpringBootApplication @Controller public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); } @GetMapping @ResponseBody public String hello() { return "hello " + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME); } }
Jibを使ってイメージを作る
デフォルトのベースイメージだとJDK12サポートしてないからベースイメージにはopenjdk:12を使うよ
あとたくさんアプリ作りそうなのでマルチプロジェクト構成にしておく
plugins { id 'java' id 'org.springframework.boot' version '2.1.8.RELEASE' apply false id 'io.spring.dependency-management' version '1.0.8.RELEASE' apply false id 'com.google.cloud.tools.jib' version '1.5.1' apply false } repositories { jcenter() } subprojects { apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' apply plugin: 'com.google.cloud.tools.jib' sourceCompatibility = 12 def defaultEncoding = 'UTF-8' [AbstractCompile, Javadoc].each { tasks.withType(it).each { it.options.encoding = defaultEncoding } } repositories { jcenter() } jib { to { image = "net.orekyuu/" + project.name } from { image = "openjdk:12" // JDK12を使いたい場合は明示的にベースイメージ設定しておこう } } }
gradlew :hello:jibDockerBuild
を叩いてイメージを作る。Jib便利~。
D:\repos\spring-illust-service>gradlew :hello:jibDockerBuild Containerizing application to Docker daemon as net.orekyuu/hello... The base image requires auth. Trying again for openjdk:12... Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, net.orekyuu.hello.HelloApplication] Built image to Docker daemon as net.orekyuu/hello Executing tasks: [==============================] 100.0% complete BUILD SUCCESSFUL in 5m 52s 2 actionable tasks: 1 executed, 1 up-to-date
ビルドできたっぽいのでコンテナを動かしてみて動くことを確認
docker run -p 8080:8080 net.orekyuu/hello
ブラウザでlocalhost:8080を見るとちゃんとメッセージが見れたのでヨシ!
docker-compose.ymlでデプロイする
compose-on-kubernetesとやらでkubernetesにdocker-compose.ymlの定義に従ってコンテナをデプロイできるっぽいので使ってみる。とりあえず動かしたいしね。
とりあえずhelloアプリだけ起動するようにdocker-compose.ymlを用意。
version: '3.7' services: hello-app: image: net.orekyuu/hello:latest ports: - 8080:8080
つぎにデプロイはdocker stack deployでできるらしい。docker-swarmと一緒だけどorchestratorオプションでkubernetesを指定できるらしい。なるほど。
stack名はhelloでデプロイ
D:\repos\spring-illust-service>docker stack deploy --orchestrator=kubernetes -c docker-compose.yml hello Waiting for the stack to be stable and running... hello-app: Pending [pod status: 0/1 ready, 1/1 pending, 0/1 failed]
起動待ちがやけに長い…?
D:\repos\spring-illust-service>kubectl get all NAME READY STATUS RESTARTS AGE pod/hello-app-557fc5fb78-b28md 0/1 ImagePullBackOff 0 5m33s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-app ClusterIP None <none> 55555/TCP 5m33s service/hello-app-published LoadBalancer 10.99.53.170 localhost 8080:32717/TCP 5m32s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 71m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-app 0/1 1 0 5m33s NAME DESIRED CURRENT READY AGE replicaset.apps/hello-app-557fc5fb78 1 1 0 5m33s
pod/hello-app-...のSTATUSがImagePullBackOffのままずっと動いてないっぽい。
おそらくローカルのイメージが見えてなくてpullをずっと待ってるのかな。明日は適当なレジストリ立てて試してみよ~