概要
この記事では、Dockerを使用してGoやVue.js、Mysqlの開発環境を構築する方法を紹介します。
間違っている部分や改善すべき点などありましたら、コメントでご指摘いただけますと幸いです。
対象読者
- Dockerを使ってGoとVue.jsの開発環境を構築したい方
- GoとVue.jsを使用したWebアプリケーションの開発に興味がある方
前提
- Dockerがインストールされていること
- node.jsがインストールされていること
- npmがインストールされていること
バージョン情報
- Go: 1.20.2
- Vue.js: 3.24
- Docker: 4.14
リポジトリ
始め方
# Gitリポジトリを取得する
$ git clone https://github.com/tomoki737/tomoki737-go_vue_project.git
# ディレクトリに移動
$ cd go_vue_project
# ネットワークの作成やコンテナの起動
$ make init
使い方
SQLを実行
$ docker-compose exec db bash -c 'mysql -ppassword < docker-entrypoint-initdb.d/*.sql'
Dockerコンテナに接続
# dbコンテナに接続
$ docker-compose exec -it db bash
# backコンテナに接続
$ docker-compose exec -it back sh
# frontコンテナに接続
$ docker-compose exec -it front bash
#sqlに接続
$ docker-compose exec db bash -c 'mysql -u user -ppassword myapp'
Goを実行
$ docker-compose exec back sh -c 'go run <ファイル名>'
npmを実行
$ docker-compose exec front bash -c 'npm run dev'
ディレクトリ構成
.
├──Makefile
├── cmd
│ └── main.go
├── database
│ ├── database.go
│ └── sql
│ └── articles.sql
├── docker
│ ├── back
│ │ └── Dockerfile
│ ├── front
│ │ └── Dockerfile
│ └── mysql
│ └── Dockerfile
├── docker-compose.yml
├── frontend
├── go.mod
└── go.sum
- frontendディレクトリ: Vue.jsのフロントエンドアプリケーションが含まれるディレクトリ
- main.go: Goのバックエンドアプリケーションが含まれるファイル
ハンズオン
- Dockerfileを作成する
- docker-compose.ymlを作成する
- Vueプロジェクトを作成する
- Dockerコンテナをビルド&起動
- サンプルコードの作成
- サーバーを起動
- ブラウザでアクセスする
1. Dockerfileを作成する
バックエンド
# alpineを使ってDockerイメージを軽量化する
FROM golang:1.20.2-alpine
# Alpine Linuxにはgitが含まれていないため、gitをインストールする
RUN apk update && apk add git
# 作業ディレクトリを設定する
WORKDIR /src/back
# go.mod、go.sumをDockerコンテナ内にコピー
COPY ../../go.mod ./
COPY ../../go.sum ./
# コピーした依存関係をダウンロード
RUN go mod download
フロントエンド
FROM node:18.15.0-bullseye-slim
# 作業ディレクトリを設定する
WORKDIR /src/front
# 依存関係をダウンロード
COPY ../../frontend/package*.json ./
# コピーした依存関係をダウンロード
RUN npm install
- package*を指定し、package.json, package.lock.jsonをDockerコンテナ内にコピーしています。
データベース
FROM mysql:8.0.27
2. docker-compose.ymlの作成
version: "3"
services:
back:
build:
context: .
dockerfile: ./docker/back/Dockerfile
container_name: back
tty: true
volumes: # プロジェクトのコードを/src/backにマウント
- ./:/src/back
env_file: # envファイルを指定
- .env
ports:
- "8080:8080"
depends_on:
- db
networks:
- go_network
front:
build:
context: .
dockerfile: ./docker/front/Dockerfile
container_name: front
tty: true
environment:
- NODE_ENV=development # 環境設定を開発用にする
ports:
- "3000:3000"
volumes: # frontendのコードを/src/frontにマウント
- ./frontend:/src/front
depends_on:
- db
networks:
- go_network
db:
build:
context: .
dockerfile: ./docker/mysql/Dockerfile
container_name: db
env_file:
- .env
ports:
- "3306:3306"
volumes:
- db:/var/lib/mysql
- ./database/sql:/docker-entrypoint-initdb.d
networks:
- go_network
volumes:
db:
networks:
go_network:
external: true
-
tty: trueにすることでDockerコンテナを起動し続けることができます。
-
networksを記述することでサービス名を使って通信ができるようになります。
-
depends_onを使用してコンテナが起動する順番を設定しています。
- 今回はdbコンテナが起動してからfront、backコンテナが起動するようにしています。
-
dbボリュームを作成して、/var/lib/mysqlにマウントすることでDBを永続化する(コンテナを停止してもデータが残る)よう設定しています。
-
このコードでは./database/sqlに書いたsqlを/docker-entrypoint-initdb.dにマウントしています。
docker-compose.ymlvolumes: - ./database/sql:/docker-entrypoint-initdb.d
.envファイルの作成
MYSQL_DATABASE=myapp
MYSQL_USER=user
MYSQL_PASSWORD=password
MYSQL_ROOT_PASSWORD=password
docker-composeのenv_fileに指定する.envファイルを作成します。
ネットワークの作成
$ docker network create go_network
docker-compose.ymlで記述したネットワークを作成します。
3. Vueプロジェクトの作成
$ npm init vue@latest
- 最新バージョンをインストールしています。
# 依存関係をダウンロード
$ docker-compose exec front bash -c 'npm install'
3. Dockerコンテナをビルド & 起動
$ docker-compose build
$ docker-compose up -d
4. サンプルコードの作成
以下のサンプルコードをコピペしてください
Goのサンプルコード
package main
import (
"bytes"
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"app/database"
)
type Article struct {
Title string `json:"title"`
Body string `json:"body"`
}
var db *sql.DB
func index(w http.ResponseWriter, r *http.Request) {
var buf bytes.Buffer
var articles []Article
enc := json.NewEncoder(&buf)
rows, err := db.Query("SELECT title, body FROM articles")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
article := &Article{}
if err := rows.Scan(&article.Title, &article.Body); err != nil {
log.Fatal(err)
}
articles = append(articles, Article{
Title: article.Title,
Body: article.Body,
})
}
enc.Encode(&articles)
fmt.Fprintf(w, buf.String())
}
func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
fn(w, r)
}
}
func main() {
db = database.GetDB()
http.HandleFunc("/", makeHandler(index))
log.Fatal(http.ListenAndServe(":8080", nil))
}
package database
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
var db *sql.DB
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
user := os.Getenv("MYSQL_USER")
password := os.Getenv("MYSQL_PASSWORD")
database := os.Getenv("MYSQL_DATABASE")
dataSourceName := fmt.Sprintf("%s:%s@tcp(db:3306)/%s?charset=utf8&parseTime=true", user, password, database)
db, err = sql.Open("mysql", dataSourceName)
if err != nil {
log.Fatal(err)
}
err = db.Ping()
if err != nil {
log.Fatal(err)
}
}
func GetDB() *sql.DB {
return db
}
sqlファイルの作成と実行
USE myapp
CREATE TABLE IF NOT EXISTS articles (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(40) NOT NULL,
body VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT current_timestamp,
updated_at TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp
);
INSERT INTO articles(title, body) VALUES ('title','body');
INSERT INTO articles(title, body) VALUES ('test_title','test_body');
docker-compose exec db bash -c 'mysql -ppassword < docker-entrypoint-initdb.d/*.sql'
依存関係のインストール
module app
go 1.20
require (
github.com/go-sql-driver/mysql v1.7.0
github.com/joho/godotenv v1.5.1
)
$ docker-compose exec back sh -c "go mod download"
5. サーバーを起動
フロントエンド
"scripts": {
// "dev": "vite" <-- 変更
"dev": "vite --port 3000 --host 0.0.0.0",
# 省略
},
viteのオプションでポートとホストIPアドレスを指定しています。
# frontコンテナに入り、npmを実行
$ docker-compose exec -it front bash -c 'npm run dev'
バックエンド
# backコンテナに入り、main.goを実行
$ docker-compose exec -it back sh -c 'go run cmd/main.go'
6. ブラウザでアクセスする
バックエンド
フロントエンド
補足
Makefile
Dockerコマンドは長いのでコマンドを打つのに時間がかかってしまいます。
そこで短いコマンドでDockerコマンドが打てるようにMakefileを作成しました。
詳細はリポジトリのMakefileをご覧ください。
# コンテナを起動する
$ make up
# コンテナを破棄する
$ make down
# backコンテナに接続する
$ make back
# frontコンテナに接続する
$ make front
# dbコンテナに接続する
$ make db
# sqlに接続する
$ make sql
参考記事