dockerとjenkinsを連携させたい(けどまだうまく行っていない)

やりたいこと

BitbucketのPrivate RepoにpushしたらJenkinsサーバがコンテナ内でテストする

やったこと

FROM centos
                                                                                                                                                                                       
# base package
RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
RUN yum update -y
RUN yum install -y passwd sudo gcc gcc-c++ make git openssl-devel zlib-devel bzip2 bzip2-devel libevent-devel openssh openssh-server openssh-clients readline-devel tar expat-devel

# execution user
RUN useradd perl_user
RUN passwd -f -u perl_user

# ssh config
RUN mkdir -p /home/perl_user/.ssh
ADD ./id_dsa /home/perl_user/.ssh/
RUN printf "Host bitbucket.org\n  StrictHostKeyChecking no\n  IdentityFile /home/perl_user/.ssh/id_dsa\n" > /home/perl_user/.ssh/config
RUN chown -R perl_user /home/perl_user/.ssh; chmod 700 /home/perl_user/.ssh; chmod 600 /home/perl_user/.ssh/id_dsa; chmod 600 /home/perl_user/.ssh/config
RUN sed -ri 's/UsePAM yes/#UsePAM yes/g' /etc/ssh/sshd_config
RUN sed -ri 's/#UsePAM no/UsePAM no/g' /etc/ssh/sshd_config

# sudoers
RUN echo "perl_user ALL=(ALL) ALL" >> /etc/sudoers.d/perl_user
RUN chmod 440 /etc/sudoers.d/perl_user

# perl
USER perl_user
WORKDIR /home/perl_user
RUN git clone git://github.com/tokuhirom/plenv.git .plenv
RUN git clone git://github.com/tokuhirom/Perl-Build.git .plenv/plugins/perl-build/
RUN echo 'export PLENV_ROOT="${HOME}/.plenv"' >> .bash_profile
RUN echo 'export PATH="${PLENV_ROOT}/bin:${PATH}"' >> .bash_profile
RUN echo 'eval "$(plenv init -)"' >> .bash_profile
ENV PLENV_ROOT /home/perl_user/.plenv
ENV PATH ${PLENV_ROOT}/bin:${PATH}
RUN plenv install 5.18.2
RUN plenv global 5.18.2
ENV HOME /home/perl_user
RUN plenv exec curl https://raw.githubusercontent.com/miyagawa/cpanminus/master/cpanm | perl - App::cpanminus
RUN plenv exec cpanm Carton; plenv rehash

# output dir
USER root
WORKDIR /root
RUN mkdir /workspace; chown perl_user /workspace; chmod 700 /workspace

# script
ADD ./jenkins.sh /root/

# sshd
RUN /etc/init.d/sshd start
RUN /etc/init.d/sshd stop

EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]

使い方

1. 上をDockerfileとして保存
2. Private Repositoryにアクセスできるキーペアを作成し、id_dsaという名前でDockerfileと同じディレクトリに配置
3. 以下のコードをjenkins.shとか適当な名前で保存し、Dockerfileと同じディレクトリに配置

#!/bin/bash

# Description
## このスクリプトはCI用コンテナ内に埋め込まれ、docker runで実行される。
## コンテナは、plenv, perl, cpanmとCartonが利用可能な状態になっている。
## ソースコードをデプロイし、依存するCPANモジュールをインストールし、テストを実行する。
## テスト結果はJUnit XML Reportファイルとして/workspece に出力される。
## テスト終了後、Jenkinsの設定によってコンテナは破棄される。

# Requirements
## 正常に動作するには、ブランチ名とプロジェクトディレクトリ名が一致している必要がある。
## docker build時にコピーされる秘密鍵によってremote repositoryにアクセスできる必要がある。
## テスト結果を取り出すため、docker run時にjenkinsの $WORKSPACE が /workspece としてコンテナにマウントされる必要がある。
## このスクリプト自体には冪等性が無いため、テスト実行毎にコンテナは破棄される必要がある。

# Examples
## sudo docker run -rm -t -i \
## -v /home/vagrant/workspace:/workspace \
## saisa6153/perl518 sh /root/jenkins.sh \
## -b 3_hoge_fuga -r 9e1a510 -o result_sample

# Options
## -r リビジョン
### ビルド対象のコミットのSHA値
### $GIT_COMMIT を渡す
### この値を見てコンテナ内からcloneする

## -b ブランチ名
### ビルド対象のブランチ名
### $GIT_BRANCH を渡す

## -o 出力ファイル名
### junit xml reportファイルの名前。.xmlが付与される
### $BUILD_TAG や $EXECUTOR_NUMBER など一意な値を渡す

CMDNAME=`basename $0`
REPO_NAME="jenkinstest"
REPO_URL='git@bitbucket.org:saisa6153/jenkinstest.git'
USER_NAME='perl_user'

# オプションの解析
while getopts r:b:o: OPT
do
    case $OPT in
        "r" ) FLG_REV="TRUE" ; VAL_REV="$OPTARG" ;;
        "b" ) FLG_BRC="TRUE" ; VAL_BRC="$OPTARG" ;;
        "o" ) FLG_OUT="TRUE" ; VAL_OUT="$OPTARG" ;;
        * ) echo "Usage: $CMDNAME [-b BRANCH] [-r GIT_COMMIT] [-o OUTPUT_FILENAME]" 1>&2
            exit 1 ;;
    esac
done

# デプロイとテスト実行
if [ "$FLG_REV" = "TRUE" ] && [ "$FLG_BRC" = "TRUE" ] && [ "$FLG_OUT" = "TRUE" ]; then
    RESULT_FILE="/workspace/$VAL_OUT.xml"
    TEST_ROOT="/home/$USER_NAME/$REPO_NAME/tddbc/$VAL_BRC"

    su -l $USER_NAME -c "cd /home/$USER_NAME &&  git clone -b $VAL_BRC $REPO_URL $REPO_NAME"
    su -l $USER_NAME -c "cd /home/$USER_NAME/$REPO_NAME && git checkout $VAL_REV"
    su -l $USER_NAME -c "cd $TEST_ROOT && plenv exec carton install"
    su -l $USER_NAME -c "export JUNIT_OUTPUT_FILE=$RESULT_FILE && cd $TEST_ROOT && plenv exec carton exec prove -lv --harness TAP::Harness::JUnit"
else
    echo "ERROR: requiring [-b BRANCH] && [-r GIT_COMMIT]" 1>&2
    exit 1
fi

4. docker build -t saisa6153/perl518 .
5. 適宜Jenkinsサーバを設定(sshとかproxyとか)
6. Jenkinsではbitbucketにhookして以下のスクリプトを実行するようにしたい

sudo docker run -rm -t -i -v $WORKSPACE:/workspace saisa6153/perl518 sh /root/jenkins.sh -b $GIT_BRANCH -r $GIT_COMMIT -o $BUILD_TAG

現時点での問題点

1. docker buildが失敗することがある。そして再現性に乏しい。(メモリ不足でcpanmを入れれないとかdownload.fedoraproject.orgを解決できないとかいろいろ)
仮想マシンにDockerとかをansibleで入れて作業していたんですが、最初のProvisioning後にOSを再起動したら大丈夫でした。cpanmもcurl使う方法でいけました。
2. テスト結果を取り出すためにマウントしたworkspaceの権限周りが原因らしく、JENKINS_ROOTにファイルを書き出せないとかなんとか
なぜか突然成功しました
3. ビルドの実行が非常に遅い(毎回carton installしては実行後に破棄しているため)
4. docker run -rmが非推奨らしいが、実行後確実にコンテナを削除する方法がよくわからない(disk fullとかよく噂を聞く)

参考
Perlの実行環境の入っているDockerイメージを作る - valencia日誌
仮想環境構築に docker を使う - apatheia.info