LoginSignup
4
0

More than 1 year has passed since last update.

【Go(golang)×Docker】自作パッケージの関数を呼び出す方法

Last updated at Posted at 2022-04-16

はじめに

この記事では、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を書いていきます。

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を書いていきます。

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ファイルにて、文字列を返すプログラムを書いてみる。

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ファイルにパッケージ名と関数を書いていく。

pokemon/kantou.go
package pokemon

func KantouBigThreePokemon() string {
	return "カントー地方の御三家: フシギダネ!・ヒトカゲ!・ゼニガメ!"
}
pokemon/houen.go
package pokemon

func HouenBigThreePokemon() string {
	return "ホウエン地方の御三家: キモリ!・アチャモ!・ミズゴロウ!"
}
pokemon/secret.go
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

すると、下記のようなファイルが出来上がります。

go.mod
module go-sample

go 1.18

このモジュール名を使って、main.goファイルの自作モジュールをimportする記述を修正

main.go
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 のモジュール管理【バージョン 1.17 改訂版】

【Go言語】GOPATHの外に作ったプロジェクトでサブパッケージをインポートする

一応、githubにもソースコードを公開しているので良かったらご確認ください。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0