Kitura   Swift

Docker+Swift+KituraでのHotReload開発

前回のKituraの記事で課題としていた、ファイル監視で自動的にビルド&再起動というのが実現できたのでメモ。

Docker環境について

今回もDocker関連なのでhttps://github.com/d-abe/dockersへあげています。

Dockerfile

Dockerfileはこちら。

FROM ubuntu:wily

MAINTAINER d-abe 

ENV PATH /opt/swift/usr/bin:$PATH
ENV LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH

WORKDIR /root

RUN apt-get update \
    && apt-get install -q -y nodejs npm git wget clang dh-autoreconf pkg-config libkqueue0 libkqueue-dev libbsd-dev libblocksruntime-dev libicu-dev build-essential libhttp-parser-dev libcurl4-openssl-dev libhiredis-dev \
    && rm -rf /var/lib/apt/lists/* \
    && ln -s `which nodejs` /usr/local/bin/node \
    && wget https://swift.org/builds/development/ubuntu1510/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu15.10.tar.gz \
    && tar zxf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu15.10.tar.gz \
    && mkdir -p /opt/swift \
    && mv swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu15.10/usr/ /opt/swift/ \
    && git clone https://github.com/apple/swift-corelibs-libdispatch.git \
    && cd swift-corelibs-libdispatch \
    && git submodule init && git submodule update \
    && sh ./autogen.sh \
    && ./configure --with-swift-toolchain=/opt/swift/usr --prefix=/opt/swift/usr \
    && make \
    && make install \
    && cd .. \
    && wget http://ftp.exim.org/pub/pcre/pcre2-10.20.tar.gz \
    && tar zxf pcre2-10.20.tar.gz \
    && cd pcre2-10.20 \
    && ./configure \
    && make \
    && make install \
    && npm install -g gulp \
    && mkdir /work

WORKDIR /work

COPY gulpfile.js /work/gulpfile.js
COPY build.sh /work/build.sh
COPY Makefile /work/Makefile

RUN npm install gulp gulp-process \
    && chmod +x /work/build.sh


WORKDIR /src

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

前回紹介したものに加え、task runnerとして利用するgulp関連をインストールしています。

また、Kitura 0.3.0がLinuxでビルドが通らなくて、調べたところKitura公式のDockerfileが上がっていました。その中身を見るとlibdispatcherのリポジトリが異なっていてmodulemapのコピー処理もなくなっていたので、その辺りを変更しています。

シェルスクリプトなど

entrypoint.shも変更しました。

#!/bin/bash

set -eu

if [ -z "$PROJECT_NAME" ]; then
    echo >&2 'PROJECT_NAME is not specified!'
    exit 1
fi

ln -s $(pwd)/Sources /work/Sources
ln -s $(pwd)/Tests /work/Tests
ln -s $(pwd)/Package.swift /work/Package.swift

cd /work

set +e
swift build
set -e

make
gulp watch

ローカルファイルが変更された時に反映されるように、コピーではなくシンボリックリンクを作っています。
そのため、Sources,Tests,Package.swift以外のファイルが/workに入らないので、この辺り必要なら変更しなければいけません。

最後に、gulp watchを動かしています。

gulpfile.jsはどうなっているかというと

var project = process.env.PROJECT_NAME;

var gulp = require('gulp');
var gulpProcess = require('gulp-process');
var exec = require('child_process').exec;

gulp.task('build', function(cb) {
    exec('./build.sh', function(err,stdout,stderr) {
        gulpProcess.restart('kitura');
        cb(err);
    });
});

gulp.task('watch', function(){
    gulpProcess.start('kitura','.build/debug/'+project);

    gulp.watch(['Sources/*.swift','Sources/**/*.swift'],['build']);
});

swiftファイルを監視して、変更があったら build.sh を実行し、その後.build内の実行ファイルを再起動させています。
Sources以下のswiftファイルしか見ていないので、Package.swiftも監視した方がいいかも?

build.shは、swift buildとmakeを実行しているだけです。

#!/bin/bash

swift build
make

Docker Compose

最後に、これらを実行させるためのdocker-compose.yamlを書いておきます。

kitura:
  build: ../../swift-kitura
  volumes:
    - "${ROOT_DIR}/src/kitura:/src"
  ports:
    - "8090:8090"
  working_dir: /src
  environment:
    PROJECT_NAME: kitura

実行してみる

実際に、実行してみます。

$ docker-compose up
(ずらずらと表示される)
 :
kitura_1 | Compiling Swift Module 'kitura' (1 sources)
kitura_1 | Linking Executable:  .build/debug/kitura
kitura_1 | make[1]: Leaving directory '/work'
kitura_1 | [07:18:19] Using gulpfile /work/gulpfile.js
kitura_1 | [07:18:19] Starting 'watch'...
kitura_1 | [07:18:19] Finished 'watch' after 8.65 ms

このように、ビルドが完了後 gulp watch がちゃんと実行されました。

確認してみると・・・

$ docker-machine ip default
192.168.171.148
$ curl -l http://192.168.171.148:8090
Hello, World!

このように動作が確認できました。

この状態で、main.swiftを書き換えてみます。

import KituraRouter
import KituraNet
import KituraSys

let router = Router()

router.get("/") {
request, response, next in

    response.status(HttpStatusCode.OK).send("Hello, Kitura!")

    next()
}

let server = HttpServer.listen(8090, delegate: router)
Server.run()

Hello, Kitura!にしてみました。

すると、先ほどのログが表示されているターミナルで、

kitura_1 | [07:45:12] Starting 'build'...
kitura_1 | [07:45:17] Finished 'build' after 4.56 s

と新たにログが出力されると思います。

ここで、再度動作確認します。

$ curl -l http://192.168.171.148:8090
Hello, Kitura!

無事、反映されました!!

次回はDB周りの処理をやってみたいです。

LINEで送る
Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です