Docker を基本からまとめてみた【Docker Composeで複数コンテナを扱う】

## Docker Composeとは？

Docker Composeとは複数のDockerコンテナを定義し実行するDockerアプリケーションのためのツールのことで、つまりDockerコンテナを楽にまとめて起動したい時はDocker Composeを使う。

## Docker Composeを使うメリット
- 実行コマンドが簡潔になり、環境差異によるミスを起こしにくい
- Dockerネットワークの作成が不要
- インフラ構成の可視化、バージョン管理が可能

## docker-compose.ymlとは？

ymlファイルにはDocker Composeプロジェクトで作成するコンテナの初期設定状態を記述する。

## Docker Composeを使ってWebAPIを作成する

公式：[spring initializr](https://start.spring.io/)

① ブラウザを開き、(https://start.spring.io/) を入力し、開く
② 下記を入力し、Dependenciesで下記を選択し、『GENERATE』ボタンを押す

- Project: Gradle
- Language: Java
- SpringBoot: 3.1.0
- Group: com.example
- Artifact: api
- Name : api
- Description: Demo project for Spring Boot
- Package name: com.example.demo
- Packaging : Jar
- Java : 17

Dependencies
- Spring Web
- Spring Data JPA
- PostgreSQL Driver
- H2 Database

③ java/com/example/api/HelloController.javaを作成する

```java/com/example/api/HelloController.java
package com.example.api;

//@SuppressWarnings("unused")
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {
    @RequestMapping("/hello")
    public String hello(
            @RequestParam String lang
    ) {
        return "HELLO";
    }
}
```
④HELP.mdをクリックしながら、Dockefileを作成する

```Dockerfile
FROM gradle:7

WORKDIR /api
COPY . .

CMD [ "./gradlew", "bootRun" ]
```
⑤ docker image build -t api-img .を行う

⑥ docker container run -p 8080:8080 --rm  api-img を行う

⑦ docker-compose.ymlを作成する

```docker-compose.yml
version: '3.9'
services:
  api:
    build: ./api
    ports:
      - 8080:8080
```
⑧ docker compose upをする

## docker　compose で DB を起動する

① docker-compose.ymlを編集する

```docker-compose.yml
//省略
db:
    image: postgres:15
    ports:
      - 5432:5432
    environment:
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_USER=postgres
      - POSTGRES_DB=appdb
    volumes:
      - db-storage:/var/lib/postgresql/data
      - ./db/initdb:/docker-entrypoint-initdb.d

volumes:
  db-storage:
```
② dbフォルダinitdbフォルダ内に１-create-greetings.sqlと2-create-greetings.sqlを作成する

```db/initdb/１-create-greetings.sql
CREATE TABLE greetings (
    id SERIAL,
    lang VARCHAR(255) NOT NULL,
    text VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);
```
```db/initdb/2-create-greetings.sql
INSERT INTO greetings (lang, text)
VALUES
    ('ja', 'こんにちは'),
    ('en', 'Hello')
;
```
③ docker compose db -d をする

④ docker compose exec db bash をする

⑤ psql -U postgres をする

⑥ docker compose downをする

## APIコンテナとDBコンテナを接続する

① java/com/example/api/GreetingRepository.javaを作成する

```GreetingRepository.java
package com.example.api;

import com.example.api.entities.GreetingEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public interface GreetingRepository extends JpaRepository<GreetingEntity, String> {
    GreetingEntity findFirstByLang(String lang);
}
```
② java/com/example/api/にentitiesフォルダとGreetingEntitiy.javaを作成する

```entities/GreetingEntitiy.java
package com.example.api.entities;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "greetings")
public class GreetingEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;
    public String lang;
    public String text;
}
```
③ java/com/example/api/HelloController.javaを編集する

```HelloController.java
package com.example.api;

import com.example.api.entities.GreetingEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {
    @Autowired
    private GreetingRepository repository;

    @RequestMapping("/hello")
    public String hello(
            @RequestParam String lang) {
        GreetingEntity entity = this.repository.findFirstByLang(lang);
        return entity.text;
    }
}
```
④ src/main/resouces/application.properties を編集する

```application.properties
spring.datasource.url=jdbc:postgresql://db:5432/appdb
spring.datasource.username=postgres
spring.datasource.password=mypassword
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=none
```
⑤ docker-compose.ymlを編集する


```docker-compose.yml
version: '3.9'
services:
  api:
    build: ./api
    ports:
      - 8080:8080

    depends_on:
      - db
  db:
    image: postgres:15
    ports:
      - 5432:5432
    environment:
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_USER=postgres
      - POSTGRES_DB=appdb
    volumes:
      - db-storage:/var/lib/postgresql/data
      - ./db/initdb:/docker-entrypoint-initdb.d

volumes:
  db-storage:
```
⑥　docker compose up　--build をする


## 参考サイト
[初心者OK！Docker入門＋応用：ゼロからでも実務で使えるスキルが身に付ける](https://itplusjp.udemy.com/course/ok-docker/learn/lecture/36758648#overview)
[【初心者向け・図解】Docker Composeとは？Dockerとの違いを現役エンジニアがわかりやすく解説](https://o2mamiblog.com/docker-beginner-2/)