前提

Jenkins を動かす環境

  • Jenkins のマスター環境もスレーブ環境も Docker コンテナで起動する
  • Docker を動かすホストの OS は Ubuntu 16.04

Python の unittest

  • Python は pyenv を介して Python 3.6.4 を利用する
  • 以下のようなコードとテストコードを用意した
# sample.py
def foo():
   return True

def bar():
   return True
   
# tests/test_sample.py
import unittest
import sample

class SampleTest(unittest.TestCase):

    def test_foo(self):
        self.assertTrue(sample.foo())

    def test_bar(self):
        self.assertTrue(sample.bar()

以下のように実行すると, テストが走る.

$ python -m unittest tests.test_sample
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

尚, これらのコードは Backlog Git にホストする.

Jenkins のコンテナの起動と初期設定

起動

以下を実行して, Jenkins コンテナを起動する.

mkdir -p ~/sandbox/jenkins/jenkins_home
cd ~/sandbox/jenkins/jenkins_home
docker run --name=jenkins -d -p 8080:8080 -p 50000:50000 -v $(pwd):/var/jenkins_home jenkins/jenkins:lts

起動したら, 初期設定を進める.

初期設定

以下のような設定を行った.

  • 認証情報
  • プラグインのインストール (今回は Backlog プラグインと pyenv プラグインをインストールした)

プロジェクトの設定

プロジェクトは以下のような項目の設定を行った.

  • General
    • プロジェクト名
    • 実行するノードを制限 (後述)
  • ソースコード管理
    • リポジトリ URL (今回は Backlog Git を利用した)
    • 認証情報 (Backlog Git の認証情報を設定)
    • ブランチ指定子 (全てのブランチを対象とする為, ** とした)
  • ビルド環境
    • pyenv build wrapper にチェック
    • The Python version に 3.6.4 を入力
  • ビルド
    • シェルスクリプトに python -m unittest tests.test_sample を入力

スレーブ環境の準備

スレーブ環境の前提

  • SSH ログイン出来る状態にしておく
  • jenkins ユーザーを作成して, マスターから SSH ログイン出来る状態にしておく (今回はパスワード認証, パスワードベタ書き)
  • Java 環境を用意してエージェントプログラム slave.jar が利用出来る状態にしておく
  • その他, ビルドに必要なパッケージを用意しておく (今回は Python インストールに必要なパッケージをインストールしておく)

最終的に以下のような Dockerfile を用意した.

FROM ubuntu:16.04
#
RUN apt-get update
RUN apt-get -y install sudo openssh-server openjdk-8-jdk git gcc make openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev
#
RUN mkdir -p /var/run/sshd
RUN useradd -d /home/jenkins -m -s /bin/bash jenkins
RUN echo jenkins:your_password | chpasswd
RUN echo 'jenkins ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
#
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]

以下のようにビルドしてランしておく.

docker build -t jenkins-slave .
docker run --name=jenkins-slave -t -d -p 22:22 jenkins-slave

スレーブの追加

[Jenkinsの管理] > [ノードの管理] にて, [新規ノード作成] をクリックして, まずは以下のように設定.

  • ノード名
  • Permanent Agent にチェック

更に以下のパラメータを設定する.

  • リモートFSルート (スレーブに作成した jenkins ユーザーのホームディレクトリ /home/jenkins を指定)
  • 起動方法 (「SSH 経由でUnixマシンのスレーブエージェント」を指定)
    • ホスト (コンテナの IP アドレスを入力)
    • 認証情報 (スレーブに作成した jenkins ユーザーのパスワードを事前に Jenkins の認証情報に定義しておくと良いかなー)
    • Host Key Verification Strategy (Not Verifying Verification Strategy を指定)

正常にスレーブの追加が行われると, 以下のようにログが出力される.

[03/18/18 13:41:42] [SSH] Opening SSH connection to xxx.xxx.xxx.xxx:22.
[03/18/18 13:41:42] [SSH] WARNING: SSH Host Keys are not being verified. Man-in-the-middle attacks may be possible against this connection.
[03/18/18 13:41:43] [SSH] Authentication successful.
[03/18/18 13:41:43] [SSH] The remote user's environment is:
BASH=/bin/bash
BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_EXECUTION_STRING=set
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='4.3.48(1)-release'
DIRSTACK=()
EUID=1000
GROUPS=()
HOME=/home/jenkins
HOSTNAME=030406dab1e6
HOSTTYPE=x86_64
IFS=$' \t\n'
LOGNAME=jenkins
MACHTYPE=x86_64-pc-linux-gnu
MAIL=/var/mail/jenkins
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PIPESTATUS=([0]="0")
PPID=36
PS4='+ '
PWD=/home/jenkins
SHELL=/bin/bash
SHELLOPTS=braceexpand:hashall:interactive-comments
SHLVL=1
SSH_CLIENT='172.17.0.2 59868 22'
SSH_CONNECTION='172.17.0.2 59868 xxx.xxx.xxx.xxx 22'
TERM=dumb
UID=1000
USER=jenkins
_=']'
[03/18/18 13:41:43] [SSH] Checking java version of java
[03/18/18 13:41:43] [SSH] java -version returned 1.8.0_151.
[03/18/18 13:41:43] [SSH] Starting sftp client.
[03/18/18 13:41:43] [SSH] Copying latest slave.jar...
[03/18/18 13:41:43] [SSH] Copied 762,466 bytes.
Expanded the channel window size to 4MB
[03/18/18 13:41:43] [SSH] Starting slave process: cd "/home/jenkins" && java  -jar slave.jar
<===[JENKINS REMOTING CAPACITY]===>channel started
Remoting version: 3.17
This is a Unix agent
Evacuated stdout
Agent successfully connected and online

プロジェクトでスレーブを利用するように設定

プロジェクトの設定に戻って, 以下の設定を行う.

  • General
    • 実行するノードを制限
      • ラベル式 (追加したスレーブの名前を入力)

ビルド

後はプロジェクトのビルドボタンをポチッとするだけで, 以下のようにビルドが実行される.

Started by user xxxxxxxxxxxxx
Building remotely on jenkins-slave in workspace /home/jenkins/workspace/my-project
 > git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 > git config remote.origin.url https://xxxxxxxxxx.backlog.jp/git/FAM/my-project.git # timeout=10
Fetching upstream changes from https://xxxxxxxxxx.backlog.jp/git/FAM/my-project.git
 > git --version # timeout=10
using GIT_ASKPASS to set credentials 
 > git fetch --tags --progress https://xxxxxxxxxx.backlog.jp/git/FAM/my-project.git +refs/heads/*:refs/remotes/origin/*
Seen branch in repository origin/master
Seen 1 remote branch
 > git show-ref --tags -d # timeout=10
Checking out Revision c8f3fc3b465451fbce37a1eb4789964c60ab22b5 (origin/master)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f c8f3fc3b465451fbce37a1eb4789964c60ab22b5
Commit message: "add files"
 > git rev-list --no-walk c8f3fc3b465451fbce37a1eb4789964c60ab22b5 # timeout=10
$ bash -c "[ -d \$HOME/.pyenv ]"
$ bash -c "cd /home/jenkins/workspace/my-project && env PYENV_ROOT\=\$HOME/.pyenv PYENV_VERSION\=3.6.4 \$HOME/.pyenv/bin/pyenv local 2>/dev/null || true"
$ bash -c "mkdir \$HOME/.pyenv.lock"
$ bash -c "env PYENV_ROOT\=\$HOME/.pyenv PYENV_VERSION\=3.6.4 \$HOME/.pyenv/bin/pyenv versions --bare"
$ bash -c "env PYENV_ROOT\=\$HOME/.pyenv PYENV_VERSION\=3.6.4 \$HOME/.pyenv/bin/pyenv rehash"
$ bash -c "env PYENV_ROOT\=\$HOME/.pyenv PYENV_VERSION\=3.6.4 \$HOME/.pyenv/bin/pyenv exec pip list"
$ bash -c "env PYENV_ROOT\=\$HOME/.pyenv PYENV_VERSION\=3.6.4 \$HOME/.pyenv/bin/pyenv rehash"
$ bash -c "rm -rf \$HOME/.pyenv.lock"
[my-project] $ /bin/sh -xe /tmp/jenkins6857290211274972615.sh
+ python -m unittest tests.test_sample
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
Finished: SUCCESS

おお, いい感じ.

本当にスレーブがビルドに使われているかどうかは, 以下のように [Jenkinsの管理] > [ノードの管理] > [スレーブ名] > [ビルド履歴] を見ると判る.

以上

Jenkins を取り上げた記事なのに, スクリーンショットが殆ど無いということに気付いた.

ということで, Jenkins 職人への道のりは遠い.

元記事はこちら

Jenkins のマスターとスレーブを Docker コンテナで起動して Python の unittest を pyenv 環境で動かすまでのメモ