今回できたこと
Goを使用してREST APIを作成した。
その際,Dockerを使用し,フレームワークには軽量なechoを使用した。
また,SSL化も行い,Let`s Encriptを使用した。
最初に知っておきたいコマンド
(停止)
$ docker stop <コンテナ名>
(削除)
$ docker rm <コンテナ名>
(全削除)
(コンテナ)$ docker rm -f `docker ps -a -q`
(イメージ)$ docker rmi $(docker images -q) -f
(build)
$ docker-compose up -d --build
(コンテナ起動)
$ docker-compose exec <コンテナ名> bash
(動いているdocker一覧表示)
$ docker-compose ps
(作成した全てのdocker一覧表示)
$ docker-compose ps -a
(コンテナ内に入る)
$ docker-compose exec <コンテナ名> bash
$ docker-compose exec mysql bash
(MySQL接続)
root@コンテナ番号:/# mysql -u root -p -h 127.0.0.1
mysql> show databases;
mysql> use golang;
mysql> show tables;
mysql> SELECT * FROM `users`;
mysql> show index from users;
mysql> CREATE INDEX association_idx ON users(A, B);
全容
初期設定
docker, docker-compose インストール済み
Docker のインストール手順
Docker のインストール手順
Docker Compose のインストール
フォルダは以下を作る
└─プロジェクト名
├─server
│ ├─docker
│ │ ├─golang
│ │ │ └─Dockerfile
│ │ ├─mysql
│ │ │ ├─Dockerfile
│ │ │ └─db
│ │ │ └─init.sql
│ │ ├─src
│ │ │ ├─crt <-Dockerで自動生成(証明書が入る予定)
│ │ │ ├─databases
│ │ │ │ └─main.go
│ │ │ ├─routing
│ │ │ │ └─main.go
│ │ │ ├─go.mod <-自動生成
│ │ │ ├─go.sum <-自動生成
│ │ │ └─main.go
│ │ ├─docker-compose.yml
│ │ └─api_v1.yaml <-必要に応じて
│ └─Server.md <-必要に応じて
└─README.md <-必要に応じて
証明書作成
無料の認証局を利用する
Let`s Encrypt
certbot
証明書が生成されているか確認する
$ ls /etc/letsencrypt/live/<自分のドメイン名>
>> README cert.pem chain.pem fullchain.pem privkey.pem
プロジェクトを書き込み
DockerComposeの設定
version: "3"
services:
golang:
build: ./golang/
image: image_golang
container_name: container_api
volumes:
- ./src:/go/src
# 証明書を/go/src/crtへ
- /etc/letsencrypt:/go/src/crt
ports:
- "443:443"
tty: true
mysql:
# platform: linux/x86_64 #AppleSiliconを使用時,必要
build: ./mysql/
image: image_mysql
container_name: container_db
volumes:
- ./mysql/db:/docker-entrypoint-initdb.d #初期データをマウントする場所
environment: # コンテナ内のMySQLを起動する際のパスワードを設定
- MYSQL_DATABASE=golang # 作成するデータベース名
- MYSQL_USER=akidon # 作業ユーザー名(任意の値)
- MYSQL_PASSWORD=12345 # 作業ユーザーのパスワード(任意の値)
- MYSQL_ROOT_PASSWORD=root # rootユーザーのパスワード(デフォルトでは「root」)
ports:
- "3306:3306"
tty: true
説明
build: Dockerfileが存在する場所
image: イメージの名前
container_name: コンテナの名前
volumes: 「./a:/b」 aはホスト側のフォルダを bのdockerコンテナ側へ
ports: ポート
environment: 環境変数
tty: true コンテナ起動永続化
links: 他のコンテナの接続?
AppleSiliconを使用している場合は17行目のリマークを外す
DockerFileの設定
# golang/Dockerfile
FROM golang:1.14
WORKDIR /go/src
# mysql/Dockerfile
FROM mysql
MySQLの初期設定
-- MySQL dump 10.13 Distrib 5.1.51, for pc-linux-gnu (i686)
--
-- Host: 127.0.0.1 Database: world
-- ------------------------------------------------------
-- Server version 5.1.51-debug-log
/*以下Databaseの内容が記載される*/
DROP SCHEMA IF EXISTS golang;
CREATE SCHEMA golang;
USE golang;
DROP TABLE IF EXISTS golang;
CREATE TABLE users
(
id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
name VARCHAR(40),
age INT(10),
created_at TIMESTAMP DEFAULT NULL,
updated_at TIMESTAMP DEFAULT NULL,
deleted_at TIMESTAMP DEFAULT NULL
);
INSERT INTO users (id, name, age) VALUES (1, "testKun", 21);
説明
Goの設定
package databases
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// SQLConnect DB接続
func GormConnect() (database *gorm.DB) {
DBMS := "mysql" // MySQL
PROTOCOL := "tcp(container_db)" // MySQLコンテナ名
DBNAME := "golang" // テーブル名
USER := "akidon" // MySQLユーザー名
PASS := "12345" // パスワード
CONNECT := USER + ":" + PASS + "@" +PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=True&loc=Local" // 修正!!
db, err := gorm.Open(DBMS, CONNECT)
if err != nil {
panic(err.Error())
} else {
fmt.Println("DB接続成功")
}
return db
}
説明
package routing
import (
"fmt"
"github.com/labstack/echo"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"src/databases"
)
type User struct {
gorm.Model
Name string `json:"name"`
Age int `json:"age"`
}
func (u User) String() string {
return fmt.Sprintf("Name:%s \n Age:%d \n ",
u.Name,
u.Age)
}
// ユーザー情報取得
func BaseAPI_GET() echo.HandlerFunc {
return func(c echo.Context) error {
db := databases.GormConnect()
defer db.Close()
text1 := search(db)
return c.JSON(200, text1)
}
}
// ユーザーを登録,更新
func BaseAPI_POST() echo.HandlerFunc {
return func(c echo.Context) error {
db := databases.GormConnect()
defer db.Close()
//追加・更新
user := new(User)
if err := c.Bind(user); err != nil {
return err
}
user1 := User{
Name: user.Name,
Age: user.Age,
}
insertUsers := []User{user1}
insert(insertUsers, db)
// update(user1, db)
return c.JSON(200, "追加完了")
}
}
func insert(users []User, db *gorm.DB) {
for _, user := range users {
db.NewRecord(user)
db.Create(&user)
}
}
func update(users User, db *gorm.DB) {
var user User
db.Model(&user).Where("id = ?", 1).Update(map[string]interface{}{"name": users.Name, "age": users.Age})
}
func search(db *gorm.DB) []User {
var user []User
// 同じ位置にいるリストを取得
db.Raw("SELECT * FROM users").Scan(&user)
return user
}
説明
type User struct {
gorm.Model
Name string `json:"name"`
Age int `json:"age"`
}
User(単数形)はMySQLのテーブル名「Users(複数形)」単数名にする必要がある
Name,Ageは先頭大文字である必要がある。
json:"name"はリクエストボディに関連させる名前。
package main
import (
"github.com/labstack/echo"
"src/routing"
)
func main() {
e := echo.New()
// routing
e.GET("/user",routing.BaseAPI_GET())
e.POST("/user",routing.BaseAPI_POST())
e.Logger.Fatal(e.StartTLS(":443", "/crt/live/<あなたのドメイン名>/fullchain.pem", "/crt/live/<あなたのドメイン名>/privkey.pem"))
}
HTTPでよいなら
version: "3"
services:
golang:
build: ./golang/
image: image_golang
container_name: container_api
volumes:
- ./src:/go/src
# 証明書を/go/src/crtへ
# - /etc/letsencrypt:/go/src/crt <- 削除
ports:
# - "443:443" <- 削除
- "8080:8080" <- 追加
tty: true
mysql:
# platform: linux/x86_64 #AppleSiliconを使用時,必要
build: ./mysql/
image: image_mysql
container_name: container_db
volumes:
- ./mysql/db:/docker-entrypoint-initdb.d #初期データをマウントする場所
environment: # コンテナ内のMySQLを起動する際のパスワードを設定
- MYSQL_DATABASE=golang # 作成するデータベース名
- MYSQL_USER=akidon # 作業ユーザー名(任意の値)
- MYSQL_PASSWORD=12345 # 作業ユーザーのパスワード(任意の値)
- MYSQL_ROOT_PASSWORD=root # rootユーザーのパスワード(デフォルトでは「root」)
ports:
- "3306:3306"
tty: true
// e.Logger.Fatal(e.StartTLS(":443", "/crt/live/<あなたのドメイン名>/fullchain.pem", "/crt/live/<あなたのドメイン名>/privkey.pem"))
e.Logger.Fatal(e.Start(":8080")) // <- 追加
オレオレ証明書では
// e.Logger.Fatal(e.StartTLS(":443", "./crt/live/<あなたのドメイン名>/fullchain.pem", "./crt/live/<あなたのドメイン名>/privkey.pem"))
e.Logger.Fatal(e.StartTLS(":443", "crt/myself.crt", "crt/myself.key")) // <- 追加
動かす
$ cd ../プロジェクト名/server/docker
(再ビルドしても変更されない場合はキャッシュが残っている可能性がある為,全削除)
(注意) $ docker rm -f `docker ps -a -q`
(ビルドする)
$ docker compose up -d --build
(コンテナ内に入る)**1分ぐらい待つ(MySQLの初期設定の完了に時間がかかる)**
$ docker-compose exec mysql bash
root@コンテナ番号:# exit
$ docker-compose exec golang bash
(go mod init フォルダ名)
root@コンテナ番号:/go/src# go mod init src
root@コンテナ番号:/go/src# go run main.go
MySQLの中を覗く
% docker-compose exec mysql bash
root@コンテナ番号:/# mysql -u root -p -h 127.0.0.1
(パスワードの入力を求められるので「root」を入力)
-> root
(現在存在するアカウントの確認)
(hostに「%」がついてるか確認)
mysql> select host,user from mysql.user;
+-----------+------------------+
| host | user |
+-----------+------------------+
| % | akidon |
| % | root |
| localhost | mysql.infoschema |
| localhost | mysql.session |
| localhost | mysql.sys |
| localhost | root |
+-----------+------------------+
(ついていない場合は以下コードで追加できたはず)
mysql> grant all privileges on golang.* to 'akidon'@'%';
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| golang | <- 作成できてるか確認
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.06 sec)
mysql> use golang;
mysql> show tables;
+------------------+
| Tables_in_golang |
+------------------+
| users | <- 作成できてるか確認
+------------------+
1 row in set (0.01 sec)
mysql> SELECT * FROM `users`;
+----+---------+------+------------+------------+------------+
| id | name | age | created_at | updated_at | deleted_at |
+----+---------+------+------------+------------+------------+
| 1 | testKun | 21 | NULL | NULL | NULL |
+----+---------+------+------------+------------+------------+
1 row in set (0.00 sec)
この時点でエラーが起きた場合
・src/main.go 27行目のcontainer_dbはdocker-composeで指定したコンテナ名を指定しているか。
・ポート解放してるか
・データベース(テーブル)が正しく作成されているか(今回ならgolang)
・大文字小文字の区別を無視していないか
・go mod init src したか?(この辺は理解不足で間違っている場合がある。src以下のファイルをサブパッケージとして参照できるようにする??)
・docker起動できているか以下コマンドで確認
# 動いているdocker一覧表示
docker-compose ps
# 作成した全てのdocker一覧表示
docker-compose ps -a
豆知識
main.goの内容を変更してもDocker再buildする必要はない
SequelAce
GoENV
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_arm64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/go/src/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build147035606=/tmp/go-build -gno-record-gcc-switches"