LoginSignup
23
25

More than 5 years have passed since last update.

情弱だがgit pushするだけで(goの)Webアプリを積んだDockerのコンテナを自動でデプロイしたい

Posted at

はじめに

以下は『なんか流行ってるみたいだし、試しにDocker使ってみたい』そんな手段の目的化メモです。

いやいや、カスな情報はいらないよ(=^・^=)
と、いう人は下記のリンクを読むと良さそうです。
http://blog.gopheracademy.com/advent-2014/easy-deployment/
http://deeeet.com/writing/2015/01/08/dockerhub-hook/

自動デプロイの流れ

以下のような感じでしょうか。

  • ローカルでgoのアプリを書く
  • リモートリポジトリにpushする
  • リポジトリ側がwebhookでデプロイ先サーバに対してPOSTを投げる
  • デプロイ先サーバはPOSTを受けてデプロイ用のシェルスクリプトを実行する
    • リポジトリからgit pullする
    • Dockerfileに基づいてdocker build
    • 起動中のコンテナをdocker kill
    • 新しいコンテナをdocker run

ローカルでgoのアプリを書く

書きましょう。

Productionモードで実行したら80ポートをみる、Developmentモードだったら9999番をみる、のような処理は追加しておくとよさそうです。

当方は標準のhttpを使ってサーバを実装してしまいました。
なので、下記のようにos.Getenv()を使って環境変数を読み込み、リッスンするポートを指定するようにしました。

env
import (
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", awesomeHandler)
    port := os.Getenv("AWESOME_PORT")
    if port == "" {
        port = ":9999"
    }
    http.ListenAndServe(port, nil)
}

イケてるWAFだったらモード切り替えあるかもしれませんね。
https://github.com/go-martini/martini#martini-env

リモートリポジトリにpushしたタイミングでwebhookを発行する

今回はbitbucketを使いました。
githubとかでもあるはず。

https://confluence.atlassian.com/display/BITBUCKET/Manage+Bitbucket+hooks
ここにかいてるPOSTってヤツを使いました。

リポジトリへのPushを検知したらhttps://"自分のドメイン"/deployを叩くように設定します。

デプロイ先のサーバでwebhookなPOSTを受け取る

bitbucketから飛んでくるPOSTを捌く必要があります。
どのように捌くのが理想形か分かりませんが、とりあえずデプロイ先のサーバにwebhookなPOSTを受け取るようにしました。

こちらを使います。
https://github.com/bketelsen/captainhook
これはgoで書かれたwebhook処理に特化したサーバです。

1エンドポイントを1つのjsonファイルで表現することができます。
公式のリポジトリに書いてるQuickStartをコピペしただけですが、こんな感じ。

endpoint.json
{
    "scripts": [
        {
            "command": "ls",
            "args": [
                "-l",
                "-a"
            ]
        },
        {
            "command": "echo",
            "args": [
            "hello"
            ]
        }
    ]
}

このようなjsonファイルを用意してcaptainhook -configdir ~/captainhook
でwebhook専用のWEBサーバが立ち上がります。
ちなみにポートはデフォルト8080です。

自分はこんな感じで動かしました。0.0.0.0指定しないと動かなかったからです。
captainhook -listen-addr=0.0.0.0:8080 -echo -configdir ~captainhook

で、このサーバに対して
curl -X POST http(s)://"自分のドメイン"/endpointってやるとhelloとか表示されるはず。

上の例ではlsechoを実行しましたが、もちろんシェルスクリプトも実行できます。

awesome.sh
{
    "scripts": [
        {
            "command": "/script/path/awesome.sh"
        }
    ]
}

で、実際に実行してるスクリプトは下記のとおり。

awesome.sh
#!/bin/bash

cd /app/path # アプリのコードが設置されているディレクトリに移動
git pull origin master # リポジトリから最新版のコードを取得(なので鍵登録は事前に必要)

docker build --tag="awesome/base:latest" . 
# アプリのコードにDockerfileを含めて、それをbuildするようにしてます

OLDPORTS=( `docker ps | tail -1 | awk '{print $1}'` ) # 起動中のコンテナのid一覧を取得

for i in ${OLDPORTS[@]}
do
    docker kill $i # 古いコンテナを消す
done

sleep 3s

docker run -d -p 80:80 -t awesome/base:latest # 新しいコンテナを実行する

これでwebhookからdockerを再起動するところまでできました。

Dockerfileのなかみ

コンテナ内で何をするかDockerfileに書きます

FROM ubuntu
MAINTAINER tokyotaro

RUN apt-get update
RUN apt-get install -y sqlite golang git gcc

RUN mkdir go
ENV GOPATH /path/go
ENV PATH /path/go/bin:$PATH

ADD . /var/www/awesome # ここでアプリのコードをコンテナ内に配置

# 必要なライブラリを導入
RUN ["go", "get", "github.com/go-gorp/gorp"] 
RUN ["go", "get", "github.com/mattn/go-sqlite3"]

# 80番ポートを開放
EXPOSE 80

WORKDIR /var/www/awesome
ENV AWESOME_PORT :80 # アプリ側でポート指定するために使う環境変数

ENTRYPOINT ["go", "run", "app.go"] 
# docker runしたときに実行される処理
# 今回はgo標準のhttpパッケージを使ったのでgo run app.goです。

なかなかカスっぽい感じですが、これでhttp(s)://"自分のドメイン"をブラウザで見ると自分のアプリが表示されるはずです。

勉強になりました、シェアさせてください。

23
25
2

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
23
25