はじめに
Googleが開発したプログラミング言語「Go」を学ぶために、Dockerを活用してMySQLコンテナと接続する手順を記録としてまとめました。
Dockerを使って「Hello, World!」を出力する手順を完了し、次のステップとしてMySQLコンテナの立ち上げ方法を実践していきます。
今回の記事では、Go言語を用いたMySQLコンテナとの連携について解説します。この内容がどなたかの技術学習の支えになれば幸いです。
書こうと思ったきっかけ
当初は、Goアプリケーションを動かすためのDockerfile作成を目標にしていました。
これまでにも他のコンテナでDockerfileを作成した経験があったため、比較的スムーズに作成を終えることができました。
その後、「Hello, World!」の表示にも成功したので、次のステップとして、SQLなどのデータベースコンテナと接続することに挑戦してみました。
技術検証の過程では、いくつかエラーが発生し、その確認に時間がかかりましたが、最終的にブラウザ上で正常に動作する形に持っていくことができました。
今回の検証内容やコードについて、この記事で共有したいと思います。
Go言語とDockerの知識整理
Go言語やDockerの基礎知識については、前回の記事で詳しくまとめていますので、必要に応じてそちらをご参照ください。
また、Go言語が端末にインストールされていない場合は、初回の記事で環境構築の手順(Windows、Linux、Macそれぞれ)を解説しています。まだ環境構築が済んでいない方は、そちらを参考にしてみてください。
本記事を書くにあたり遭遇したエラーたち
この記事を投稿するにあたり、ローカル環境で試行錯誤する中でいくつかのエラーに遭遇しました。そこで、それらを備忘録としてまとめておきます。
エラーその1: Goのバージョン指定エラー
このエラーは、go.mod
ファイル内の Goバージョン指定が誤っている ことが原因でした。
-
有効な形式:
go 1.20
-
無効な形式:
go 1.23.4
(エラー例)
エラー詳細
=> [app 4/6] RUN [ ! -f go.mod ] && go mod init my-go-app || true 0.1s
=> ERROR [app 5/6] RUN go mod tidy 0.1s
------
> [app 5/6] RUN go mod tidy:
0.099 go: errors parsing go.mod:
[+] Running 0/1od:3: invalid go version '1.23.4': must match format 1.23
⠼ Service app Building 1.3s
failed to solve: process "/bin/sh -c go mod tidy" did not complete successfully: exit code: 1
➜ my-go-app git:(honda-branch) ✗
解決方法
go.mod
ファイルを確認し、現在のバージョン指定に誤りがないかチェックします。不正なバージョン指定があった場合は、正しい形式に修正してください。
遭遇したエラー その2: MySQLの起動完了前に接続を試みる問題
Goアプリケーションが、MySQLの起動完了を待たずに接続を試みたために発生したエラーです。
ログを見ると、go_app
がデータベースに接続を試みた時点で、MySQLはまだ初期化中(Initializing database files
)であることが分かります。
mysql_db | 2025-01-12T21:04:10.100046Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
go_app exited with code 1
解決方法
このように、MySQLが完全に起動していない状態でGoアプリケーションが接続を試みると、接続に失敗し、go_app コンテナが終了してしまいます(詳細は後述します)。
ディレクトリ構造
以下のようなディレクトリ構造を使用します。
my-go-app/
├── main.go # Goアプリケーションのエントリポイント
├── Dockerfile # Goアプリケーション用のDocker設定ファイル
├── docker-compose.yml # Docker Compose設定ファイル
├── wait-for-it.sh # MySQLの起動を待機するスクリプト
├── go.mod # Goモジュール設定ファイル
├── go.sum # Goモジュール依存関係ファイル
└── README.md # プロジェクト説明用(任意)
今回使用したコード
今回、私が使用した各ファイルのコードを以下に示します。このコードを利用することで、前述のエラーを解決することができました。
※ただし、これはあくまで一例です。
使用する際にはご自身の環境に合わせて調整し、自己責任でご利用ください。
1. main.go
GoアプリケーションにMySQL接続機能を追加し、上記の修正内容を反映した最終的なコードです。
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
_ "github.com/go-sql-driver/mysql"
)
// データベース接続設定
const (
dbUser = "root"
dbPassword = "password"
dbHost = "db"
dbPort = "3306"
dbName = "testdb"
)
func main() {
// データベース接続文字列を構築
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", dbUser, dbPassword, dbHost, dbPort, dbName)
// データベースに接続
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer db.Close()
// データベース接続を確認
err = db.Ping()
if err != nil {
log.Fatalf("Failed to ping database: %v", err)
}
fmt.Println("Connected to the database successfully!")
// ハンドラ関数をルートパスに登録
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World! Database connection is working!")
})
// サーバーをポート8080で起動
fmt.Println("Server is running on port 8080...")
http.ListenAndServe(":8080", nil)
}
db.Ping()
を使って接続をチェックし、問題があればログにエラーメッセージを出力して終了します。
-
HTTPハンドラの設定
/
パスでリクエストを受け取った際に、MySQL接続が成功しているメッセージを返します。 -
Docker環境との連携
dbHost
はDocker Composeで設定したサービス名(例:db
)と一致させる必要があります。
2. Dockerfile
Goで書かれたアプリケーションをビルドし、MySQLの準備が完了するのを待機してから起動するためのDockerイメージを作成しています。
FROM golang:1.20
WORKDIR /app
COPY . .
# wait-for-it.sh をコンテナにコピー
COPY wait-for-it.sh /wait-for-it.sh
RUN chmod +x /wait-for-it.sh
RUN [ ! -f go.mod ] && go mod init my-go-app || true
RUN sed -i 's/^go .*/go 1.20/' go.mod || true
RUN go mod tidy
RUN go build -o main .
CMD ["/wait-for-it.sh", "db:3306", "--", "./main"]
EXPOSE 8080
MySQLが起動するまで待機するためのスクリプト wait-for-it.sh
をコンテナにコピーし、実行可能にしています。
-
ビルドとエントリポイント
- Goアプリケーションをビルドして実行可能ファイルを生成します。
- 起動時に
wait-for-it.sh
を使用してMySQLの起動完了を待機し、アプリケーションを起動します。
-
ポート8080の開放
アプリケーションで使用するポート8080を公開します。
3. docker-compose.yml
このファイルでは、サービス構成の定義や環境変数の設定など、GoアプリケーションとMySQLデータベースの連携に必要な設定を記述しています。
version: "3.8"
services:
app:
build:
context: .
ports:
- "8080:8080"
container_name: go_app
depends_on:
- db
environment:
DB_USER: root
DB_PASSWORD: password
DB_HOST: db
DB_PORT: 3306
DB_NAME: testdb
db:
image: mysql:8.0
container_name: mysql_db
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: testdb
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
-
サービス構成の定義
- app: Goアプリケーションをビルドして実行するサービス。
- db: MySQLデータベースをホストするサービス。
-
ポートの設定
- app: ホストの8080ポートをコンテナの8080ポートにマッピング。
- db: ホストの3306ポートをコンテナの3306ポートにマッピング。
-
環境変数の設定
- app: データベース接続情報(ユーザー名、パスワード、ホスト名、ポート番号、データベース名)を指定。
- db: MySQLのルートパスワードと初期データベース名を指定。
-
依存関係の設定
-
depends_on
を使用して、app が db に依存していることを定義。
-
-
ボリュームの永続化
-
db_data
ボリュームを使用して、MySQLデータを永続化。
-
4. wait-for-it スクリプト
wait-for-it
スクリプトを使用して、GoアプリケーションがMySQLの準備完了を待機するように設定します。
手順
プロジェクトディレクトリに wait-for-it.sh
をダウンロードし、実行可能にします。
curl -o wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
chmod +x wait-for-it.sh
5. 必要な依存関係を追加
MySQLドライバーをインストールするために、以下のコマンドをプロジェクトディレクトリで実行します。
go mod init my-go-app
go get -u github.com/go-sql-driver/mysql
6. 起動手順
Docker Composeを使用して、アプリケーションをビルドし起動します。
docker compose up --build
実際にブラウザでアクセスしてみた
ブラウザで確認 ブラウザで http://localhost:8080
にアクセスし、「Hello, World! Database connection is working!
」が表示されることを確認します。
表示例
また、ターミナル上では以下のように、go_app | Server is running on port 8080...
と出力され、正常に起動していることが確認できます。
ターミナル表示例
まとめ
ここまで読んでいただきありがとうございました!
今回は、最近興味を持ったGo言語を学ぶ中で、MySQLコンテナとの連携に挑戦し、技術検証を行いました。
エラー修正や調査に少し時間がかかりましたが、最終的に自己解決し、ブラウザ上でアプリケーションを動かすことができ、とても満足しています。
次回の記事では、立ち上げたMySQLコンテナにログインし、データベースの中身を確認する方法について詳しくご紹介します。