オープンソース版Droneで、自作のDocker imageを使ってビルドを行う方法

オープンソース版Droneで、自作のDocker imageを使ってビルドを行ってみましたので、その方法・手順を共有します。

今回は、Go 1.2とMongoDB 2.4がインストールされたDocker imageを作成し、DroneではそのDocker imageを使ってビルドを行います。

なお、Droneのservicesという機能を使うことでビルド時にデータベースを使用できるため、通常は、今回のようなMongoDBがインストールされたDocker imageを使う必要はありません。今回は練習としてこのようなDocker imageを作成しています。ただし、Droneのservicesでは、現在、データベースのバージョンを指定することができませんので、もしデータベースの特定のバージョンでビルドを行いたい場合は、今回のように、ビルド時に使用するデータベースをインストールしたDocker imageを使う必要があります。

Docker imageの作成

以下の内容が記載されたDockerfileを作成します。

# Go 1.2 and MongoDB 2.4
#
# VERSION 1.0

# Use the ubuntu base image provided by dotColud.
FROM ubuntu

MAINTAINER Keiji Yoshida, yoshida.keiji.84@gmail.com

# Update the package lists.
RUN apt-get update

# Install curl and git.
RUN apt-get install -y curl git

# Install Go 1.2.
RUN curl -o /usr/local/go1.2.linux-amd64.tar.gz https://go.googlecode.com/files/go1.2.linux-amd64.tar.gz
RUN tar -C /usr/local -xzf /usr/local/go1.2.linux-amd64.tar.gz
RUN rm /usr/local/go1.2.linux-amd64.tar.gz
ENV PATH $PATH:/usr/local/go/bin

# Install MongoDB 2.4.9.
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list
RUN apt-get update
RUN apt-get install -y mongodb-10gen=2.4.9

# Install Bazaar.
RUN echo "deb http://ppa.launchpad.net/bzr/ppa/ubuntu precise main" >> /etc/apt/sources.list
RUN echo "deb-src http://ppa.launchpad.net/bzr/ppa/ubuntu precise main" >> /etc/apt/sources.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D702BF6B8C6C1EFD
RUN apt-get update
RUN apt-get install -y bzr

※このDockerfileはこちらのGitHubリポジトリより取得頂けます。

以下のコマンドを実行し、作成したDockerfileをもとにDocker imageを作成します。

$ docker build .
Uploading context 40.78 MB
Uploading context
Step 0 : FROM ubuntu
(中略)
Successfully built 36a40c0fe330

以下のコマンドを実行し、作成したDocker imageにタグ付けを行います。今回は、作成したDocker imageにyosssi/go-mongoというリポジトリ名を設定し、1.2-2.4というタグを設定します。

$ docker tag 36a40c0fe330 yosssi/go-mongo:1.2-2.4

以下のコマンドを実行し、作成したDocker imageをDocker公式レジストリへアップロードします。

$ docker push yosssi/go-mongo

Docker Indexの自分のアカウントページで、アップロードしたDocker imageが表示されていることを確認します。

f:id:kysd:20140210024058p:plain

※今回私が作成したDocker imageは、こちらのDocker Indexのページにて内容をご確認頂けます。

プロジェクトの作成

ビルドを行うプロジェクトを作成します。今回は、MongoDBを使用する以下のプロジェクトを用意しました。

yosssi/drone-test-custom-docker-image

mongo.go

package mongo

import (
    "labix.org/v2/mgo"
    "labix.org/v2/mgo/bson"
)

type User struct {
    Name string `bson:"name"`
    Age  int    `bson:"age"`
}

func Find(name string) (*User, error) {
    session, err := mgo.Dial("localhost")
    if err != nil {
        return nil, err
    }
    defer session.Close()
    session.SetMode(mgo.Monotonic, true)
    c := session.DB("droneTest").C("users")
    var user User
    err = c.Find(bson.M{"name": name}).One(&user)
    if err != nil {
        return nil, err
    }
    return &user, nil
}

mongo_test.go

package mongo

import (
    "fmt"
    "labix.org/v2/mgo"
    "testing"
)

var (
    taro   = &User{Name: "Taro", Age: 20}
    hanako = &User{Name: "Hanako", Age: 22}
)

// テストデータを投入
func init() {
    session, err := mgo.Dial("localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    session.SetMode(mgo.Monotonic, true)
    c := session.DB("droneTest").C("users")
    c.DropCollection()
    err = c.Insert(taro)
    if err != nil {
        panic(err)
    }
    err = c.Insert(hanako)
    if err != nil {
        panic(err)
    }
}

// Find関数をテスト
func TestFind(t *testing.T) {
    // User(Nmae="Taro")を抽出
    user, err := Find(taro.Name)
    if err != nil {
        t.Error(err)
    }
    if user.Name != taro.Name || user.Age != taro.Age {
        t.Error(fmt.Sprintf("検索結果が不正です。[期待値: %+v][実際: %+v]", taro, user))
    }

    // 存在しないUserを抽出
    user, err = Find("X")
    if err == nil || err.Error() != "not found" {
        t.Error("検索結果が不正です。検索結果が存在します。")
    }
}

Droneへのリポジトリの登録

画面右上のNew Repositoryボタンをクリックし、今回ビルドを行うGitHubリポジトリをDroneへ登録します。

f:id:kysd:20140210025358p:plain

.drone.ymlの作成

以下の.drone.ymlを作成し、GitHubリポジトリへプッシュします。

image: yosssi/go-mongo:1.2-2.4
env:
  - GOPATH=/var/cache/drone
script:
  - LC_ALL=C mongod --dbpath /var/lib/mongodb --logpath /var/log/mongodb/mongo.log &
  - sleep 10
  - go get labix.org/v2/mgo
  - go get labix.org/v2/mgo/bson
  - go build
  - go test -cover -v

imageに、今回作成したDocker imageのリポジトリ名:タグを記載します。scriptの先頭行でMongoDBを起動しています。

ビルド結果の確認

Droneのビルド結果画面を開き、ビルドが正常終了していることを確認します。

f:id:kysd:20140210025631p:plain

所感

自作Docker imageを使用することで、個々のプロダクトに合わせたビルド環境を柔軟かつ簡単に構築することができると思います。使い捨ての環境を簡単に構築できるというDockerの強み・特徴を十二分に活かした素晴らしい機能だと思います。