ちょっとしたWebアプリを開発をVue.js+Go+MongoDBで作成したいなーと思い立ち、色々覚えたこと調べたことをメモ書きや振り返っていきます。
なお、筆者はGoとMongoDBは完全初見。
作ったアプリはまた別の形で公開しようかなと考え中です。
目次
環境
- Windows 11
- Virtual Box 6.1(ゲスト:Ubuntu 20.04)
- Docker 20.10.11
- Go 1.17.6
- MongoDB 5.0.6
フォルダ構成
Goのフォルダ構成はとりあえず適当です。後々ファイルが多くなってきたら修正していきたい…。
あとは適当にDockerファイルなんかを配置したりしています。
$ tree
.
├── docker-compose.yml
├── go
│ ├── app
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── mongo.go
│ └── config
│ └── Dockerfile
└── mongo
└── docker-entrypoint-initdb.d
├── 01_init.js
├── 02_init.sh
└── sample.json
Dockerの設定周り
MongoDBはイメージそのまま使用しています。
Goのイメージは設定を少し弄りたかったのでDockerfileを使用しています。
MongoDBコンテナの設定周り
MongoDBはそのままイメージを使用するのですが、一部環境設定をenvironment
に記述しています。rootユーザのusername及びpasswordです。
他に設定可能な情報は公式を参照してください。
あとは/docker-entrypoint-initdb.d
以下にスクリプトとデータを配置してコンテナ起動時に初期データを投入しています。
version: '3.9'
services:
go:
container_name: go
build:
context: ./go
dockerfile: ./config/Dockerfile
restart: unless-stopped
tty: true
volumes:
- type: bind
source: ./go/app
target: /go/src/app
mongo:
container_name: mongo
image: mongo:5.0.6-focal
restart: unless-stopped
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=password
- MONGO_INITDB_DATABASE=sample
- TZ=Asia/Tokyo
ports:
- 27017:27017
volumes:
- type: bind
source: ./mongo/docker-entrypoint-initdb.d
target: /docker-entrypoint-initdb.d
- type: volume
source: mongo
target: /data/db
volume:
nocopy: true
- type: volume
source: mongo
target: /data/configdb
volume:
nocopy: true
volumes:
mongo:
Goコンテナの設定周り
composeファイルの設定に加えて別途Dockerfileにも設定を記述しています。必要なソフトウェア類をインストールしているだけですが。
Goのコンテナイメージを扱うのは初なのでこの辺はもう少し良い方法を模索していきたいなと思っています。
FROM golang:1.17.6-bullseye
RUN apt-get update && \
apt-get install -y \
git \
curl
# clean
RUN apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /go/src/app
COPY ./app /go/src/app
WORKDIR /go/src
MongoDBの初期設定、初期データスクリプト
以下のファイルで初期設定と初期データを投入しています。
- 01_init.js
- 02_init.sh
- sample.json
01_init.jsではユーザ、データベースを作成するスクリプトです。sample
データベースの作成とそこにアクセス可能なユーザ(mongo)を作成しています。作成したデータベース上にはsample_collection
というcollectionも併せて作成しています。
var user = {
user: "mongo",
pwd: "mongo",
roles: [
{
role: "dbOwner",
db: "sample"
}
]
};
db.createUser(user);
db.createCollection("sample_collection");
02_init.sh及びsample.jsonでは作成したcollectionに対して初期データを投入しています。
mongoimport -u mongo -p mongo --db sample --collection sample_collection --file /docker-entrypoint-initdb.d/sample.json --jsonArray
初期データは特に意味の無いデータです。
[
{
"sampleDate": "2021-01-01 10:00:00",
"username": "sample_user_001"
},
{
"sampleDate": "2021-01-02 10:00:00",
"username": "sample_user_002"
},
{
"sampleDate": "2021-01-03 10:00:00",
"username": "sample_user_003"
}
]
Goコンテナからの接続
Goの接続ドライバーにはmongo-go-driverを使用しました。
MongoDBに接続して、初期データを一覧表示させるところまで実装していきます。
GoコンテナからはMongoDBのサービス名「mongo」で接続が可能です。ユーザ名やパスワードはURLに直接指定しています。credential
情報にユーザ名とパスワードをSetAuth
経由で設定して接続しようとした場合、以下のエラーが発生し接続出来ませんでした。何故だろう…。
connection() error occured during connection handshake: auth error: sasl conversation error: unable to authenticate using mechanism "SCRAM-SHA-1": (AuthenticationFailed) Authentication failed.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://mongo:mongo@mongo:27017/sample"))
if err != nil {
log.Fatal(err)
}
log.Println("fetch start.")
collection := client.Database("sample").Collection("sample_collection")
cursor, err := collection.Find(context.Background(), bson.D{})
if err != nil {
log.Fatal(err)
}
for cursor.Next(context.Background()) {
result := struct {
ID primitive.ObjectID
sampleDate string
username string
}{}
err := cursor.Decode(&result)
if err != nil {
log.Fatal(err)
}
raw := cursor.Current
log.Println(raw)
}
log.Println(collection)
// Close connection
client.Disconnect(ctx)
}
実行結果は以下になります。
root@24c511c33904:/go/src/app# go run main.go
2022/02/15 14:03:57 fetch start.
2022/02/15 14:03:57 {"_id": {"$oid":"620a67eaf3e939096fedc06b"},"sampleDate": "2021-01-01 10:00:00","username": "sample_user_001"}
2022/02/15 14:03:57 {"_id": {"$oid":"620a67eaf3e939096fedc06c"},"sampleDate": "2021-01-02 10:00:00","username": "sample_user_002"}
2022/02/15 14:03:57 {"_id": {"$oid":"620a67eaf3e939096fedc06d"},"sampleDate": "2021-01-03 10:00:00","username": "sample_user_003"}
2022/02/15 14:03:57 &{0xc00015a4e0 0xc0000a8600 weight 0xc0000919a0 <nil> 0xd5bf40 0xc0000a2270 0xc0000a2288 0xc0000b8bd0}
とりあえず接続するところまでは出来ました。
もう少しソースや構成を変更してみようかと思います。