2016/05/15

稼働中のJenkins2コンテナに接続する方法

Jenkins2をDocker imageから起動してコンテナ運用している時, そのコンテナにアタッチしてbash操作したい場合があります.

次のようにJenkinsコンテナを起動します.

docker run --name jenkins2.3 --volumes-from j_storage -p 8080:8080 -p 50000:50000 jenkins:2.3

docker psでjenkins2.3が起動していることを確認し, 次のコマンドでコンテナに接続しましょう. bashプロンプトが表示されたら成功です.

docker exec -it <JENKINS CONTAINER NAME> bash

docker attach

docker attachでこのコンテナに接続&bashを試みますがプロンプトは現れません.

docker attach jenkins2.3

JenkinsのDockerfileENTRYPOINTを見るとjenkins.shを実行するようになっています.
docker runでコマンドも指定していませんので, docker attachはこれに接続することになります.

ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"]

以上です.

Jenkins2のソフトウェアアップデート

Dockerから起動したJenkinsにソフトウェアアップデートがあった場合にそれを適用する方法です.

Jenkinsのアップデート情報はJenkins管理画面で通知されてjenkins.warのダウンロードリンクが示されます.
サーバ上でjenkins.warを指定してJenkinsサーバを起動している場合はこれを置き換えるだけで済みますが, Jenkins公式のDocker imageを使ってコンテナ上にJenkinsサーバを起動している場合は違うアプローチが必要です.

今回のJenkins on Containerは次の内容で起動しています.

// jenkins用のData Volume Containerを用意
docker run -v /var/jenkins_home --name j_storage ubuntu /bin/bash

// jenkins user用にディレクトリのアクセス権限を設定
docker exec j_storage chown 1000 /var/jenkins_home

// jenkinsコンテナをData Volume Container指定して起動
docker run --volumes-from j_storage -p 8080:8080 -p 50000:50000 jenkins:2.0

Jenkinsコンテナの起動方法は何種類かあります.

  • コンテナ内にデータを格納する方法
  • ホスト側のディレクトリをコンテナの/var/jenkins_homeにマウントする方法
  • Data Volume Container(/var/jenkins_home)をマウントする方法

そして, コンテナにあるJenkinsのバージョンをアップデートする方法も何種類かあります.

  • 直接jenkins.warを書き換える
  • 新しいJenkinsバージョンに対応したDocker imageをpullする

コンテナの思想を考えると推奨されるのは後者です. 前者だとコンテナのポータビリティを活かせません.

// 新しいバージョンのjenkins docker imageを取得
docker pull jenkins:2.3

// 新しいバージョンのjenkins containerを起動
// 現行のjenkinsで使用していたData Volumeを指定すること
docker run --name jenkins2.3 --volumes-from j_storage -p 8080:8080 -p 50000:50000 jenkins:2.3

Jenkinsのバージョンアップで注意することは, Jenkinsのコンテナを起動する際にコンテナ内にデータを保存する方法だと, 新しいDocker imageでも使えるようにデータを引き継ぐ必要があるということです.

docker cp $CONTAINER_ID:/var/jenkins_home

ホストディレクトリのマウントやData Volume Containerでデータ部を外からマウントしている場合は, 新しいJenkins バージョンのコンテナを起動する際にそれをマウントするだけで済みます.

Jenkinsの起動についてはこちらもあわせてお読みください.
Yukiの枝折 - Get Started Jenkins2

以上です.

Get Started Jenkins2

Docker Image

Jenkins2.0のOfficial docker image(LTS/安定版)がDocker Hubで公開されています.

Weekly buildベースのDocker imageも公開されていますが, 今回はLTS版のDocker Imageを使ってDocker + Jenkins2.0な環境を構築します(構築はMacOS上で実施しています).

JenkinsのDocker imageはGitHub上のレポジトリで管理されています.

本稿はすでにDocker環境を構築できており, 使用できる状態にあることを前提に進め, Docker環境構築手順については省略します.

docker pull

docker pullでJenkins2のdocker imageを取得しましょう. 現時点で公開されている最新のtagを指定します.

docker pull jenkins:2.0

上記はJenkins2.0が最新であった場合の例です.
下記のようなメッセージが表示されて, 正しくDocker imageをpullできたことを確認します.

Digest: sha256:e6f668256b6a048e7041d0bb636425fdd45f50559f23633cb94a9baea59578ee
Status: Downloaded newer image for jenkins:2.0

Docker image取得後にJenkinsのソフトウェアバージョンをアップデートする方法は別稿に記載します.
これでJenkinsを実行できる環境は整いました. Dockerを使えば手軽に環境構築できますね.

docker run

JenkinsのDocker imageを起動する方法はいくつかありますが,
まずはJenkinsのコンテナにある2つの重要なPortを確認しておきます.

8080:
Jenkins serverのListen portです.

50000:
JenkinsのSlave server用Portです. Slave agent接続時に使用されます.

docker runで起動する際にはこれら2つのPortのポートフォワーディングを指定します.

docker run -p 8080:8080 -p 50000:50000 jenkins:2.0

デフォルトのSlave agent portを50000から変更したい場合は環境変数JENKINS_SLAVE_AGENT_PORTを指定します.

FROM jenkins:2.0
ENV JENKINS_SLAVE_AGENT_PORT 50001

またはrunコマンドの引数にこれを指定できます.

docker run -e JENKINS_SLAVE_AGENT_PORT 50001 ...

これでJenkins serverを起動することができました

run with Host Directory

先ほどの方法でJenkinsを起動するとデータがコンテナ内に保存されます.
つまり, Jenkinsのデータは永続化されず, コンテナを破棄するとデータは失われます.
もしコンテナを破棄してデータを引き継ぎたい場合やバックアップしたい場合は, 一手間必要です.

docker cp $CONTAINER_ID:/var/jenkins_home

Jenkinsのデータは/var/jenkins_homeに作成されます.

# Jenkins home directory is a volume, so configuration and build history 
# can be persisted and survive image upgrades
VOLUME /var/jenkins_home

そこで, ホストのディレクトリをJenkins コンテナの/var/jenkins_homeにマウントする方法があります.

docker run -p 8080:8080 -p 50000:50000 -v </host/volume>:/var/jenkins_home jenkins

これでコンテナ破棄でデータが消えることはありませんし, バックアップも容易です.

run with Data Volume Container

ホストのディレクトリをマウントする方法だとコンテナの旨味を活かしきれていません. ホストのボリュームに依存するとコンテナのポータビリティ性を欠いてしまいます.
Data Volume Containerを使ってこの課題を解決していきます.

まず, Data Volume Container(j_storage)を作成することからはじめます.

docker run -v /var/jenkins_home --name j_storage ubuntu /bin/bash

-vでData Volumeのパスに/var/jenkins_homeを指定して作成します.
この状態で作成されているjenkins_homeフォルダのアクセス権限は次の状態です.

drwxr-xr-x 14 root root  4096 May 14 15:26 jenkins_home

これではJenkinsユーザに書き込み権限がないのでJenkinsコンテナを起動することができません.

touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

Data Volume Container(j_storage)の/var/jenkins_homeのアクセス権限を変更します.

docker exec j_storage chown 1000 /var/jenkins_home

Jenkinsユーザのuidは1000で定義されていますのでchownでそれを指定します.

ARG user=jenkins
ARG group=jenkins
ARG uid=1000
ARG gid=1000

# Jenkins is run with user `jenkins`, uid = 1000
# If you bind mount a volume from the host or a data container, 
# ensure you use the same uid
RUN groupadd -g ${gid} ${group} \
    && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user}

設定できたらData Volumeを指定してJenkinsサーバを起動しましょう.

docker run --volumes-from j_storage -p 8080:8080 -p 50000:50000 jenkins:2.0

これでJenkinsのデータについてもポータビリティを確保できました.

以上です.