Ubuntuにjenkinsをインストールする手順を記載します。
基本的には こちら にしたがって作業を進めます。
バージョン
- Ubuntu: 18.04
- Jenkins: 2.190
- Javaランタイム: 11
Javaランタイムのインストール
Jenkins 2.164 よりJava 11をサポートしているらしいので、Java11をインストールします。
それ以前のバージョンの場合は、Java8をインストールします。
sudo apt-get update
sudo apt-get install openjdk-11-jre
java --version
> openjdk 11.0.4 2019-07-16
Jenkinsインストール
wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins
これにより、以下の設定が行われます。
- Jenkinsがサーバ起動時に起動するデーモンとして設定される。詳細は
/etc/init.d/jenkins
参照 - Jenkins起動用のjenkinsユーザが作成される
- コンソールのログ出力を
/var/log/jenkins/jenkins.log
にリダイレクトする -
/etc/default/jenkins
を読み込む - Jenkinsが8080ポートをリッスンするよう設定する。変更したい場合は、
/etc/default/jenkins
のHTTP_PORT
を変更する
起動・停止
sudo systemctl start jenkins
sudo systemctl stop jenkins
初回設定
- ブラウザで
http://{hostname}:8080
にアクセスします - Administrator passwordの入力を求められますので、
cat /var/lib/jenkins/secrets/initialAdminPassword
でパスワードを確認して入力します -
Select Plugins to Install
を選択し、必要そうなpluginを選んで、Nextをクリックします - これでpluginのインストールが始まります
-
Create First Admin User
画面で、ユーザー名、パスワードなどを入力します - あとは流れで初回設定は完了です
Adminユーザとしての初期設定(ユーザ、権限周りの設定)
管理画面を表示
- ブラウザでJenkinsの画面(
http://{hostname}:8080
)にアクセスします- 空白画面になるようでしたら、一旦
sudo systemctl restart jenkins
でjenkinsの再起動をするとなおるかもしれません
- 空白画面になるようでしたら、一旦
- ログイン画面が表示されるので、一つ前の手順で設定したAdminのユーザ名とパスワードを入力します
- メニューの
Jenkinsの管理
ボタンから管理画面トップに移動します- URLは
http://{hostname}:8080/manage
です
- URLは
プラグインのインストール
- 管理画面トップから
プラグインの管理
に移動します -
利用可能
タブから目的のプラグインを探してチェックし、プラグインをインストールします - 今回は
Authorize Project
とRole-based Authorization Strategy
の二つのプラグインをインストールして、再起動しました
ユーザの管理
- 管理画面トップから
ユーザの管理
に移動します -
ユーザ作成
をクリックして、ユーザを作成します
グローバルセキュリティの設定
- 管理画面トップから
グローバルセキュリティの設定
に移動します -
セキュリティを有効化
をチェック(デフォルトなので何もしなくていいですが) - ユーザ情報の設定します
- 今回は
Jenkinsのユーザデータベース
をチェックします - 勝手にユーザ登録されたくないので、
ユーザにサインアップを許可
はチェックしません
- 今回は
- 権限管理の設定をします
- 今回は
Role-Based Strategy
を選択します- 事前に
Role-based Authorization Strategy
プラグインのインストールが必要です -
Authorize Project
プラグインがインストールされ設定されてないと、ワーニングが表示されます -
行列による権限設定
はユーザやグループ単位にやれることを設定できますが、Jenkinsのユーザデータベース
を利用している場合は新しいグループを追加したりできないようです。LDAP
やUnix user/group database
を利用する場合、グループがそのまま利用できます。なのでユーザ単位ではなくグループ単位で権限設定を行いたい場合はRole-Based Strategy
が必要になります -
ログイン済みユーザに許可
はログインユーザであれば誰でも何でもできます -
全員に許可
はJenkinsにアクセスできれば、ログインせずとも誰でも何でもできます
- 事前に
- 今回は
-
Access Control for Builds
の設定をします- Buildの実行ユーザの権限を指定する設定です
- 今回は面倒なので、
全プロジェクトに適用するジブド実行の権限を指定
を選択し、システムユーザーの権限で実行する
にしました- ただしこの設定だと、SYSTEMユーザで実行しちゃってるよーとワーニングが出るので
DISMISS
する必要があります
- ただしこの設定だと、SYSTEMユーザで実行しちゃってるよーとワーニングが出るので
- プロジェクト単位でコントロールしたい場合は
プロジェクト設定内でビルド実行の権限を設定する
を選びます- ちなみに、Jenkinsにおいて
プロジェクト
とジョブ
は同一と考えて良さそうです -
ビルドを起動したユーザの権限で実行する
指定したユーザの権限で実行する
システムユーザの権限で実行する
など、プロジェクト設定に表示する選択肢をチェックしたうえで、ジョブの権限の設定
欄から、上記でチェックした選択肢からプルダウンで選択できるようになります
- ちなみに、Jenkinsにおいて
Roleの設定
-
管理画面トップから
Manage and Assign Roles
に移動します -
Manage Roles
で新しいRoleを追加します- 今回は3つのGlobal Roleを追加することにしました
-
admin
: システム管理者ユーザ。なんでもできます- これはデフォルトで存在します。全ての付与されています
-
developer
:エンジニアユーザ。ジョブやビューの作成ができます- 全体:Read、ジョブ:全部、ビルド:全部、ビュー:全部 にチェックします
-
executer
:特定のジョブの実行だけができるユーザ。- 全体:Read だけをチェックします
- ビルド権限をつけたくなりますが、Global Roleと Project RoleはOR条件なので、Project Roleの方で付けます
- 全体:Read だけをチェックします
-
- Project Roleを追加します
-
hoge-executer
:Patten
には対象のジョブ名を正規表現で指定します- ジョブ:Build、Cancel、Read にチェックします
- 正規表現でジョブ名を指定することを前提に、ジョブ名の接頭語をパターン化しておくことをおすすめします。具体的には部署名とかプロジェクト名を接頭語としてつけておくと楽です
-
- 今回は3つのGlobal Roleを追加することにしました
-
Assing Roles
でユーザに対してRoleをアサインします- システム管理者ユーザには、Global Roleの
admin
を割り当てます - エンジニアユーザには、Global Roleの
developer
を割り当てます - 特定のジョブの実行ユーザは、Global Roleの
executer
とProject Roleのhoge-executer
を割り当てます - Anonymous(未ログインユーザ)には何もRoleを割り当てません
- システム管理者ユーザには、Global Roleの
Git連携
- Git連携を行うには
Git
プラグインが必要です - ジョブ側でGitからソースを取得する設定を行います
- ジョブの設定画面に移動します
-
ソースコードの管理
でGit
を選択します -
リポジトリURL
にURL(今回はgit@
の方)を入力します - 認証情報の
追加
ボタンをクリックして、認証情報を作成します- ちなみに追加した認証情報はJenkinsトップの左側メニューの
認証情報
欄から変更できます
- ちなみに追加した認証情報はJenkinsトップの左側メニューの
- 認証情報を設定します
- クレデンシャルの種類は3択だと思います
- SSHユーザ名と秘密鍵: gitのurlを
git@
にする場合で、ssh認証を行いたい場合はこれを選択します - ユーザ名とパスワード: gitのurlを
https://
にする場合はこれを選択します(たぶん) - GitLab API トークン: APIトークンによる認証をしたい場合はこれを選択します。
GitLab
のプラグインが必要かも。GItLab側でAPIキーの発行を行う必要があります。多分Github
プラグインを入れればGitHubの選択肢も出てくると思われます(たぶん)
- SSHユーザ名と秘密鍵: gitのurlを
- 今回はSSH認証を行うので、
SSHユーザ名と秘密鍵
を選択し、必要な情報を記入していきます- Domain: グローバルドメイン
- スコープ: グローバル
- ID: Jenkins上の認証情報に対して一意になる名前をつける
- ユーザ名: 対象のユーザ名
- 秘密鍵: 秘密鍵(id_rsa.pubではなくid_rsaの方)の内容を貼り付け
- パスフレーズ: 認証を行う場合は、パスフレーズを記入
- クレデンシャルの種類は3択だと思います
- これでジョブ実行時にワークスペース直下に対象のプロジェクトが
git clone
された状態になります- 直下にプロジェクトフォルダができるのではなく、直下にプロジェクトフォルダの内容が展開されます
Jenkins CLIを使えるようにする
こちらのマニュアルを参考に進めます。
今回は、sshポートを開けれないケースを想定して、CLIクライアントを利用することにします。
-
jenkins-cli.jar
を入手します- 管理画面トップから
Jenkins CLI
に移動します -
jenkins-cli.jar
ダウンロードリンクがあるので、そこからダウンロードします
- 管理画面トップから
- APIトークンを発行します
- 管理画面トップ >
ユーザの管理
> CLI経由で接続するユーザ >設定
でユーザ設定画面に移動します - APIトークン欄で
Add new Token
します。その際のトークンを覚えておいてください。
- 管理画面トップ >
- CLIを実行する
java -jar jenkins-cli.jar [-s JENKINS_URL] -auth user_name:api_token help
- 使えるcommandの一覧が出てきたらOKです。
- うまく行かない場合、原因調査します
- まずは標準出力ログを確認します
-
java -jar jenkins-cli.jar -logger FINE [-s JENKINS_URL] -auth user_name:api_token help
のように-logger
オプションで標準出力の内容を詳細レベルにすることができます
-
- Jenkinsサーバ側のログを確認します
- 管理画面トップから
システムログ
に移動します -
すべてのログ
からログを確認します
- 管理画面トップから
- まずは標準出力ログを確認します
-
full-duplex channel timeout
が原因の場合- ログ確認
- 標準出力に
getOrCreateProvider(EdDSA) created instance of net.i2p.crypto.eddsa.EdDSASecurityProvider
と出力されます - システムログに
java.io.IOException: HTTP full-duplex channel timeout: dba62b92-ee7c-49b3-0qewkjba-dsfopiuadfqwe
と出力されます
- 標準出力に
- 原因
- nginxやapacheなどのリバースプロキシを経由して、jenkinsにアクセスしている場合、リバースプロキシが正しく設定されいないと全二重HTTP通信でタイムアウトが発生するようです
- 具体的には、こちらのISSUEを踏んでいる可能性があります
- 対処
- nginxを使っている場合は、proxyの設定(/etc/nginx/sites-available)に以下を追加します
server { location / { proxy_http_version 1.1; # 1.0だと以下の二つの設定が効かないので、1.1にする必要がある proxy_request_buffering off; proxy_buffering off; :
- nginxを再起動(systemctl restart nginx)して、再度
java -jar jenkins-cli.jar ...
を実行して、コマンド一覧が出てくればOKです
- nginxを使っている場合は、proxyの設定(/etc/nginx/sites-available)に以下を追加します
- ログ確認
ジョブとビュー定義を別のJenkinsにコピーする(staging環境からproduction環境へ)
いくつか方法があるようですが、Jenkins CLIを利用する方法で実装しました。
今回は、staging環境からproduction環境へ全ジョブを単純にコピーするケースを想定します。
- まず、上記の
Jenkins CLIを使えるようにする
の手順でstatging環境とproduction環境のJenkins両方で、Jenkins CLIを使えるようにします - あとは、以下のようなスクリプトを記載するだけです
- staging環境から
list-jobs
でジョブリストを取得する - ジョブ1件毎に以下の処理を行う
- staging環境から
get-job
でジョブ定義XMLを取得する - production環境から
get-job
ですでにジョブが存在するか確認する- すでに存在したらproduction環境に
update-job
でジョブを上書きする -
delete-job
してcreate-job
する手もあるが、一度削除するとビューから外れてしまうので、update-job
の方がいいと思います - 存在しなかったらproduction環境に
create-job
でジョブを作成する
- すでに存在したらproduction環境に
- staging環境から
- ビューもジョブと同じように実装すれば大丈夫です
具体的には、以下のようなスクリプトになりました。このスクリプトをstaging環境のJenkinsジョブとして登録して、実行できるようにしています。
#!/bin/bash
set -euC
# グローバル定数
readonly JAR_PATH=/usr/share/jenkins/jenkins-cli.jar
readonly STG_JENKINS_URL="https://stg.hoge.huga/"
readonly STG_USER="admin_user"
readonly STG_API_TOKEN="0245691pdjf8414g93841"
readonly STG_JENKINS_CLI="java -jar ${JAR_PATH} -s ${STG_JENKINS_URL} -auth ${STG_USER}:${STG_API_TOKEN}"
readonly PRD_JENKINS_URL="https://prd.hoge.huga/"
readonly PRD_USER="admin_user"
readonly PRD_API_TOKEN="4598fg09w745bg8dvkn2"
readonly PRD_JENKINS_CLI="java -jar ${JAR_PATH} -s ${PRD_JENKINS_URL} -auth ${PRD_USER}:${PRD_API_TOKEN}"
# ジョブをコピーする
function copy_jobs() {
# ジョブリスト取得
local jobs=($(${STG_JENKINS_CLI} list-jobs))
# ジョブ件数分繰り返し
for job in "${jobs[@]}"; do
set +e
local prd_xml="$(${PRD_JENKINS_CLI} get-job ${job} 2>&1)"
local stg_xml="$(${STG_JENKINS_CLI} get-job ${job})"
set -e
if [[ "${prd_xml}" == "" ]]; then
echo "${stg_xml}" | ${PRD_JENKINS_CLI} create-job "${job}"
else
echo "${stg_xml}" | ${PRD_JENKINS_CLI} update-job "${job}"
fi
done
}
# ビューをコピーする
function copy_views() {
# ビューリスト取得 ※CLIで直接取得できなかったので直指定
local views=("01_ビュー" "02_ビュー" "03_ビュー")
# ビュー件数分繰り返し
for view in "${views[@]}"; do
set +e
local prd_xml="$(${PRD_JENKINS_CLI} get-view ${view} 2>&1)"
local stg_xml="$(${STG_JENKINS_CLI} get-view ${view})"
set -e
if [[ "${prd_xml}" == "" ]]; then
echo "${stg_xml}" | ${PRD_JENKINS_CLI} create-view "${view}"
else
echo "${stg_xml}" | ${PRD_JENKINS_CLI} update-view "${view}"
fi
done
}
# メイン処理
copy_jobs
copy_views
Jenkins本体のバージョンUP
新しいバージョンのJenkinsが存在する場合、画面上部からjenkins.warのダウンロードができますので、それをサーバ上のwarファイルと置き換えるだけです。
- 実行中のwarファイルの場所を確認します
- 管理画面トップから
システム情報
に移動します -
executable-war
の値がwarファイルの場所になります(例:/usr/share/jenkins/jenkins.war
)
- 管理画面トップから
- jenkins.warファイルのダウンロードします
- サーバにコピーします
scp ~/Downloads/jenkins.war hoge_server:/tmp/
- ファイルを実行中のファイルと置き換えます
mv /usr/share/jenkins/jenkins.war /usr/share/jenkins/jenkins.war_bk
mv /tmp/jenkins.war /usr/share/jenkins/
chown root:root /usr/share/jenkins/jenkins.war
- jenkinsを再起動します
systemctl restart jenkins
jenkinsの実行ユーザを変更
ジョブのシェルスクリプトをデフォルトのjenkins
ユーザではなく、別のユーザで実行したいケースがあると思います。
コマンド単位で別ユーザにしたい場合
まず、visudo でjenkinsユーザにsudo権限を与えます。ケースに応じて与える権限を検討する必要があります。
visudo
+ # 全権限をhogeユーザに付与
+ jenkins ALL=(hoge) NOPASSWD: ALL
+ # git実行権限をhogeユーザに付与
+ jenkins ALL=(batch) NOPASSWD: /usr/bin/git *
+ # 環境変数を引き継いで(つまりsudo -E)、shを実行できる権限をhogeユーザに付与
+ jenkins ALL=(batch) NOPASSWD: SETENV: /bin/sh *
そのうえで、ジョブのシェルスクリプト内で、コマンドを個別に別ユーザで実行していきます。
sudo -u hoge git fetch
sudo -Eu hoge sh -c "echo fuga"
一律別ユーザにしたい場合
最初は頑張ってコマンド単位でsudoしていたのですが、.bashrc
を読み込む必要があるケースが出てきて、sudo -iu hoge
したところ/home/hoge/
にカレントディレクトリが変更されてしまうことがあり、その整合を取るために色々頑張っていたのですが、途中で馬鹿らしくなり、そもそもシェルスクリプトを別ユーザで実行する方法を探しました。
自分の調査ではシェルスクリプトだけを別ユーザで実行する方法は見つからなかったので、jenkins自体を別ユーザで起動することにしました。
jenkinsを別ユーザで起動すると、シェルスクリプトも同じように別ユーザで実行されます。
sudo -iu root
vi /etc/default/jenkins
- JENKINS_USER=$NAME
+ JENKINS_USER=hoge
chown -R hoge: /var/lib/jenkins /var/log/jenkins /var/cache/jenkins
systemctl restart jenkins
developerとしての設定
ビュー(タブ)の作成
- Jenkinsトップの
+
タブをクリックして、ビュー作成画面に移動します -
リストビュー
を選択します - ビューに含めたいジョブを選択して保存します
ジョブの作成
- Jenkinsトップもしくは各ビューで
新規ジョブ作成
をクリックしジョブ作成画面に移動します -
copy from
で既存のジョブをコピーするか、ジョブの種類を選択して作成します- 基本的には
フリースタイル・プロジェクトのビルド
を利用することが多いと思います
- 基本的には
- 詳細は多岐にわたるため割愛します。
パイプライン ジョブの作成
- Jenkins Pipeline プラグインが必要です
- 公式のドキュメントはこちらです
- ジョブの一括実行の観点
- パイプラインは複数のジョブをまとめて定義することができるとても便利なジョブです
- こんな感じのスクリプトで定義します
node { stage('hoge stage') { build job: 'hoge' } stage('fuga stage') { build job: 'fuga', parameters: [ string(name: 'param1', value: 'xxx'), string(name: 'param2', value: 'yyy') ] } }
- CIの観点
- パイプラインの定義は
Jenkinsfile
で定義でき、プロジェクトのGITリポジトリで管理できます(設定のコード化ができる) - その上で、commitされたら
Jenkinsfile
の定義に従って、パイプラインジョブが実行されるようにできます - agentにdockerを設定することで、独立した環境でテストすることも可能ですし、複数のstageを定義して並列で実行させるようなこともできます
- GitlabCIなどと同等の機能が提供されている印象です。CIの観点でもJenkins Pipelineは有効かもしれません
- パイプラインの定義は