はじめに
この記事では、docker×go環境で自作パッケージとして切り出した関数を実行する方法を書いています。
別パッケージの関数がうまく読み込めず苦戦した(go modulesを理解できていなかった。。)ので、備忘録的にまとめました。
前提
- Dockerがインストールされていること。
実行環境
- macOS Catalina: 10.15.4
- docker version: 19.03.13
目次
- dockerによる環境構築
- main.goファイルを作成
- シンプルなプログラムを実行
- サブパッケージに関数を切り出す
- 切り出した関数をmain.goで読み込んでプログラム実行
最終的なディレクトリ構造とゴール
.
|--Dockerfile
|--docker-compose.yml
|--go.mod
|--main.go
|--pokemon
| |--houen.go
| |--kantou.go
| |--secret.go
上記、pokemonパッケージ下の各ファイルの関数をmain.goでインポートして実行するところまで。
dockerによる環境構築
まずは、dockerを使ってGoのプログラム実行環境を構築していきます。
① ルートディレクトリと各種dockerファイルを作成します。
2022projects % mkdir go-sample && cd $_
go-sample % touch {Dockerfile,docker-compose.yml}
② Dockerfileを書いていきます。
# Dockerイメージ指定 Doc: https://hub.docker.com/_/golang
FROM golang:1.18.1-alpine
# 作業ディレクトリ作成
RUN mkdir /go/src/app
# コンテナログイン時のディレクトリ指定
WORKDIR /go/src/app
# ホストのファイルをコンテナの作業ディレクトリに移行
ADD . /go/src/app
③docker-compose.ymlを書いていきます。
# composeファイルのバージョン指定 doc: https://docs.docker.jp/compose/compose-file.html
version: "3"
services:
app: # service名
build: . # ビルド時に参照するDockerファイル指定
tty: true # コンテナの正常終了を防ぐ(≒ 永続化)
volumes:
# マウントするディレクトリ指定(ホストディレクトリ : コンテナディレクトリ)
- .:/go/src/app
④コンテナを作成します。
# コンテナ作成
go-sample % docker-compose build
# 作成されたコンテナの確認
go-sample % docker ps
# 作成されたイメージの確認
go-sample % docker images
# docker psの例
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23a42594db7c7e go-demo_app "bash" 2 days ago Up About an hour go-demo_app_1
# docker imagesの例
REPOSITORY TAG IMAGE ID CREATED SIZE
go-sample_app latest c733dc31a8b3a About a minute ago 329MB
golang 1.18.1-alpine cd6f429de0e957 2 days ago 329MB
Goファイルを作成してプログラムを実行してみる
次は、go言語でシンプルな文字列を返すプログラムを書いてみます。
main.goファイルを作成。
go-sample % touch main.go
main.goファイルにて、文字列を返すプログラムを書いてみる。
package main
import (
"fmt"
)
func main() {
fmt.Println("Hey Siri!")
}
メモ
- Goでは、パッケージという単位でコードを管理する。
- 異なるパッケージの関数を利用する場合は、importが必要。
- 外部パッケージの関数を利用する際は、
パッケージ名.関数名
として明示的に指定。 - ↑でいう
fmt
など、Goの標準ライブラリに関してはパッケージ名をimportするだけで、簡単にパッケージ内の関数を利用できる。
※ Goの標準パッケージ一覧
https://xn--go-hh0g6u.com/pkg/
main.goファイルを実行してみる。
go-sample % docker-compose up -d
go-sample % docker-compose exec app go run main.go
############### 出力結果 ###############
Hey Siri!
出力に成功しました!
メモ
go run
: コンパイルとプログラムの実行を行ってくれる。
go build
: コンパイルを行う。
自作パッケージの作成
main.goファイル単体でのプログラム実行ができたので、次は自作パッケージを作成→main.goで読み込ませて実行できるようにします。
go-sample % mkdir pokemon
go-sample % touch {pokemon/kantou.go,pokemon/houen.go,pokemon/secret.go}
作成した各goファイルにパッケージ名と関数を書いていく。
package pokemon
func KantouBigThreePokemon() string {
return "カントー地方の御三家: フシギダネ!・ヒトカゲ!・ゼニガメ!"
}
package pokemon
func HouenBigThreePokemon() string {
return "ホウエン地方の御三家: キモリ!・アチャモ!・ミズゴロウ!"
}
package pokemon
func SecretBigThreePokemon() string {
return "???地方の御三家: ニャオハ!?・ホゲータ!?・クワッス!?????"
}
Golangは静的型付け言語のため、戻り値の型を指定する必要がある(今回の例だと、文字列なのでstringを指定)。これを怠ると、下記のようにコンパイル時にエラーが返ってきてしまうので注意。
go-sample % docker-compose exec app go run main.go
pokemon/houen.go:4:9: too many return values
have (string)
want ()
自作パッケージファイルが作成できたら、ファイルをimportするためにmain.goを修正する。
package main
import (
"fmt"
"./pokemon"
)
func main() {
fmt.Println(pokemon.KantouBigThreePokemon())
fmt.Println(pokemon.HouenBigThreePokemon())
fmt.Println(pokemon.SecretBigThreePokemon())
}
importの記述ができたので、早速main.goファイルを読み込んで見るが...
go-sample % docker-compose exec app go run main.go
main.go:5:2: package go-demo/pokemon is not in GOROOT (/usr/local/go/src/go-demo/pokemon)
上述のようなエラーでうまくプログラムを実行できない。
結論、go modulesを使って自作パッケージを読み込ませる必要がありました。
メモ
go modulesとは、Goパッケージの集合体であるモジュールを管理してくれるシステム。
このgo modulesが提供するgo.modファイルに、「モジュールのインポートパスとバージョン情報」を記述する。
先ほど失敗した自作パッケージの読み込みは、このモジュールのインポートパスを使うことで解消できます。
go.modファイルを作成して自作パッケージの関数を実行する
ということで、自作パッケージを読み込むためにgo.modファイルを作成します。
# go mod init モジュール名
go-sample % docker-compose exec app go mod init go-sample
すると、下記のようなファイルが出来上がります。
module go-sample
go 1.18
このモジュール名を使って、main.goファイルの自作モジュールをimportする記述を修正
package main
import (
"fmt"
// ↓ ここをモジュール名/パッケージ名に変更 | 相対パスは使えないので注意が必要。 ↓
"go-sample/pokemon"
)
func main() {
fmt.Println(pokemon.KantouBigThreePokemon())
fmt.Println(pokemon.HouenBigThreePokemon())
fmt.Println(pokemon.SecretBigThreePokemon())
}
改めて、Goプログラムを実行する。
go-sample % docker-compose exec app go run main.go
############### 出力結果 ###############
カントー地方の御三家: フシギダネ!・ヒトカゲ!・ゼニガメ!
ホウエン地方の御三家: キモリ!・アチャモ!・ミズゴロウ!
???地方の御三家: ニャオハ!?・ホゲータ!?・クワッス!????
無事、成功しました!
参考記事
【Go言語】GOPATHの外に作ったプロジェクトでサブパッケージをインポートする
一応、githubにもソースコードを公開しているので良かったらご確認ください。
完