DockerのインストールからSpring BootでDockerHubへプッシュまで

はじめまして。ドカっとドカ土香　ドカちゃんです♡
Dockerの使い方あまりわかってないけど、
とりあえず使いながら理解していこうってことで、
Springドキュメントのガイド『[Docker で Spring Boot](https://spring.pleiades.io/guides/gs/spring-boot-docker/#initial)』を見ながら進めてたんだけど、所々詰まったから手順を残しておくよ><
気になったところはガイドを見てね。

準備ができたら
**よーい よーい ドーンだYO!!**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/bd1df209-5d86-9967-cc3e-8c14e660367e.png)

環境
---
・Windows 10 pro

前提条件
---
Windows 10でDockerを利用するには「Hyper-V」 が必要だよ。
Windows 10 の Professional 以上のエディションが必要で、Windows 10 Home には対応していないよ。

##Hyper-Vを有効化
コントロール パネルを開いて、
プログラムと機能→左の[Windows の機能の有効化または無効化] →[Hyper-V] 選択→[OK]
Windowsの再起動をするよ。
##Dockerのインストール
利用するには Docker IDを登録する必要があるよ。
・https://hub.docker.com/

ここからインストールしていくよ。
インストールは簡単だったよ。
・https://hub.docker.com/?overlay=onboarding
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/d0310883-e794-0e4a-eefd-a4b6474ba4f8.png)
手順の中でPowerShellが必要になるよ。
インストールできたら、PowerShellを起動してコピペで入力していくだけだよ。
・[windows PowerShellのインストール](https://www.virment.com/how-to-install-latest-powershell-in-windows10/)

チュートリアルを完了してレジストリができていたらおｋだよ。

##Spring Boot
####準備するもの
- ファイル編集用にテキストエディターまたは IDE　→メモ帳でおｋ
- JDK 1.8  以降　→コマンドプロンプトで「jar」と打って使用方法が表示されたらおk　[インストール方法](https://qiita.com/ko2a/items/69fa8a5366d7449500ca)
- Gradle 4+　→[インストールサイト](https://gradle.org/install/)

PowerShellに次のコードを入力するよ。
①`git clone https://github.com/spring-guides/gs-spring-boot-docker.git`
②`cd gs-spring-boot-docker/initial`

(参考パス、C:ユーザー/ユーザー名/gs-spring-boot-docker/initial/)
src/main/java/hello/Application.javaを開くよ。
「Hello Docker World」を表示させたいなら以下に書き換えるよ。

```java
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class Application {

  @RequestMapping("/")
  public String home() {
    return "Hello Docker World";
  }

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

}
```
　
gradlew buildをしていくよ。
Springのガイドでは以下を入力するよう記載されてるけどPowerShelldだとエラーがでるよ。
`./gradlew build && java -jar build/libs/gs-spring-boot-docker-0.1.0.jar`

```エラー.html
発生場所 行:1 文字:17
+ ./gradlew build && java -jar build/libs/gs-spring-boot-docker-0.1.0.j ...
+                 ~~
トークン '&&' は、このバージョンでは有効なステートメント区切りではありません。
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidEndOfLine
```
「&&」を「;」に書き換えると成功するよ。
`./gradlew build ; java -jar build/libs/gs-spring-boot-docker-0.1.0.jar`

8080に繋げて「Hello Docker World」が表示されたらOKだよ。
クリック→ http://localhost:8080/

##コンテナー化
パス：～/gs-spring-boot-docker/initial/ 配下にDockerfileを作成するよ。
このあとのDockerイメージを作成するのに必要だよ。
拡張子はつけないよ。
①～③パターンあるよ。
初めて作る人は①から試して理解を深めていくといいよ。
面倒なら①だけでもいいし、最適化された③から実施してもいいよ。

####①基本

```Dockerfile.
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
```
JDK8をベースとしているよ。
JAR ファイルを「app.jar」としてコンテナーに入れ、
ENTRYPOINT で実行しているよ。
　

PowerShellで以下を実行してイメージを作成するよ。
`docker build --build-arg JAR_FILE=build/libs/*.jar -t springio/gs-spring-boot-docker .`
「docker build [OPTION]には一つ以上の引数が必要です～」とメッセージが出てビルドできなかったけど、
端末再起動後に入力したら上手くいったよ。
成功すると以下のようなイメージで表示されるよ。

```成功イメージ.html
Sending build context to Docker daemon  21.11MB
Step  : FROM openjdk:8-jdk-alpine
 ---> 
Step  : ARG JAR_FILE=target/*.jar
 ---> Using cache
 ---> 
Step 5/6 : COPY ${JAR_FILE} app.jar
COPY failed: no source files were specified
```

####②セキュリティ向上ver.
このままではセキュリティ上問題があるらしく、
非 root ユーザーとしてアプリを実行するように書き換えるよ。

```Dockerfile.html
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
```
イメージ作成
`docker build -t springio/gs-spring-boot-docker .`

以下で実行すると
`docker run -p 8080:8080 springio/gs-spring-boot-docker`
ユーザー名を確認できるよ。
>[アプリケーションの起動ログでユーザー名を確認できます（最初の INFO ログの「開始者」に注意してください）](https://spring.pleiades.io/guides/gs/spring-boot-docker/#initial)


```ログ.html
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

2020-04-23 07:29:41.729  INFO 1 --- [           main] hello.Application  
...
```

####③パフォーマンス向上ver.
次にSpring Boot fat の特性を活かしてパフォーマンスを上げるよ。また書き換えていくよ。
>[Spring Boot fat jar ファイルでは依存関係とアプリケーションリソースが明確に分離されており、その事実を使用してパフォーマンスを向上させることができます。](https://spring.pleiades.io/guides/gs/spring-boot-docker/#initial)

```Dockerfile.
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
```
次にSpringのガイドでは下のコードで実行するように記載してあるけどPowerShellだとエラーが起こるよ。
`mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)`

```エラー.html
式の終わりの ')' が存在しません。
発生場所 行:1 文字:30
+ mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*. ...
+                              ~~~~~~~~~~~~~~~~~~~~
式は、パイプラインの最初の要素としてのみ許可されます。
発生場所 行:1 文字:73
+ ... r -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
+                                                                         ~
式またはステートメントのトークン ')' を使用できません。
```
「()」括弧を使えないみたいだよ。
macだと問題ないのかな？
かなり探したけど括弧を置き換えたり、有効化する方法は見つからなかったよ。。
よく見たら括弧外して処理を分けれるよ。
①`mkdir -p build/dependency`
②`cd .\build\dependency\`
③`jar -xf ../libs/*.jar`
dependency配下に、BOOT-INF/lib とアプリケーションクラスを含む BOOT-INF/classes ディレクトリが作成されたよ。

##Gradle を使用して Docker イメージを作成する
Gradle で Docker イメージを作成するよ。
ネームスペースにはdockaerのユーザー名を入力するよ。
（ちなみに、個人のイメージはネームスペースが必要で、公式イメージなら必要ないよ。）
リポジトリ名は自由に決めてね。
今回はリポジトリ名を「spring-boot-docker」にしておくよ。
`./gradlew bootBuildImage --imageName=ネームスペース/spring-boot-docker`

イメージを作成したときのログだよ。
images()の中身はイメージIDだよ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/14f8322f-e08e-39b9-6eea-e338db1748fb.png)


「./gradlew」が使えないとエラーが出たら階層を間違えているからGradleのある場所に戻ればいいよ。
例：`cd C:\Users\ユーザー名\gs-spring-boot-docker\initial`

ローカルで作成したイメージを動かしてみるよ。
`docker run -p 8080:8080 -t springio/gs-spring-boot-docker`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/7d0fb697-91b8-b3a4-60cc-0ee772c8a083.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/c693fa0b-a66e-fb66-78ff-13415bd7e1ba.png)

##DockerHubへプッシュ
`docker images`で作成したイメージ一覧を確認できるよ。
`docker push ユーザー名/spring-boot-docker`でプッシュするよ。

（ちなみに docker rmi コマンドでイメージを削除できるよ。
削除するにはイメージ ID かイメージ名を使うよ。
・docker rmi -f 7d9495d03763
・docker rmi -f spring-boot-docker）

dockaerにログインしてリポジトリ一覧を見るとプッシュしたリポジトリが追加されているよ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/13d6f9aa-6b06-1c76-94e5-fd53d1d32d9f.png)

**おわりだYO!!**

間違っていたら指摘お願いするよ。