[実践編]docker-machine + さくらのクラウドでリモートdocker:ビルドサーバ作るよ編

* * * 
(前回の記事)
[docker-machine + さくらのクラウドでお手軽リモートdockerするよ](http://qiita.com/yamamoto-febc/items/4aff7472fc1ea025db0a)

(今回使うソースコード)
[github:docker-machine-sakuracloud](https://github.com/yamamoto-febc/docker-machine-sakuracloud)

## (時間がない人へ)この記事の結論

リモートDockerコンテナをビルドサーバにするには以下のようにすればOK

1. Dockerfile内で`ADD . [コンテナ内パス]`でソースコードなどをコンテナへコピー
2. `docker run` 実行時にmakeなどのビルドコマンドを指定
3. ビルド後に`docker cp`コマンドで成果物をローカルPCにコピー

* * * 


## docker-machine-sakuracloudをバージョンアップした

docker-machineからさくらのクラウド上の仮想サーバを使えるようにするプラグイン
[docker-machine-sakuracloud](https://github.com/yamamoto-febc/docker-machine-sakuracloud)をv0.0.3へバージョンアップしました。

今回のバージョンから、

 1. docker-machineでさくらのクラウド上にサーバを作り、
 2. そのサーバ上でリモートDockerコンテナを動かして、
 3. 手元のPCにあるソースコードをビルド

が行えるようになりました。
ビルドシステムは親元であるdocker-machineを参考にしています。

docker-machine-sakuracloud自身もこの方法、いわゆるセルフホスティング?というやつをやってます。
本記事タイトルの「ビルドサーバ作るよ」はこの3手順で終わっちゃいます。

、、、が、これだけだと「じゃあ自分のプロジェクトではどうすりゃいいのよ！？」という声が聞こえそうですので、以下でdocker-machine-sakuracloudで実際にビルドをしてみながら仕組みを解説していこうかと思います。


## docker-machine-sakuracloudをdocker上でビルドしてみる

docker-machine-sakuracloudをdocker上でビルドするには以下の環境が必要です。
(詳細は[コントリビューションガイド](https://github.com/yamamoto-febc/docker-machine-sakuracloud/blob/master/CONTRIBUTING.ja.md)を参照ください。)

 - dockerコマンド([docker-toolbox](https://www.docker.com/docker-toolbox)をインストールしておけばOK)
 - makeコマンド
 - bash

なお、windowsでdocker-toolboxをインストールした際に一緒にインストールされる
MinGWではmakeコマンドが使えないため別途msys2などmakeできる環境を用意しておきます。


## 下準備

 - [前回の記事](http://qiita.com/yamamoto-febc/items/4aff7472fc1ea025db0a)を参考にdocker-machine-sakuracloudを使えるようにしておいてください
 - サーバ作成時のコマンド入力を楽にするために以下のように環境変数を設定しておきます。

```bash
$ export SAKURACLOUD_ACCESS_TOKEN=[さくらのクラウドのアクセストークン]
$ export SAKURACLOUD_ACCESS_TOKEN_SECRET=[アクセストークンシークレット]
```

これらの環境変数を設定しておくことで`docker-machine create`時に
トークンとシークレットの入力を省略できます。

## ソース取得からビルドまでの流れ

1. さくらのクラウド上にサーバをつくる([こちら](http://qiita.com/yamamoto-febc/items/4aff7472fc1ea025db0a)を参考に)
2. githubからソース一式を取得
3. makeする時にDockerコンテナを使うように環境変数$USE_CONTAINERを設定
4. make build実行

これだけです。以下に実行例を示します。

### 1. さくらのクラウド上にサーバをつくり、dockerから使えるようにする

```bash
$ docker-machine create -d sakuracloud sakura-dev
$ eval "$(docer-machine env sakura-dev)"
```

### 2. githubからソース取得

```bash
$ git clone https://github.com/yamamoto-febc/docker-machine-sakuracloud.git
$ cd docker-machine-sakuracloud
```

### 3. make時にDockerコンテナを使うように環境変数でフラグを立てておく

```bash
$ export USE_CONTAINER=true
```

### 4. ビルド実施
```bash
$ make build
$ ls bin/  # docker-machine-driver-sakuracloudバイナリができてるよ！
```


あら不思議、dockerコンテナはさくらのクラウド上にあるはずなのに
ローカルPCのソースがGoでコンパイルされて`カレントディレクトリ/bin`に出力されています。


## どうやってリモートでビルドしてるの？

ポイントは以下2点です。

1. 環境変数`USE_CONTAINER`でローカル/リモートどちらでの処理か判定
2. リモートでの処理の場合はdockerコマンドでリモートサーバ上で処理

dockerコマンドを実行している箇所を見てみましょう。

#### script/build_in_container.sh(抜粋)
```bash 
#!/bin/bash

#〜中略〜

# 1. カレントディレクトリでDockerイメージのビルド
docker build -t $DOCKER_IMAGE_NAME .

# 2. ビルドしたイメージからコンテナ実行
docker run --name $DOCKER_CONTAINER_NAME \
  -e DEBUG \
  # 〜中略:各種環境変数の設定〜 
  $DOCKER_IMAGE_NAME \
  make "$@"

#〜中略〜

# 3. makeターゲットが"build"を含む場合コンテナからローカルPCへディレクトリコピー
if [[ "$@" == *"build"* ]]; then
  docker cp $DOCKER_CONTAINER_NAME:/go/src/github.com/yamamoto-febc/docker-machine-sakuracloud/bin bin
fi

```

やっていることは、

  1. カレントディレクトリの`Dockerfile`を使ってDockerイメージをビルド
  2. ビルドしたイメージからDockerコンテナを実行:環境変数各種を設定しmakeを実行させる
  3. makeのターゲットが"build"を含む場合はbinディレクトリをDockerコンテナからローカルPCへコピー 

ビルド後にローカルPCのbinディレクトリにバイナリが格納されたのは3.の処理のおかげですね！
`docker cp`でリモートサーバ上のDockerコンテナとのファイルのやり取りが可能になります。

参考までに`docker cp`のヘルプを記載しておきます。

```bash
$ docker help cp

  Usage:	docker cp [OPTIONS] CONTAINER:PATH LOCALPATH|-
           docker cp [OPTIONS] LOCALPATH|- CONTAINER:PATH

  Copy files/folders between a container and your host.
  Use '-' as the source to read a tar archive from stdin
  and extract it to a directory destination in a container.
  Use '-' as the destination to stream a tar archive of a
  container source to stdout.

```

ではローカルPCにあるソースコードはどうやってリモートサーバに送られているのでしょうか?

今度はDockerfileを見てみましょう。

#### Dockerfile(抜粋)
```Dockerfile
# 1. ベースイメージを指定
FROM golang:1.5.1

# 2. ビルドに必要なライブラリ類の取得
RUN go get  github.com/golang/lint/golint \
# 〜中略〜

# 3. コンテナ内でmakeを実行する際の作業ディレクトリを指定
WORKDIR /go/src/github.com/yamamoto-febc/docker-machine-sakuracloud

# 4. !カレントディレクトリをコンテナ内にコピー!
ADD . /go/src/github.com/yamamoto-febc/docker-machine-sakuracloud
```

このDockerコンテナ内では$GOPATHが`/go`に設定されているため、
それに合わせたソース配置にし、カレントディレクトリの内容、つまりソースコードをコピーしています。

これでビルドの流れが追えましたね。


## まとめ

まとめると、リモートDockerコンテナでビルドするには

1. Dockerfile内で`ADD . [コンテナ内パス]`でソースコードなどをコンテナへコピー
2. `docker run` 実行時にmakeなどのビルドコマンドを指定
3. ビルド後に`docker cp`コマンドで成果物をローカルPCにコピー

を行えば良いです。

私の開発環境がOSXであるためmakeを使いましたが、dockerコンテナ上で実行できれば
バッチでもなんでも構いませんので色々応用できますね!

以上です。

*11/15 コマンド誤りを修正*
修正前：

```bash
$ cd docker-machine-sakuracloud.git
```

修正後：

```bash
$ cd docker-machine-sakuracloud
```