IBM Cloud を利用した Go言語のアプリ開発入門（その３）


Go言語はワークスペースの単位でGOPATHを設定が必要で、コードのリポジトリは、その遥かにしたのレベルで管理することになります。従って、Go言語のコードを一つのリポジトリの階層構造の中で、管理できないという事を意味している様に思います。　それでは、依存するパッケージを集めて、設定ファイルやデータと合わせて、全体をビルドするには、どうしたら良いのでしょうか？　

２回目の学習結果を基に、もっとスマートで簡単に、Go言語のウェブ・アプリを IBM Cloud CloudFoudry アプリとして、構築してデプロイするにはどうすれば良いか、学んで見たいと思います。


## GitリポジトリとGo言語のワークスペース

Go言語はワークスペースの単位でGOPATHを設定が必要なので、複数のパッケージを統合してアプリをビルドする場合に、考慮が必要となります。 例えば、GitHubのリポジトリで管理する範囲は、ワークスペースのsrcの下の go_util や go_webserver のそれぞれのディレクトリのレベルで、独立して管理することになります。 

これらのソースからビルドされた実行モジュールは、binの下に入るため、実行モジュール、ここでは go_webserverが読取る設定ファイルなどスタティックなファイルやサンプルデータなどは、どうやって、独立性を失わず、統合的にリポジトリを管理して、デプロイできる様にしたら良いのでしょうか？

~~~
.
├── bin
│   └── go_webserver  <--- 実行形式のファイル
├── pkg
│   └── linux_amd64
│       └── github.com
│           ├── takara9
│           └── tools
├── src
│   └── github.com
│       ├── takara9
│       │   ├── go_util       <--- 一つのリポジトリ  (https://github.com/takara9/go_util)
│       │   └── go_webserver  <--- これも独立のリポジトリ (https://github.com/takara9/go_webserver)
~~~



## 複数のリポジトリを統合するアプリをどの様に？

言い方を変えると、Go言語で書かれた２つのリポジトリを利用するアプリを開発するには、どうするか？　という課題でもあります。
整理すると、以下３個のリポジトリになります。

* スタティック・コンテンツ、Cloud Foundry へデプロイするためのYAMLファイルなどのリポジトリ
* Go言語で記述したウェブサーバー、RESTサーバーのリポジトリ
* ２回目で開発した共通的な処理 go_util のリポジトリ


## いきなり結論！？

パッケージマネージャーの機能などを調べて、いろいろ試行錯誤した結果、次の２つの動作で、３つのリポジトリの独立性を失わずに、Go言語のアプリを開発できる事がわかりました。

* git clone https://github.com/takara9/go_webpages --recursive
* bx cf push



# 複数のパッケージを統合するリポジトリの作り方

## スタティックコンテンツや設定ファイルのリポジトリ作成

ワークスペース（プロジェクト）ディレクトリをつくって、移動します。

~~~
mkdir ~/go/go_webpages
cd ~/go/go_webpages
~~~

GOPATH環境変数をセットします。 

~~~
export GOPATH=`pwd`
~~~

このGOPATHのルートには、以下の静的なファイルをセットされているものとします。  これをGitHubのリポジトリに登録して、必要なモジュールを関連づけていきます。

~~~
.
├── config.json        <-- go_webserverの設定ファイル
├── manifest.yml       <-- Cloud Foundry用のYAMLファイル
├── public             <-- 公開用の任意のスタティック・コンテンツ
│   ├── gopher.png
│   ├── index.html
│   ├── style.css
│   ├── test_doc_1.html
│   └── tokyotower.jpg
└── README.md          <-- 説明資料
~~~
Go言語で書いたコードのリポジトリから、マスタープロジェクトを取得して、パッケージマネージャのgodepを取得します。
この時、マスタープロジェクトである go_webserver2の中で、go_utilが参照されていれば、一回の `go get` で一緒に取得されます。なんと便利ですよね。

## godep により依存関係を解決する情報の追加

~~~
go get github.com/takara9/go_webserver2
go get github.com/tools/godep
~~~
コマンドのサーチパスを追加しておきます。godepは $GOPATH/bin にインストールされるので、動作いない時はパスを確認して見ましょう。

上記のコマンドを実行すると、以下の様に bin, pkg, srcが作成され、必要なモジュールがインストールされます。

~~~
$ tree -L 3
.
├── bin
│   ├── godep
│   └── go_webserver2
├── config.json
├── manifest.yml
├── pkg
│   └── linux_amd64
│       └── github.com
├── public
│   ├── gopher.png  以下省略
│
├── README.md
└── src
    └── github.com
        ├── takara9
        └── tools
~~~



~~~
export PATH=$GOPATH/bin:$PATH
~~~
マスタ・プロジェクトを指定して、godepで設定やコードを取得します。取得したコードはvendorディレクトリに配置されます。そして、パッケージマネージャの定義ファイルは、Godepsに置かれます。

~~~
godep save github.com/takara9/go_webserver2
~~~

コマンド godep の実行によって、Godeps のJSON定義ファイルが作成され、vendor ディレクトリ下にソースコードがコピーされます。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/go/webapp03$ tree -L 3
.
├── bin
│   ├── godep
│   └── go_webserver2
├── config.json
├── Godeps              <--- Godeps が作成
│   ├── Godeps.json
│   └── Readme
├── manifest.yml
├── pkg
│   └── linux_amd64
│       └── github.com
├── public
│   ├── gopher.png 以下省略
│
├── README.md
├── src
│   └── github.com
│       ├── takara9
│       └── tools
└── vendor                <--  vendor が作成  srcがコピーされている
    └── github.com
        └── takara9
~~~


CloudFoundryにデプロイするために不要なというか、問題の原因となるファイルを削除しておきます。

~~~
rm -fr bin pkg src
~~~

## GitHubへの登録

gitリポジトリとして初期化します。

~~~
git init
~~~
vender のしたのgo_utilやgo_webserver2は、削除して、GitHub でサブモジュールとして登録します。

~~~
rm -fr vender/github.com/takara9/go_util
rm -fr vender/github.com/takara9/go_webserver2
~~~
GitHubのサブモジュールとして、go_webserver2 と go_util を登録します。

~~~
$ git submodule add https://github.com/takara9/go_util.git  go_util
$ git submodule add https://github.com/takara9/go_webserver2.git  go_webserver2
~~~

この状態で、`git add`、`git commit`、`git push`して、GitHubへ登録すれば完了です。


## 実行例

上記で作成したリポジトリから オプション `--recursive` を付与して、submodule も含めてローカルにコピーします。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/go$ git clone https://github.com/takara9/go_webpages --recursive
Cloning into 'go_webpages'...
remote: Counting objects: 27, done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 27 (delta 6), reused 24 (delta 3), pack-reused 0
Unpacking objects: 100% (27/27), done.
Checking connectivity... done.
Submodule 'vendor/github.com/takara9/go_util' (https://github.com/takara9/go_util.git) registered for path 'vendor/github.com/takara9/go_util'
Submodule 'vendor/github.com/takara9/go_webserver2' (https://github.com/takara9/go_webserver2.git) registered for path 'vendor/github.com/takara9/go_webserver2'
Cloning into 'vendor/github.com/takara9/go_util'...
remote: Counting objects: 16, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 16 (delta 2), reused 15 (delta 1), pack-reused 0
Unpacking objects: 100% (16/16), done.
Checking connectivity... done.
Submodule path 'vendor/github.com/takara9/go_util': checked out '38ff0221e206b57cd7ea242e4f1238fb8f613b8a'
Cloning into 'vendor/github.com/takara9/go_webserver2'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.
Checking connectivity... done.
Submodule path 'vendor/github.com/takara9/go_webserver2': checked out '25d39c2700995e71dbb9a3b9c80891cec437ffd5'
~~~


ここで、必要に応じて、YAMLファイルのホスト名が一意になる様に編集します。 そして、`bx cf push`でデプロイ開始です。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/go/go_webpages$ bx cf push
Invoking 'cf push'...

Using manifest file /home/vagrant/go/go_webpages/manifest.yml

Updating app go-webserver2 in org takara@jp.ibm.com / space dev as takara@jp.ibm.com...
OK

Using route go-webserver2.mybluemix.net
Uploading go-webserver2...
Uploading app files from: /home/vagrant/go/go_webpages
Uploading 24.5K, 23 files
Done uploading               
OK

Stopping app go-webserver2 in org takara@jp.ibm.com / space dev as takara@jp.ibm.com...
OK

Starting app go-webserver2 in org takara@jp.ibm.com / space dev as takara@jp.ibm.com...
Creating container
Successfully created container
<途中省略>
Successfully destroyed container

1 of 1 instances running

App started


OK

App go-webserver2 was started using this command `go_webserver2`

Showing health and status for app go-webserver2 in org takara@jp.ibm.com / space dev as takara@jp.ibm.com...
OK

requested state: started
instances: 1/1
usage: 128M x 1 instances
urls: go-webserver2.mybluemix.net
last uploaded: Wed Jan 17 05:06:57 UTC 2018
stack: cflinuxfs2
buildpack: https://github.com/cloudfoundry/go-buildpack.git

     state     since                    cpu    memory         disk         details
#0   running   2018-01-17 05:08:15 AM   0.0%   4.8M of 128M   9.1M of 1G
~~~

最後のstate が、running となっていれば、デプロイ成功です。 urlsにあるアドレスをブラウザからアクセスします。

https://go-webserver2.mybluemix.net/

これで、ウェブページが表示されたら、成功です。


# まとめ

個別の機能単位のgolangパッケージ、そして、アプリとして統合するリポジトリ、それらの依存関係を定義するgodepパッケージマネジャーの機能の関係が、これで全部繋がった様に思います。 

![gopher.png](https://qiita-image-store.s3.amazonaws.com/0/42829/1e547b1e-0514-5584-4ebe-cebc0ba98af9.png "gopher.png")


さらに、Dockerコンテナにして、k8sでデプロイするには、どうするんでしょうね？