構成
Go アプリ
- アプリ名/コンテナ名
- app/app
- 機能
- IDを指定してテーブルを検索・結果表示
- フォルダ共有
- コンテナ中の go ファイルをホストOS から編集できるようにしたいので、
ホストOS の go ファイルがあるフォルダを golang コンテナにマウント
PostgreSQL
- コンテナ名
- postgres
- ユーザ名/パスワード
- app_user/password
- データベース名/テーブル名
- app_db/TEST_USER
- テストデータ
- コンテナ起動時にテーブル作成とデータ挿入を行う
ファイル配置
$GOPATH/src/app
中に、docker と go ソースコードを次のような形で配置
│
├─docker-compose.yml
├─docker
│ ├─golang
│ │ └─Dockerfile
│ └─postgres
│ ├─Dockerfile
│ └─init
│ ├─1_create_table.sql
│ └─2_insert_testdata.sql
└─go
└─main.go
Docker 設定
Docker Compose
「今日から始めるDocker【docker-composeを使ってGo & Mysqlをよしなに起動しよう編】」1 を参考にしました。
# docker-compose のバージョン
version: '3'
# 各コンテナの情報
services:
# postgres サービス
postgres:
# コンテナの名前
container_name: postgres
# Dockerfile のディレクトリパス
build:
context: .
dockerfile: ./docker/postgres/Dockerfile
# postgres 設定
environment:
- POSTGRES_USER=app_user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=app_db
# golang アプリケーション
app:
container_name: app
# postgres をビルドした後に app をビルド
depends_on:
- postgres
# Dockerfile を指定
build:
context: .
dockerfile: ./docker/golang/Dockerfile
# GOPATHを指定
environment:
- GOPATH=/go
# フォルダ共有(ホストOS:コンテナ)
volumes:
- ./go:/go/src/app/go/
# docker-compose run 実行時に実行されるコマンド
command: go run main.go
Dockerfile
app
FROM golang:1.9
# コンテナ作業ディレクトリの変更
WORKDIR /go/src/denki/go
# ホストOSの ./go の中身を作業ディレクトリに追加
ADD ./go .
# パッケージのインストール
RUN go get github.com/lib/pq
postgres
FROM postgres:latest
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UTF-
# 初期化用 sql ファイルを、コンテナ内の所定のディレクトリにコピー
COPY ./docker/postgres/init/*.sql /docker-entrypoint-initdb.d/
/docker-entrypoint-initdb.d/ 内に sql ファイルを配置すると、それらを自動で実行してくれるらしい2
その他ファイル
SQLファイル
テーブル作成
CREATE TABLE TEST_USER (
user_id BIGINT PRIMARY KEY,
user_password VARCHAR(20) NOT NULL
);
テストデータ挿入
DELETE FROM TEST_USER;
INSERT INTO TEST_USER VALUES(1, 'password1');
INSERT INTO TEST_USER VALUES(2, 'password2');
Go
書籍「Goプログラミング実践入門」3を参考にしました
package main
import (
"database/sql"
"fmt"
"log"
// postgres ドライバ
_ "github.com/lib/pq"
)
// TestUser : テーブルデータ
type TestUser struct {
UserID int
Password string
}
// メイン関数
func main() {
// Db: データベースに接続するためのハンドラ
var Db *sql.DB
// Dbの初期化
Db, err := sql.Open("postgres", "host=postgres user=app_user password=password dbname=app_db sslmode=disable")
if err != nil {
log.Fatal(err)
}
// SQL文の構築
sql := "SELECT user_id, user_password FROM TEST_USER WHERE user_id=$1;"
// preparedstatement の生成
pstatement, err := Db.Prepare(sql)
if err != nil {
log.Fatal(err)
}
// 検索パラメータ(ユーザID)
queryID := 1
// 検索結果格納用の TestUser
var testUser TestUser
// queryID を埋め込み SQL の実行、検索結果1件の取得
err = pstatement.QueryRow(queryID).Scan(&testUser.UserID, &testUser.Password)
if err != nil {
log.Fatal(err)
}
// 検索結果の表示
fmt.Println(testUser.UserID, testUser.Password)
}
Docker Compose の実行
シェルで以下のコマンドを実行
$ docker-compose build # イメージの作成
$ docker-compose up # コンテナの作成、起動
コンテナの起動順序を指定していないため、postgres より前に app コンテナが先に起動する場合がある。
そうなると DB にテーブルが存在しないので、以下のエラーが吐かれる
app | 2018/12/15 13:50:02 dial tcp 172.29.0.2:5432: getsockopt: connection refused
一回 Ctrl+C でコンテナを停止させ、もう一度 docker-compose up
でコンテナを実行すると、app の実行結果( app | 1 password1
)が表示される
※起動順序を指定したいときは、docker-compose の entrypoint とスクリプトによって、DBコンテナが起動するまでアプリ起動を待機させる方法がある 4
コンテナの停止・破棄
docker-compose down
イメージの破棄
docker image rm app_app app_postgres
詰まったところ
go get に失敗する
イメージのビルドの際、go get において
cannot find package "パッケージ名" ... (from $GOROOT) ... (from $GOPATH)
のエラーが出てビルドに失敗することがある。原因として、
- パッケージ自体が存在しないか、パスが間違っている
- golang イメージに git がインストールされていない5
があるらしいので、URIを確認するなり、イメージのバージョンを golang:1.9
に変更する等する
postgres コンテナに接続できない
main.go の DB 接続設定で
var Db *sql.DB
// Dbの初期化
Db, err := sql.Open("postgres", "host=localhost user=...
のように host=localhost
とすると
app | ... dial tcp 127.0.0.1:5432: connect: connection refused
データベース接続エラーが吐かれる。host
の値は、接続先のコンテナ名にする必要がある6 ので、host=postgres
に修正して解決