Jenkins による リリース & Git操作 & build 入門
index
00. Jenkinsについて
Jenkinsとは
準備された仕事を指定されたタイミングで実行する箱
- 継続的インテグレーション(continuous integration)ツール
- アジャイル型開発での利用を前提に設計された
- on-premises(自社運用)型のため企業において一括管理しやすい
- 日本製で、作者は川口耕介氏
- "ジョブ"と呼ばれる用途単位の機能を順次実行していくことでGit操作やファイル転送を実行する
- 1つのジョブは、対象Gitブランチ設定やGitコマンド、シェルコマンドなどを設定することで1つの機能を担う構造になっている
- ジョブを一度作成すると実行時に機能の詳細内容を意識することなく反復利用できる
- 初期状態では、ジョブが何も与えられてない"からっぽのハコ"のようなもの
川口耕介氏
なぜCIツール
- 機械が得意なことを機械に任せる
- 差分抽出
- 反復作業
- 転送設定
- 高速リリース
- テスト
- ローカルルールの撲滅
- 本来創意工夫の必要のない作業
- 属人的な要素の排除
その他のCIサービス
01. シェルコマンド
Jenkins の Job でよく利用する シェルコマンド を紹介
Jenkins 「シェルの実行」内容の例
#!/bin/bash
### 変数定義
# ホスト
HOST_REMOTE=[ホストの名前]
# パス
PATH_DIST=${WORKSPACE}/dist/
PATH_REMOTE=[リモートのパス]
# コマンド
RSYNC="rsync -rlcv --delete"
### ディレクトリ生成 (2回目の実行以降はコメントアウトする)
# echo -e "\n\n*** ディレクトリ生成 開始 ***"
# ssh $HOST_REMOTE mkdir -p $PATH_REMOTE
# echo -e "*** ディレクトリ生成 終了 ***\n"
### ファイル転送
if ${DRYRUN} ; then
# dryrun
echo -e "\n\n*** dryrun 開始 ***"
$RSYNC -n $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** dryrun 終了 ***\n\n"
else
# deploy
echo -e "\n\n*** deploy 開始 ***"
$RSYNC $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** deploy 終了 ***\n\n"
fi
よく使うコマンド
echo
rsync
mkdir
rm
if then elif then else exit fi
for do done
test
ls
grep
xargs
#
#!/bin/bash
次章にてこれらを1つずつ確認する
コマンド解説
echo
文字列や変数の内容を表示する
- UNIXコマンドの1つ
- 文字通り「echo」の意味
よく使うオプション
option | 内容 |
---|---|
-e |
escapeの頭文字。エスケープ文字を有効にして表示する |
サンプルコード
echo -e "\n\n*** dryrun 開始 ***"
Work
01
以下の動作の違いを確認しましょう
echo あいうえお
echo あ\nい\nう\nえ\nお
echo -e あ\\nい\\nう\\nえ\\nお
echo "あ\nい\nう\nえ\nお"
echo -e "あ\nい\nう\nえ\nお"
02
変数の働きを確認しましょう
HOGE="あ\nい\nう\nえ\nお"
echo -e $HOGE
rsync
テストサーバーや本番サーバーへのファイルアップロードにはおもにrsync
を利用する
- UNIXソフトウェアの1つ
- 「remote sync」の意味
- 転送元パスの「/」の有無が挙動に影響するので注意が必要
- 転送元パスの「/hoge」はディレクトリ自身を含み、「/hoge/」はディレクトリの中身だけに作用する
よく使うオプション
option | 内容 |
---|---|
-r , --recursive
|
指定したディレクトリの下層のディレクトリにも再帰的に実行する |
-l , --links
|
ローカルのシステムと同様にリモートのシステムでシンボリック・リンクを再作成する |
-c , --checksum
|
コピー先に同じチェックサムとサイズを持つ同名のファイルをスキップする |
-v , --verbose
|
転送中の情報を詳しく表示する。このオプションは三つまで連記指定可能 |
-n , --dry-run
|
実際には実行しないで、実行したと仮定した場合の情報だけを表示する |
--delete |
コピー先に存在してコピー元に存在しないファイルを削除する |
--ignore-existing |
コピー先に存在するファイルは更新しない |
--include |
指定したファイルやディレクトリを対象に含む |
--exclude |
指定したファイルやディレクトリを対象に含まない |
サンプルコード
PATH_LOCAL=${WORKSPACE}/dist/
PATH_REMOTE=/hoge/
rsync -rlcv --delete $PATH_LOCAL $PATH_REMOTE
rsync -r -l -c -v --delete $PATH_LOCAL $PATH_REMOTE
Work
以下の動作の違いを確認しましょう
cd [作業するディレクトリ]
rsync -rlcvn a/ b
rsync -rlcv a/ b
rsync -rlcvn a c
rsync -rlcv a c
rsync -rlcv a/ d
rsync -rlcvv a/ e
rsync -rlcvvv a/ f
mkdir
新しいディレクトリを作成する
- UNIXコマンドの1つ
- 「make directory」の意味
よく使うオプション
option | 内容 |
---|---|
-p , --parents
|
親ディレクトリも同時に作成する |
サンプルコード
PATH_REMOTE=/hoge/
mkdir -p $PATH_REMOTE
Work
以下の動作を確認しましょう
PATH_REMOTE=e
mkdir -p $PATH_REMOTE
rm
指定したディレクトリ以下の全ディレクトリツリーを削除する
- UNIXコマンドの1つ
- 「remove」の意味
- パスの指定を誤るとサーバーが空になるので注意
よく使うオプション
option | 内容 |
---|---|
-r , -R , --recursive
|
指定したディレクトリの下層のディレクトリにも再帰的に実行する |
-f , --force
|
警告メッセージを表示せずに実行する |
サンプルコード
PATH_BACKUP=${WORKSPACE}/_backup/
if test -d $PATH_BACKUP ; then
rm -rf $PATH_BACKUP
fi
Work
以下の動作を確認しましょう
PATH_REMOTE=e
rm -rf $PATH_REMOTE
if [条件]; then [処理] elif [条件]; then [処理] else [処理] fi
条件分岐する
- シェル・スクリプト構文
- 条件によって処理を分ける
サンプルコード & Work
HOGE=3
if [ $HOGE -eq 1 ]; then
echo -e "1です"
elif [ $HOGE -eq 2 ]; then
echo -e "2です"
else
echo -e "${HOGE}です"
fi
for [イテレータ変数] in [配列] do [処理] done
for文を定義する
- シェル・スクリプト構文
- ループ制御文
- Bに配列、Aにイテレータ変数、Cに処理内容を記述する
サンプルコード & Work
CONTENT_ARR=()
CONTENT_ARR+=(a/)
CONTENT_ARR+=(b/)
CONTENT_ARR+=(c/)
for CONTENT in ${CONTENT_ARR[@]}
do
echo -e "${CONTENT}"
done
test
真偽を判定する
- UNIXコマンドの1つ
- 条件式を評価し真偽値を返す
よく使うオプション
option | 内容 |
---|---|
-d |
directoryの頭文字。指定したファイルが存在し,ディレクトリであれば真を返す |
サンプルコード
### WORKSPACEから dist/ と .git/ 以外を削除
if test -d ${WORKSPACE} ; then
ls -A | grep -v "dist" | grep -v ".git" | xargs rm -rf | rm -rf .editorconfig | rm -rf .gitignore | rm -rf bin
fi
Work
if test -d a/; then
echo -e "存在します"
else
echo -e "存在しません"
fi
if test -d z/; then
echo -e "存在します"
else
echo -e "存在しません"
fi
ls
ファイル、ディレクトリの情報取得
- UNIXコマンドの1つ
- 「list」の意味
- ディレクトリやファイルの情報を表示する
よく使うオプション
option | 内容 |
---|---|
-A |
".."や"."を表示しない |
サンプルコード
### WORKSPACEから dist/ と .git/ 以外を削除
if test -d ${WORKSPACE} ; then
ls -A | grep -v "dist" | grep -v ".git" | xargs rm -rf | rm -rf .editorconfig | rm -rf .gitignore | rm -rf bin
fi
Work
ls ./
ls -A ./
grep
検索して出力する
- UNIXコマンドの1つ
よく使うオプション
option | 内容 |
---|---|
-v , --invert-match
|
マッチしない行を出力する |
サンプルコード
### WORKSPACEから dist/ と .git/ 以外を削除
if test -d ${WORKSPACE} ; then
ls -A | grep -v "dist" | grep -v ".git" | xargs rm -rf | rm -rf .editorconfig | rm -rf .gitignore | rm -rf bin
fi
Work
以下の動作の違いを確認しましょう
grep テキスト ./b/*.txt
grep a ./b/*.txt
grep b ./b/*.txt
xargs
前の処理を受けて処理を実行する
- UNIXコマンドの1つ
- 「エックスアーグズ」と読む
- 入力を読み込み、それを引数として指定したコマンドを実行する
サンプルコード & Work
rsync -rlcv a/ b
ls | grep b | xargs rm -rf
#
- UNIXシェルスクリプトの一行コメントアウトの記述に利用する
#!/bin/bash
- UNIXシェルスクリプトの先頭に書くUNIX命令
- この命令のことをシバン、シェバン(shebang)と呼ぶ
- インタプリタを起動する命令
- シェバン以下に書くコマンドの種類を指定している
-
#!/bin/bash
、#!/bin/sh
、#!/bin/csh
、#!/usr/bin/perl
、#!/usr/bin/ruby
などがある
02. gitコマンド
Octocat Monalisa
Once upon a time, there was a cat who’s name was Monalisa. Monalisa and her owner went to the beach. When Monalisa got to the beach, her owner Kelly gave her goggles so Monalisa could swim and see what was in the ocean. When Monalisa went in the water she found lots of fish. When Monalisa was swimming she was so exited she opened her mouth and swallowed a coral that made you grow legs like a octopus but keep your normal face. So Monalisa grew legs and became Mrs. Monalisa octocat.
Jenkins の Job でよく利用する gitコマンド を紹介
Jenkins 「シェルの実行」内容の例
### $BRANCH_NAME を checkout
git checkout $BRANCH_NAME
### $BRANCH_NAME を master に merge
git checkout master
git merge $BRANCH_NAME
git push origin master
### $WORKSPACEを削除
if test -d ${WORKSPACE} ; then
rm -rf ${WORKSPACE}
fi
よく使うコマンド
clone
checkout
add
commit
push
merge
tag
次章にてこれらを1つずつ確認する
コマンド解説
clone
既存リポジトリのコピーを取得
- clone コマンドは Jenkins Job内では「ソースコード管理」の「Git」の機能で実行することが多い
サンプルコード & Work
cd [作業するディレクトリ]
git clone https://github.com/sekiyaeiji/jenkins-demo.git
cd jenkins-demo
checkout
ブランチやファイルを取得してその後の処理の準備をする
サンプルコード & Work
git checkout master
git checkout develop
git checkout master
add
インデックスに追加する
よく使うオプション
option | 内容 |
---|---|
-A |
「.」と「-u」を合わせた機能。すべての変更を含む内容を追加登録する |
サンプルコード & Work
git add -A
commit
commit する
サンプルコード & Work
git commit -m "hoge"
push
push する
サンプルコード & Work
git push origin develop
merge
merge する
サンプルコード & Work
git checkout master
git merge develop
tag
tag を作成する
よく使うオプション
option | 内容 |
---|---|
-m |
作成する tag にメッセージを付与する |
サンプルコード & Work
git tag fuga -m "piyo"
git tag
git push --tag
03. 設定
基本設定
ジョブ名(プロジェクト名)
- 半角英数文字列により命名する
- その文字列ままジョブのURLとして利用される
- インスタンス内でユニークである必要がある
- スペースは原則として使わない(%20になる)
説明
- html要素がレンダリングできる
- [プレビュー]押下で作業中のレイアウトが確認できる
古いビルドの破棄
- Jenkinsインスタンスの容量節約のため設定する
- 基本的には「ビルドの保存最大数 : 10」を設定しておけば問題ない
Slack Notifications
- チームでジョブ実行監視を行いたい場合などに有効
- 特に本番用ビルドが走る場合など、失敗ログにすばやく気付けて便利
手順
- 「Notify Success」をチェック
- [高度な設定...]を押下
- 「Team Domain : [Slackのチームドメイン]」
- 「Integration Token : [インテグレーショントークン値]」
- 「Project Channel : [通知したいチャンネル名]」
Git ブランチ選択
Git Parameter
手順
- 引数名になる「Name : BRANCH_NAME」を入力
- このジョブのブランチルールの説明などを「Description」に記載
- 通常のブランチ操作を行うジョブの場合、「Parameter Type : Branch」を選択
- 扱う頻度の高いブランチやデフォルトブランチを設定する developの場合は「Default Value : origin/develop」
DRYRUN フラグ
真偽値
手順
- 引数名になる「名前 : DRYRUN」を入力
- 失敗を許容されないジョブの場合は「デフォルト値」をチェックする テストサーバーではチェックは不要
- このジョブのDRYRUNの使い方などを「説明」に記載
Git Clone
ソースコード管理 - Git
手順
- 「ソースコード管理」で「Git」ラジオボタンをチェックする
- 「Repository URL」にリポジトリのSSHパスを設定
- Ex.) git@github.com:◯◯◯/□□□.git
- 「Branches to build」に、Git Parameterで設定した引数「$BRANCH_NAME」を入力
「シェルの実行」の設定
シェルコマンド
01. シェルコマンドで学んだコマンドで実際の動作を確認しましょう
gitコマンド
02. gitコマンドで学んだコマンドで実際の動作を確認しましょう
04. 「シェルの実行」のバリエーション
dryrun試行 を含む通常の rsync deploy
- WORKSPACE内の「dist」ディレクトリの内容をリモートにリリースするシェルサンプル
#!/bin/bash
### 変数定義
# ホスト
HOST_REMOTE=[ホストの名前]
# パス
PATH_DIST=${WORKSPACE}/dist/
PATH_REMOTE=[リモートのパス]
# コマンド
RSYNC="rsync -rlcv --delete"
### ディレクトリ生成 (2回目以降の実行時はコメントアウトしてもOK)
# echo -e "\n\n*** ディレクトリ生成 開始 ***"
# ssh $HOST_REMOTE mkdir -p $PATH_REMOTE
# echo -e "*** ディレクトリ生成 終了 ***\n"
### ファイル転送
if ${DRYRUN} ; then
# dryrun
echo -e "\n\n*** dryrun 開始 ***"
$RSYNC -n $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** dryrun 終了 ***\n\n"
else
# deploy
echo -e "\n\n*** deploy 開始 ***"
$RSYNC $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** deploy 終了 ***\n\n"
fi
remote からファイルを取得する
- WORKSPACE内の「_backup」ディレクトリにリモートのファイルを保存するシェルサンプル
#!/bin/bash
### 変数定義
# ホスト
HOST_REMOTE=[ホストの名前]
# パス
PATH_BACKUP=${WORKSPACE}/_backup/
PATH_REMOTE=[リモートのパス]
# コマンド
RSYNC_BACKUP="rsync -rl"
### バックアップ保存
# WORKSPACE内の過去のバックアップを削除
if test -d $PATH_BACKUP ; then
rm -rf $PATH_BACKUP
fi
# WORKSPACEにバックアップを保存
echo -e "\n\n*** backup 開始 ***"
$RSYNC_BACKUP $HOST_REMOTE:$PATH_REMOTE $PATH_BACKUP
echo -e "*** backup 終了 ***\n\n"
rsync deploy と remote からのバックアップ保存の組み合わせ
- おもに本番リリースジョブに利用する
- 本番 deploy ではこのリリース直前のバックアップを原則として義務づけている
- DRYRUN の際にバックアップが作動しないよう条件を設定する
#!/bin/bash
### 変数定義
# ホスト
HOST_REMOTE=[ホストの名前]
# パス
PATH_DIST=${WORKSPACE}/dist/
PATH_BACKUP=${WORKSPACE}/_backup/
PATH_REMOTE=[リモートのパス]
# コマンド
RSYNC="rsync -rlcv --delete"
RSYNC_BACKUP="rsync -rl"
### ディレクトリ生成 (2回目以降の実行時はコメントアウトしてもOK)
# echo -e "\n\n*** ディレクトリ生成 開始 ***"
# ssh $HOST_REMOTE mkdir -p $PATH_REMOTE
# echo -e "*** ディレクトリ生成 終了 ***\n"
### バックアップ保存
if [ ${DRYRUN} = false ] ; then
# WORKSPACE内の過去のバックアップを削除
if test -d $PATH_BACKUP ; then
rm -rf $PATH_BACKUP
fi
# WORKSPACEにバックアップを保存
echo -e "\n\n*** backup 開始 ***"
$RSYNC_BACKUP $HOST_REMOTE:$PATH_REMOTE $PATH_BACKUP
echo -e "*** backup 終了 ***\n\n"
fi
### ファイル転送
if ${DRYRUN} ; then
# dryrun
echo -e "\n\n*** dryrun 開始 ***"
$RSYNC -n $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** dryrun 終了 ***\n\n"
else
# deploy
echo -e "\n\n*** deploy 開始 ***"
$RSYNC $PATH_DIST $HOST_REMOTE:$PATH_REMOTE
echo -e "*** deploy 終了 ***\n\n"
fi
Work
- 「RSYNC_BACKUP」のオプション値「-rl」の理由を考察する
WORKSPACE 内に残留するブランチ情報を削除する
- ジョブの最後に記述する
- WORKSPACE 内のGitブランチリストを削除することによって、次のビルド表示のブランチリストを最新の状態で取得できるようにする
#!/bin/bash
### WORKSPACE 内に残留するブランチ情報を削除
# パス
PATH_GIT_BRANCHES=${WORKSPACE}/.git/refs/remotes/
# 削除
if test -d $PATH_GIT_BRANCHES ; then
rm -rf $PATH_GIT_BRANCHES
fi
バックアップから deploy する
- 万が一、バックアップからの切り戻しをする場合に利用する
- 通常、誤操作防止のため通常のデプロイジョブとは別に作成するのが一般的
- 別のジョブの WORKSPACE を直接参照するため、 PATH_BACKUP に環境変数の ${WORKSPACE} を利用しないことに注意
- 別の Jenkins インスタンスに設定する場合は PATH_BACKUP のルートパスを変更すること
- 説明欄の
<h2 style="color:red;">【警告】 このジョブは通常運用では決して利用しません 【警告】</h2>
のような警告記載により、操作を防止する工夫が必要
#!/bin/bash
### 変数定義
# ホスト
HOST_REMOTE=[ホストの名前]
# パス : PATH_BACKUP は特定のジョブのパスを直接指定しています
PATH_BACKUP=[Jenkins インスタンスのルートパス]/workspace/[リリースジョブのプロジェクト名]/_backup/
PATH_REMOTE=[リモートのパス]
# コマンド
RSYNC="rsync -rlcv"
### ファイル転送
if ${DRYRUN} ; then
echo -e "\n\n*** failback dryrun 開始 ***"
$RSYNC -n $PATH_BACKUP $HOST_REMOTE:$PATH_REMOTE
echo -e "*** failback dryrun 終了 ***\n\n"
else
# deploy
echo -e "\n\n*** failback deploy 開始 ***"
$RSYNC $PATH_BACKUP $HOST_REMOTE:$PATH_REMOTE
echo -e "*** failback deploy 終了 ***\n\n"
fi
TAG を打つ
- リリースTAGを生成する場合などに利用する
- 「$BRANCH_NAME」 は Git Parameter などから取得する
#!/bin/bash
### checkout develop
# git checkout develop
git checkout $BRANCH_NAME
BRANCH_ID="${BRANCH_NAME//origin\/release\//}"
### Tag生成
DATE=`date +%Y%m%d_%H-%M-%S`
TITLE="release_${DATE}_$BRANCH_ID"
git tag -a ${TITLE} -m "version : ${DATE}"
git push --tag
git tag -d ${TITLE}
develop を master にマージする
- develop と master の同期をする場合などに利用する
- 「$BRANCH_NAME」 は Git Parameter などから取得する
#!/bin/bash
### $BRANCH_NAME を checkout
git checkout $BRANCH_NAME
### $BRANCH_NAME を master に merge
git checkout master
git merge $BRANCH_NAME
git push origin master
納品用ブランチ delivery ブランチにコミットする
- MU納品案件の納品方法の1スタイル
- delivery という名前のブランチに、build 後の dist の内容だけをコミットする
- 納品先に diff を送付することにより変更点を伝達できる
- 「$BRANCH_NAME」 は Git Parameter などから取得する
#!/bin/bash
### 変数
BRANCH_DELIVERY=delivery
COMMIT_ID="$(git rev-parse HEAD)"
echo -e "\n\n*** $BRANCH_DELIVERY に $COMMIT_ID をデプロイする ***"
### checkout
git checkout $BRANCH_DELIVERY
git checkout origin/$BRANCH_NAME -- dist
### WORKSPACEから dist/ と .git/ 以外を削除
if test -d ${WORKSPACE} ; then
ls -A | grep -v "dist" | grep -v ".git" | xargs rm -rf | rm -rf .editorconfig | rm -rf .gitignore | rm -rf bin
fi
### distディレクトリをroot展開
cp -r dist/* .
rm -rf dist
### commit
if [ -z "$(git status --porcelain)" ]; then
echo -e "\n*** commitすべき差分が存在しません ***\n\n"
else
git add -A
git commit -m "delivery branch : $COMMIT_ID"
git push origin $BRANCH_DELIVERY
fi
WORKSPACE 内で build する (シンボリックリンクを利用する場合)
- バージョン管理の理想形は、dist をコミットしない状態
- Jenkins ジョブ内で dist を生成して deploy する
- 現状、ジョブ実行でnpmインストールできる環境は社内にない
- /home/node_package/ に事前にインフラにインストール依頼が必要
- インストールされたパスを SYMBOLIC_LINK に設定する
#!/bin/bash
### 変数定義
# パス
PATH_SRC=${WORKSPACE}/src/
# シンボリックリンク
SYMBOLIC_LINK=/home/node_package/[プロジェクトディレクトリなど]/node_modules
# コマンド
BUILD="npm run build"
### ビルド
if test -d $PATH_SRC ; then
# 指定領域のnode_modulesにシンボリックリンクを張る
if test -d node_modules ; then
echo -e "*** node_module is exist ***\n\n"
else
ln -s $SYMBOLIC_LINK
fi
# npm update
source ~/.nvm/nvm.sh
nvm use v8.9.1
node -v
nvm ls
BABEL_DISABLE_CACHE=1
# ビルド
echo -e "\n\n*** build ***"
$BUILD
echo -e "*** build done ***\n\n"
else
echo -e "\n\n*** content buildが実行できませんでした ***\n\n"
exit
fi