Next.js × Go のWebアプリをDocker上で作成してみませんか？ 〜環境構築編〜

# はじめに
👋こんにちは！Web系の企業に勤務し、地方からフルリモート勤務をしている@takakouと申します🏙️✨

今回は、「**Next.js × Go のWebアプリをDocker上で作成してみませんか？ 〜環境構築編〜**」というテーマで記事をシェアします！📝🐳

この記事を執筆しようと思った経緯としては、私自身が **Next.js** × **Go** × **Docker**の組み合わせでアプリを作成しようとした際、この技術スタックに関する情報が少なく、詰まることも多かったからです😫💡

そこで、同じように、この組み合わせの技術スタックに興味を持つ初学者の方々のために、Dockerを使用して環境を構築する方法を詳しくシェアしたいと思いました🌟

記事執筆は未熟者で、至らない点もあるかと思いますが、皆さんのコメントやフィードバックをお待ちしています！🚀💬
# 目次
<!-- タイトルとアンカー名を編集 -->
1. [対象者 👨](#対象者)
1. [動作環境 🖥️](#動作環境)
1. [技術選定 🛠️](#技術選定)
1. [導入手順 🚀](#導入手順)
1. [参考文献 📚](#参考文献)
1. [おわりに 🎉](#おわりに)
<!-- 各チャプター -->

# 対象者

* ある程度のWebアプリケーションに関する知識がある人
* Dcokerを使ったことがある人
* 必要な知識は自分自身である程度調べられる人

:::note warn
今回の記事では**コードの説明は基本的に行いません**。
気になることがある場合は、記事を調べたり、chatGPTに聞いてみたりして自分で解決していただくようにお願いいたします。

:::

<a id="#environment"></a>
# 動作環境


* PC : **MacBook Air(M1,2020)**

* RAM : **8GB**

* OS : **macOS Monterey(ver12.1)**
:::note warn
環境上の注意点
**Docker** が使える前提で始めていきます。
**Docker**が入っていない場合は、導入するようにお願いいたします。
**Docker Compose V2**を使っています。

:::

<a id="#technical"></a>
# 技術選定
### フロントエンド
* Language: **TypeScript**

* Library: **React**

* FW: **Next.js**

### バックエンド
* Language: **Go**

* FW: **gin**

* DB: **PostgreSQL**


<a id="#exec"></a>
# 導入手順
:::note warn
導入手順内の注意点
``cd``,`exit`コマンドなどの記述はしていません。
適宜必要なタイミングでフォルダを移動したりコンテナのshellから抜けるようにしてください。
:::
## 1. フォルダの作成
アプリのフォルダ作成いたします。
```sh
~ $ mkdir Next_Go_App
```

## 2. backendフォルダ、frontendフォルダ、compose.ymlを作成
作成したアプリのフォルダの中に必要なフォルダ、ファイルを作成いたします。
```sh
~ /Next_Go_App $ mkdir frontend
~ /Next_Go_App $ mkdir backend
~ /Next_Go_App $ touch compose.yml
```

## 3. backendフォルダにDockerfileを作成
```sh
~ /Next_Go_App/backend $ touch Dockerfile
```

## 4. Dockerfileに記述を追加
```Dockerfile
# ベースイメージを指定
FROM golang:latest
# コンテナ内の作業ディレクトリを設定
WORKDIR /app
```

## 5. frontendフォルダにDockerfileを作成
```sh
~ /Next_Go_App/frontend $ touch Dockerfile
```

## 6. Dockerfileに記述を追加
```Dockerfile
# ベースイメージを指定
FROM node:16-alpine
# コンテナ内の作業ディレクトリを設定
WORKDIR /app
```

## 7. compose.yml を記述
frontendとbackend、ついでに今回は使いませんが、dbの設定もしておきます。
```yml
services:
  backend:
    build:
      context: ./backend/
      dockerfile: Dockerfile
    ports:
      - 8080:8080
    volumes:
      - ./backend:/app 
    depends_on:
      - db
  frontend:
    build:
      context: ./frontend/
      dockerfile: Dockerfile
    volumes:
      - ./frontend:/app
    ports:
      - 3000:3000 
  db:
    image: "postgres:15-alpine"
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=db
    volumes:
      - db-store:/var/lib/postgresql/data

volumes:
  db-store:
```
## 8.backendのアプリケーション作成
* backendのコンテナを起動しshellへ入る
```
~ /Next_Go_App $ docker compose run backend sh
```

* Goモジュールを初期化する
```
# go mod init [githubプロジェクト名]
```

* HTTPルータの役割をするFWのGinを導入
```
# go get -u github.com/gin-gonic/gin
```

* main.go を作成
```
# touch main.go
```

* main.goの処理を記述
```go
package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	//Ginフレームワークのデフォルトの設定を使用してルータを作成
	router := gin.Default()
	
	// ルートハンドラの定義
	router.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello, World!",
		})
	})

	// サーバー起動
	router.Run(":8080")
}
```
* backend/Dockerfileの記述を更新
```Dockerfile
# ベースイメージを指定
FROM golang:latest

# コンテナ内の作業ディレクトリを設定
WORKDIR /app

# ローカルのソースコードをコンテナにコピー
COPY . .

# 必要なパッケージをインストール
RUN go mod download

# アプリケーションをビルド
RUN go build -o main .

# 公開予定のコンテナのポートを明示
EXPOSE 8080

# アプリケーションを実行
CMD ["go", "run", "main.go"]
```
* backendのコンテナを起動
```sh
~ /Next_Go_App $docker compose up backend --build
```

* ブラウザで「**localhost:8080**」へアクセス
```json
{”message” : ”Hello World!”}
```
先ほどmain.goで作成したmessageがjson形式で戻ってくればOKです。

:::note info
ブラウザでアクセスする方法の他にAPIを叩けるツールが用意されていたりします。
参考文献にTalendAPIについて言及している他の方の記事を貼っておきます。
そちらを使ってみるのも良いと思います。
:::

## 9. frontendアプリケーションの作成
* frontendのコンテナを起動し、shellに入る
```
~ /Next_Go_App $ docker compose run frontend sh
```

* Dockerfileを削除する
これはアプリを作成するディレクトリに他のファイルがあると、npxコマンド実行時にコマンド実行ができないためです。
```
/app# rm ./Dockerfile
```
* Next.jsのアプリケーションを作成
作成時に設定をどうするか出てきますが、基本的にはデフォルトのままで大丈夫です。
```
/app# npx create-next-app . --typescript
```

* Dockerfileを再度作成
```sh
/app# touch Dockerfile
```

* Dockerfileに記述
```Dockerfile
# ベースイメージを指定
FROM node:16-alpine

# 作業ディレクトリを設定
WORKDIR /app

# キャッシュ利用で効率化するために別でコピー
COPY package.json package-lock.json ./

# ソースコードをコピー
COPY . .

# 依存関係をインストール
RUN npm install

# アプリケーションをビルド
RUN npm run build

# ポート番号を指定
EXPOSE 3000

# アプリケーションを起動
CMD ["npm","run","dev"]
```

* backendのコンテナを起動します。
```
~ /Next_Go_App $ docker compose up frontend --build
```

* ブラウザで「**localhost:3000**」にアクセス
下記のような画面が表示されていたら無事に起動できています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524017/750ea24f-fd7f-8c99-ef4d-6dcbb9f4dcb4.png)

<a id="#reference"></a>
# 参考文献

https://qiita.com/ktr1211/items/c16cb4f99f91b998af46


<a id="#end"></a>
# おわりに


今回の記事では、各アプリケーションが個別のコンテナ内で正常に起動できることを確認しました🚢💻

次回の記事では、DBのスキーマ作成に説明していきます🔗🔀

もし興味を持っていただけましたら、ぜひ続きも読んでいただけるとうれしいです！📖🌟（次回の公開は近日中を予定しています）

この連載を通じて、より深い理解とスキルの向上を目指して、一緒に学んでいただけると幸いです🌱👨‍🎓

(最後に、気づいた方もいらっしゃると思うのですが、絵文字を入れるのは苦手なので、文章に沿った絵文字を挿入するのに、ChatGPTを利用させていただきましたが、いかがでしたでしょうか。不快に思われた方がいたら申し訳ございません🙇‍♂️)

(8/18追記)
続編となる記事を公開しました。
この記事を読み終わって次に進みたい方などがいらっしゃいましたら見ていただけると幸いです。🙇‍♂️

https://qiita.com/takakou/items/4f8cd3686c7ec84c141d

(10/10追記)
さらに続編となる記事を公開しました。

https://qiita.com/takakou/items/b00f5065428ac1cb10ec