Because I am hard you will not like me.
But the more you hate me the more you will learn.
I am hard but I am fair.
There is no racial bigotry here.
I do not look down on n*ggers, kikes, wops or greasers.
Here you are all equally worthless.
And my orders are to weed out all non-hackers who do not pack the gear to serve in my beloved Corps.
Do you maggots understand that?
貴様らは厳しい俺を嫌う
だが憎めば、それだけ学ぶ
俺は厳しいが公平だ
人種差別は許さん
黒豚、ユダ豚、イタ豚を、俺は見下さん
すべて平等に価値がない!
俺の使命は役立たずを刈り取ることだ 愛する海兵隊の害虫を!
分かったか、ウジ虫ども!
⇧ ご存知、「フルメタルジャケット(監督:スタンリー・キューブリック)」のハートマン軍曹のセリフですね。
「Boot Camp」の恐ろしいイメージに、トラウマになりそうですかね。
ブートキャンプ(アメリカ英語: Boot Camp)とは、アメリカ合衆国で「新兵訓練施設」を意味する口語表現である。転じてアメリカ軍の新兵に対して行われる教育・訓練プログラム(新兵訓練)自体を指すようになり、さらには軍隊式トレーニング全般を意味するようになった。
ブート(Boot)とは俗語で新兵を意味する。
⇧ Wikipediaの写真も、むっちゃ怖い...
そんなこんなで、今回は、Javaのフレームワークである「Spring Framework」の機能を利用しているという「Spring Boot」について。
まぁ、「Spring Boot」は、
ブート(英: boot)またはブートストラップ(英: bootstrap)は、コンピュータシステムの電源投入時、あるいはシステムのリセット後、モニタやOSなどなんらかの基本的なシステムソフトウェアを主記憶に展開し、ユーザプログラムを実行できるようにするまでの処理の流れをいう。ブートローダ(英: boot loader)は、以上のプロセスで使われるローダ、すなわち不揮発性の補助記憶にある目的のプログラムを読み出し、揮発性の主記憶に書き込むプログラムのことである。
⇧ こっちのイメージでしょうけど。
そんでは、レッツトライ~。
Spring Bootって?
ネットとかの情報だと、「Spring MVC vs Spring Boot」って比較が多いから、てっきり、Spring Frameworkの一部かと思ってたんだけど、
⇧ プロジェクトが分かれてるところを見ると、まったく別物って考えないといけないってことですかね。
っていうか、「Spring Framework」「Spring MVC」「Spring Boot」の関係性が分かりにくいんだが...
『はじめての Spring Boot』の著者である槙俊明さんのスライドによりますと、
⇧ 「Spring Boot」は、あくまで、「Spring Framework」の外側にいて、「Spring MVC」は「Spring Framework」の機能の「Web」の一部ってことなので、「Spring Framework」に含まれるっていう扱いになりそうですかね。
情報が旧いんですが、
⇧ https://spring.io/ にあるドキュメントでも、「Spring MVC」は「Spring Framework」の機能の一部である「Web」に属するってことでしょうかね。
「Spring Boot」は、
⇧ っていうか、この説明で分かれっていうのは、疑問なんだが...
槙さんのスライドの画像から推測するに、「Spring Boot」は、「Spring Framework」にある様々な機能の内、使いたいものを自分で選んで、プロジェクトを作成できるっていうことではないかと。
Spring Boot は、Tomcatが内蔵されてるらしい
Eclipseなんかで、Java の標準APIだけ使っていると、「Java アプリケーション」として実行しかできないんですが、今時のアプリケーションといえばWebアプリケーションが主流ではないかと思われるわけです。
Webとしての機能が欲しい場合、Javaの場合だと、だいたいServlet APIを導入して実現することが多いかと。
Servlet APIは、ApacheなどのWebサーバでサーブレットを動作させるために必要なモジュールです。 Servlet APIは、Javaエクステンションで、javaxの標準パッケージとして提供されます。
⇧ 上記サイト様が詳しいです。
「Tomcat」+「サーブレット」== 「サーブレットコンテナ(サーブレットエンジン)」があれば、実は、Webサーバは無くても大丈夫だったりします。なぜなら、AppサーバであるTomcatは簡易的なWebサーバの機能も持ち合わせているため。
ですが、Appサーバだけに処理を集中させると、パフォーマンスが悪くなるため、通常は、「Webサーバ」、「Appサーバ」の両方を使っていく感じになるかと。
Javaだと、
があれば、Web通信を実現できるかと。
普通のJavaのWebアプリケーションであれば、「Appサーバ」に、「JAR」や「WAR」などの形式にまとめたファイルを配置することでデプロイされるかと思われますが。
だいぶ、脱線しましたが、Spring Boot のややこしいところは、Tomcat を内蔵しているということかと。そのため、デプロイする手段として「Appサーバ」に配置って方法は適さないかと。(「Appサーバ」込みのアプリケーションを「Appサーバ」に載せるってことになってしまうから)
サービスとして起動するのが主流らしいと思ったけど...
なんか、Spring Boot をLinuxで動かす場合、サービスとして起動するのが一般的らしい。と、
⇧ 上記サイト様の参考サイトの方はGradleでSpring Boot プロジェクトを作成してる感じですかね。
ちょっと、
⇧ トリッキーなことをしている人もおられるけど。
最近だと(最近でもないのかもしれないですが)、
Spring Bootはバージョン1.3.0以降、Executable JarとしてJarファイルに固めるだけでなく、実行スクリプトがJarファイル内に埋め込まれたFully Executable Jarが作成できる。
サーバに常駐させるため、普通のJarファイルであれば起動スクリプトを書く必要があるが、Fully Executable Jarであれば不要となる。
通常のJarファイルの起動スクリプトが公式に提供されていない状況だが、Fully Executable Jarの登場によって、実質的に起動スクリプトが公式に提供されたことになる。
これによって、簡単にserviceコマンドでアプリをdeamon起動することができるようになった。
⇧ 「Fully Executable Jar」という形のJARファイルを作れば、サービス起動のためのスクリプトも用意してくれるらしい。
だが、しかし!
Spring BootのTomcatのバージョンを調べてみるの冒頭でも述べた通り、Spring BootではTomcatが組み込まれており、非常に手軽に開発ができます。
ただ、開発中はSTS + Spring Bootで組み込みTomcatを使って、本番環境や結合テスト環境には別でTomcat(とかJettyとかJBossとか)を立てて、そっちで稼働させたい、なんてケースもあるかと思います。
現に自分の今の現場はそんな構成になっています。
⇧ 上記サイト様が仰るように、現場では、「Appサーバ」にデプロイするケースが多いんですかね。
いまいち、Spring Boot の方向性が分からんよね...
CentOS7ベースの仮想マシンに、AdoptOpenJDK 11 を導入で
とりあえず、デプロイ先として、Linux環境を用意するため、仮想マシンを作成して、CentOS7をインストールして、AdoptOpenJDK 11 をインストールします。
⇧
Docker ToolBoxを利用して、CentOS7のDockerコンテナを用意し、そのコンテナにAdoptOpenJDK 11 をインストールするということで。
2019年11月5日(火)追記:↓ ここから
OpenJDKは、特にこだわりが無ければ、CentOS7なら、yum でインストールしたほうが早いです。
2019年11月5日(火)追記:↑ ここまで
ここからは、Dockerを使える環境が整っているという前提で話を進めていきます。
まずは、docker-machine createで作成した仮想マシンの一覧を表示。
docker-machine ls
そしたらば、新たに仮想マシンを作成します。
docker-machine create --driver [仮想化ソリューション] [仮想マシン名]
⇧ 指示通りに、コマンドを実行します。
⇧ 作成した仮想マシンが起動してます。
そんでは、Docker Hubから、CentOS7のコンテナimage を取得します。(Docker Hubのアカウント登録をしてない場合は、登録しちゃいましょう)
そしたらば、コンテナを作成・起動していきますが、ホスト側とゲスト側のディレクトリをマウントしていこうと思うので、「C:\Users\[ユーザ名]」の配下に適当にディレクトリを作成で。
注意する点としましては、
すでに作ったコンテナでホスト側のディレクトリをマウントする方法はあるでしょうか?
できません。
他の run のオプションも含めて、コンテナ化した後は変更できません。
一度、コンテナの内容を docker commit で、イメージに書き戻して run しなおすことで run のオプションを変更できます。
⇧ とありますように、docker run の段階で、いろいろ決めておかないといけないってことですかね。
というのも、docker run コマンドは、
docker run
コマンドは、まず指定されたイメージ上に書き込み可能なコンテナ・レイヤを create
(作成)します。それから、指定されたコマンドを使って start
(開始)します。
この docker run
は、 API の /containers/create
の後で /containers/(id)/start
を実行するのと同じです。以前に使っていたコンテナは docker start
で再起動できます。
全てのコンテナを表示するには docker ps -a
を使います。
docker run
コマンドは、 コンテナの内容を確定するために、 docker commit
コマンドと連携して使えます。
⇧ 「create」+「start」ってことをやっているので、「create」の段階でコンテナの構成が決まってしまうと思われるので、後から、マウントしたり、ポートフォワーディングしたりってことは変更できないってことですかね。
そんじゃ、コンテナ作成・起動で。
docker run -it --name [コンテナ名] -d -v //c/Users/[ユーザ名]/[マウントしたいディレクトリまでのパス]:/[ゲスト側のディレクトリ] [REPOSITORY]:[TAG]
コンテナにログインして、マウントしたディレクトリにファイルを作成してみます。
ホスト側のディレクトリからゲストOSのマウントしたディレクトリが見えましたんで、ホスト側とゲスト側のディレクトリがマウントできてます。
2019年12月5日(木)追記 ↓ ここから
2019年11月5日の追記で言及したように、特にどこのOpen JDKにするかにこだわりが無ければ、今回で言えば、CentOS7のパッケージ管理ツールのyumでインストールが早いで、yum install で、Open JDKをインストールする場合は、下記の"AdoptOpenJDKをインストール"の手順は不要です。
2019年12月5日(木)追記 ↑ ここまで
そんでは、AdoptOpenJDKをインストールしていきたいと思います。
まずは、git をインストールで。
そしたらば、git cloneします。
依存ライブラリが必要らしいので、インストールしておきます。
yum -y install bzip2 yum -y install autoconf yum -y install unzip yum -y install zip yum -y install java-11-openjdk-devel yum -y groupinstall "Development Tools" yum -y install libXtst-devel libXt-devel libXrender-devel libXi-devel yum -y install cups-devel yum -y install fontconfig-devel yum -y install alsa-lib-devel
で、ビルドしようとしたら、
エラー。which コマンド入ってないらしい。
インストールで。
改めて、
で、エラー。
依存ライブラリ足りなかったらしい...
インストールで。
もう一回やり直しで。
で、むっちゃ時間かかる...ここから異様に進まない
あ...少し進んだ、でも、こっからまためちゃ時間かかるし...
めっちゃ時間かかって、何かエラーっぽいメッセージが
展開します。
インストールできたらしい。
時間の都合上、翌日に持ち越しということで、仮想マシンを停止。
ホスト側でSpring Bootのプロジェクトを作成
翌日。仮想マシンを起動で。
指示通り、コマンドを実行していきましょう。
コンテナを起動しておきましょう。
docker start [コンテナ名]
コンテナが起動しました。ゲスト側は、一旦、ここまで。
そんじゃ、ホスト側でSpring Boot プロジェクトを作成で。
Eclipse(バージョンは2019-09使ってます)を起動して、 「ファイル(F)」>「新規(N)」>「その他(O)...」で。
「Spring Boot」>「Spring スターター・プロジェクト」を選択で。「次へ(N)>」。
「Java バージョン:」を「11」にしときます。あとは、「名前」だけ変えてみました。「次へ(N) >」で。
依存ライブラリは、一旦、「Spring Web」だけ追加しました。後から追加とかもできるはずなので。「完了(F)」で。
しばし時間がかかりますが、「Spring Boot」なプロジェクトできました。
もし、pom.xml でエラーが出た場合、
⇧ 自分は上記サイト様の方法で解決できました。(会社のパソコンで、Windows 10 Proで、Hyper-vを有効にしてた時に、ネットワークが不安定になって「C:\Users\[ユーザ名]\.m2\repository」に上手く依存ライブラリがダウンロードできてなかったのかと思われる時に、上記サイト様の方法で解消できました。)
そんじゃ、ブラウザで「Hello Spring World」って表示できるようにしていきましょう。
ちなみに、依存関係で「Spring Web」を選択したので、おそらく、「Spring Framework」の「Spring MVC」が使えるってことだと思われるので、
⇧ 上記のような、仕組みが利用できるかと。
なので、今回は、「Hello Spring World」って表示するだけなので、
- Controller用のJavaファイル
- View用のhtmlファイル
の2つを用意してあげればOKということになるかと。
ビジネスロジックは使わないので、「Business Service Facade」でデータベースなんかとやり取りするってことも、今回は行いません。
ちなみに、プロジェクトを作成した段階で存在する、「[プロジェクト名]Application.java」にmainメソッドが存在するので、プロジェクトのエントリポイントになるかと。
Class SpringApplication
- java.lang.Object
-
- org.springframework.boot.SpringApplication
Class that can be used to bootstrap and launch a Spring application from a Java main method. By default class will perform the following steps to bootstrap your application:
⇧ Spring Bootも、mainメソッドを起点としているんですかね。
そんでは、まずは、Javaのクラスファイルを作成していきます。
「パッケージ(K):」「名前(M):」を適当に決めて、「完了(F)」で。
そしたらば、「HelloController.java」のソースコードを編集で。
package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @RequestMapping(value="/hello") private String hello() { return "/index.html"; } }
そしたらば、今度は、htmlファイルを作成します。「src/main/resource」配下の「static」ディレクトリに、ファイルを作成します。
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Spring Boot デビュー</title> </head> <body> <p>Hello Spring Boot</p> </body> </html>
そんでは、「Spring Boot」なプロジェクトを起動してみます。
コンソールに、
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.0.RELEASE) 2019-11-04 12:36:54.477 INFO 28704 --- [ main] com.example.demo.HelloSpringApplication : Starting HelloSpringApplication on Toshinobu-PC with PID 28704 (C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target\classes started by Toshinobu in C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring) 2019-11-04 12:36:54.484 INFO 28704 --- [ main] com.example.demo.HelloSpringApplication : No active profile set, falling back to default profiles: default 2019-11-04 12:36:55.302 INFO 28704 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-11-04 12:36:55.313 INFO 28704 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-11-04 12:36:55.313 INFO 28704 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27] 2019-11-04 12:36:55.398 INFO 28704 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-11-04 12:36:55.398 INFO 28704 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 870 ms 2019-11-04 12:36:55.545 INFO 28704 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-11-04 12:36:55.592 INFO 28704 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html] 2019-11-04 12:36:55.692 INFO 28704 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-11-04 12:36:55.696 INFO 28704 --- [ main] com.example.demo.HelloSpringApplication : Started HelloSpringApplication in 1.56 seconds (JVM running for 3.25)
ってなったら、起動できているので、ブラウザから、「http://localhost:8080/hello」にアクセスすると、
⇧ index.htmlが表示できています。
停止するには、コンソールの横にある をクリックすればOK。
停止すると、ブラウザからのアクセスもできなくなります。
Spring Boot なプロジェクトをWARファイルにする
Linux環境へのSpring Bootなプロジェクトのデプロイ方法としては、
- JARファイルをサービスとして起動させる
- AppサーバにWARファイルを配置する
の2つが考えられそうですが(他にもいろいろ方法はあると思われますが、ネットで調べた感じでは、上記の2つの方法が多かったので)、今回は、「2. AppサーバにWARファイルを配置する」方法でデプロイしたいと思います。
⇧ 上記サイト様を参考にさせていただきました。
Linux環境に、「Appサーバ」を用意して、「Appサーバ」に「Spring Boot なプロジェクト」をデプロイするために、「WAR」ファイルを用意します。
ホスト側でやることとしては、
- pom.xmlの修正
- packagingをwarにすること
- spring-boot-starter-tomcatのscopeをprovidedにすること
- エントリポイントのクラスファイルを用意
- SpringBootServletInitializerクラスを継承すること
- configureメソッドをoverrideすること
の2つらしいです。
では、まず、「pom.xml」の修正。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>HelloSpring</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>HelloSpring</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
続きまして、エントリポイントクラスを作成。
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication public class App extends SpringBootServletInitializer { public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ SpringApplication.run(App.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(App.class); } }
んで、実行しようとすると、
mainメソッドが2つあることになっちゃうんで、どっちのクラスで実行するかを選ぶことになるので、新しく作った「App.java」を選択して「OK」で。
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.0.RELEASE) 2019-11-04 15:20:34.567 INFO 31304 --- [ main] com.example.demo.App : Starting App on Toshinobu-PC with PID 31304 (C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target\classes started by Toshinobu in C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring) 2019-11-04 15:20:34.572 INFO 31304 --- [ main] com.example.demo.App : No active profile set, falling back to default profiles: default 2019-11-04 15:20:35.239 INFO 31304 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-11-04 15:20:35.247 INFO 31304 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-11-04 15:20:35.248 INFO 31304 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27] 2019-11-04 15:20:35.323 INFO 31304 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-11-04 15:20:35.323 INFO 31304 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 715 ms 2019-11-04 15:20:35.455 INFO 31304 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-11-04 15:20:35.499 INFO 31304 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html] 2019-11-04 15:20:35.583 INFO 31304 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-11-04 15:20:35.587 INFO 31304 --- [ main] com.example.demo.App : Started App in 1.269 seconds (JVM running for 2.592)
App.javaのほうのmainメソッドの中のSpring Boot用の処理で、Spring Bootなプロジェクトが起動。
んで、ブラウザから「http://localhost:8080/hello」でアクセスすれば、
⇧ index.html が表示されました。
動作することが確認できたので、プロジェクトを停止します。
そんでは、WARファイルを作成で。
「ゴール(G):」に「package」と入力し、「実行(R)」で。
で、エラー。
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.315 s <<< FAILURE! - in com.example.demo.HelloSpringApplicationTests [ERROR] com.example.demo.HelloSpringApplicationTests Time elapsed: 0.313 s <<< ERROR! java.lang.IllegalStateException: Found multiple @SpringBootConfiguration annotated classes [Generic bean: class [com.example.demo.App]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target\classes\com\example\demo\App.class], Generic bean: class [com.example.demo.HelloSpringApplication]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target\classes\com\example\demo\HelloSpringApplication.class]] [INFO] [INFO] Results: [INFO] [ERROR] Errors: [ERROR] HelloSpringApplicationTests » IllegalState Found multiple @SpringBootConfigura... [INFO] [ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 13.960 s [INFO] Finished at: 2019-11-04T15:30:43+09:00 [INFO] ------------------------------------------------------------------------ [WARNING] The requested profile "pom.xml" could not be activated because it does not exist. [ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project HelloSpring: There are test failures. [ERROR] [ERROR] Please refer to C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target\surefire-reports for the individual test results. [ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream. [ERROR] -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
なんでも、
Avoid @SpringBootConfiguration conflicts
When @SpringBootTest is undefined (classes=... and nested @Configuration class is not found), an attempt is made to query @SpringBootConfiguration, which throws an exception if more than one is found:
Spring, Spring Boot and TestNG Test Guide - Using Spring Boot Testing Tools
⇧ デフォルトで作成されてた「/HelloSpring/src/test/java/com/example/demo/HelloSpringApplicationTests.java」が見つけられんっていってるらしい...
一応、解決方法としては、
The solution to this problem is to avoid automatically querying @SpringBootConfiguration:
-
Define @SpringBootTest(classes=...)
-
Provide nested@Configuration class
Spring, Spring Boot and TestNG Test Guide - Using Spring Boot Testing Tools
⇧ って、なってるけど、分かりにくいな...どっちか片方を実施すれば良いのか、それともどっちもやらなきゃいけないのか...
@SpringBootTestと一緒に使用するSpring Boot Mainクラスを指定する必要があります。
@SpringBootTest(classes = YourUiSpringBootApp.class)
⇧ 上記サイト様によりますと、 「1.Define @SpringBootTest(classes=...)」だけでイケそうかしら。
デフォルトのテストクラスを修正。
package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest(classes=HelloSpringApplication.class) class HelloSpringApplicationTests { @Test void contextLoads() { } }
んで、再度WARファイル作成で。
エラー。
[WARNING] The requested profile "pom.xml" could not be activated because it does not exist. [ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.2.0.RELEASE:repackage (repackage) on project HelloSpring: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.2.0.RELEASE:repackage failed: Unable to find a single main class from the following candidates [com.example.demo.App, com.example.demo.HelloSpringApplication] -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
複数の「@SpringBootApplication」アノテーションがあると起こる問題らしい。
ただ、マイクロサービスとかでは、結構、「@SpringBootApplication」アノテーションを複数にする要件が出てきそうな感じなんですかね。
複数あるままいきたい場合は、
⇧ 上記サイト様のように設定する必要があるらしい。
今回は、「HelloSpringApplication.java」側の「@SpringBootApplication」をコメントアウトしました、Spring よく分からんな...。
んで、再度WARを作成すると、できました。
「C:\Eclipse_2019-09\pleiades-2019-09-java-win-64bit-jre_20191007\pleiades\workspace\work_00\HelloSpring\target」にできてました。(Eclipseの「パッケージエクスプローラー」からだと確認できないけど...)
とりあえず、ゲスト側とマウントしていたホスト側のディレクトリに配置しときます。
仮想マシン側にTomcatをインストール
CentOS7のコンテナにTomcatをインストールしていきます。
⇧ 上記サイト様を参考にさせていただきました。
まずは、コンテナにログインし、Tomcatをダウンロード。
展開します。
そしたら、ディレクトリをリネームします。
Tomcatを起動するユーザを追加で。
Tomcatを起動する権限を付与。
Systemd 設定ファイルを作成します。
以下内容で保存。
で、サービス起動しようとするも、
エラー。
すっかり忘れてたけど、
Systemd is now included in both the centos:7 and centos:latest base containers, but it is not active by default. In order to use systemd, you will need to include text similar to the example Dockerfile below:
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
⇧ systemctl とか、システム系のコマンドを使えるようにしないといけなかったという...手遅れやん。
致し方ない、いま作業してるコンテナからDocker imageを作成して、上記のようにDockerfile でコンテナを作り直しますか。
コンテナからログアウトし、コンテナを停止します。
コンテナからDocker image を作成。
docker commit [コンテナ名] [REPOSITORY]:[TAG]
imageのサイズがやべぇっす...
そんじゃ、Dockerfileを適当な場所に作成して、
ファイルを編集。「FROM」には、いま作成したDocker imageを指定で。
FROM centos-spring:reborn ENV container docker RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \ systemd-tmpfiles-setup.service ] || rm -f $i; done); \ rm -f /lib/systemd/system/multi-user.target.wants/*;\ rm -f /etc/systemd/system/*.wants/*;\ rm -f /lib/systemd/system/local-fs.target.wants/*; \ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ rm -f /lib/systemd/system/basic.target.wants/*;\ rm -f /lib/systemd/system/anaconda.target.wants/*; VOLUME [ "/sys/fs/cgroup" ] CMD ["/usr/sbin/init"]
で、このDockerfileを使って、最終的なDocker imageを作成します。
Dockerfileまでのパスは、普通のWindowsのパスで良いらしい
Docker imageができました。
そんでは、作成したDocker imageで、コンテナを作成・起動で。
コンテナを起動する際も条件があったみたい。
In order to run a container with systemd, you will need to mount the cgroups volumes from the host. Below is an example command that will run the systemd enabled httpd container created earlier.
$ docker run -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 80:80 local/c7-systemd-httpd
マウント先が限定されると、って、これ、Windowsだと不可能でした。そもそも、Windowsに「sys/fs/cgroup」なんてディレクトリないしね。
Windowsの場合は、--privilege オプションで、docker run させるしかなさそう。(セキュリティ系に宜しくないらしいけど、他に方法なさそうですしね)
はい、エラー。
⇧ 上記サイト様を参考に、仮想マシンにディレクトリを作成する。
で、再度、コンテナを作成してみるが、
同じエラー。やってられん...
どうやら、特権付与(privileged)をtrueにしてしまうと初回起動はするが、その後コンテナを更新したときにマウントエラーが発生し、以降コンテナが立ち上がらなくなるみたいだ・・・
そして、systemctlを利用するには、特権付与(privileged)をtrueにしないといけない。
⇧ 終わった...systemctl 使わないでいくしかないと...。
っていうか、systemctl って非推奨なの?どうするのがベストプラクティスなのかね?
今回は、systemctl でいかざるを得ないので(というかそれ以外の方法が分からん)、致し方ないけど、仮想マシン再起動で。
起動ログインして、systemctl 動くことを確認!
そんでは、Tomcatをサービスとして起動します。
そしたらば、Tomcatにデプロイします。
ホストのブラウザから、コンテナのTomcatにアクセスできました。
「http://[ホスト名:ポート番号]/[warファイル名]/[Spring Bootのコントローラーで指定したマッピング先]」
Spring Boot のWARもデプロイできてます!
むちゃくちゃ、ハマったけど、なんとか、Linux環境にSpring Boot なプロジェクトをデプロイできましたね。
とりあえず、本日はここまでということで、仮想マシンを停止。
結局、Spring Boot なプロジェクトは、Linux環境でどうデプロイするべきなのか分からずですね...モヤモヤ感しか残らない...
こうして、自分のような知識のない人間が奮闘して分からないまま試行錯誤した結果、アンチパターンが量産されていくんでしょうね...
『「持てる者はさらに与えられ、持たざる者はさらに奪われるであろう」(マタイ伝)』って言葉には、「熱意」を重視ってあるけど、どうなんでしょうね...
というか、休日が潰れてしまったではないか(涙)
今回はこのへんで。