Jenkinsとshellの初心者が1からジョブを作って勉強になったこと - その１(shell script)

最近社内で新たにJenkinsジョブを作るチャンスがありました。
ShellScript、dockerなどに詳しくないこともあり、色々模索しました。
その中で勉強になったことをこの記事で記録します。
今後Jenkinsジョブを作る方のためにもなれればと思います。

# shellスクリプト諸々
今回のJenkinsはUnixサーバーで建てられたため、シェルスクリプトを書く必要がありました。
windowsのbatを少し作ったことはありますが、shellはほとんど経験がなく、初歩的なところから色々調べました。

## #!/bin/bash
shellで書くため、まず先頭にこの記述が必要です。
bash以外に他にもcsh、zshとか色々種類があります。
種類ごとに文法も違います。
例えば、cshでは環境を設定する場合、setenvというコマンドを使いますが、bashではこういう文法はなくて、exportを使うことになります。
bashが一番使われていそうで今回はbashを使ってみました。

## 変数宣言
windowsで変数宣言する場合、
```
set PRJ_ROOT=C:\jenkins\workspace
```
のような感じになります。
shellの場合
``` 
PRJ_ROOT=/var/jenkins/workspace
```
の感じでsetは要らなく、直接付与することになります。
そして、=の前後にスペースがあってはいけない模様です。

## 変数利用
以下のように変数名`PRJ_ROOT`の前に`$`をつければよいのです。
```
echo "PRJ_ROOT: " $PRJ_ROOT
```
複数の変数を結合して代入する場合、どこまでが変数名で、どこが文字列なのか判別がつかないことがあり、「${PRJ_ROOT}」のような感じで{}で囲む必要があります。
```
DIR_NAME=${PRJ_ROOT}_${PRJ_NAME}
```

## 環境変数の設定
前述のようにexportで指定して、PATHに代入すればよいのです。
以下はJavaの環境変数を設定する例です。
```
JAVA_HOME=/usr/lib/jvm/java-1.8.0-amazon-corretto/
export PATH=$JAVA_HOME/bin:$PATH
```

## 条件分岐
https://www.sejuku.net/blog/53707

こちらの記事を参考しました。結構わかりやすいので見ればわかると思います。
条件分岐及び条件文の書き方をまとめています。
例えば、ディレクトリの存在をチェックして、存在しない場合はそのフォルダを作成するコマンドは以下のようになります。
```
if [ ! -d $PRJ_DIR ]; then
  mkdir $PRJ_DIR
fi
```

## ファイルの読み込み
以下の例文はファイルから一行一行読みこんで、標準出力するコマンドになります。
```
cat [ファイル名] | while read line
do
　echo $line
done
```
ただ、これだけだと一つ問題があって、もしファイルの最終行は改行コードがない場合、最終行が読みこまれない事象が発生します。
ファイルの最後に改行コード入れたらよいのですが、入れたくないとかの場合に、以下のように追加で修正する必要があります。
```
cat ファイルのフルパス | while read line || [ -n "${line}" ];
do
　echo $line
done
```
ここの [ -n "${line}" ]の部分はその行の文字列の長さは1以上であるかどうかをチェックし、
1以上であればtrueを戻していますので、これで最終行の結果を読み込むようにしています。

## コマンド実行結果の代入
以下のように、バッククォートの中にコマンドを入れれば代入することができます。
```
[変数名]=`コマンド`
```
例として、dateコマンドで実行した結果をTODAYという変数に結果を代入するコマンドは以下の通りです。
```
TODAY=`date "+%Y%m%d%_H%M%S"`
```
日付付きのファイルとかを作成する時にこのコマンドをさらにファイル名に代入し、作成すると便利だと思います。

## ファイルの新規作成
一番シンプルのは以下通りで、touchコマンドを使うことです。
```
touch [ファイル名]
```
他にも色々オプションがありますが、以下の記事が参考になるかと思います。

https://eng-entrance.com/linux-command-touch

## コマンドの結果をログファイルに出力
以下の構文でできます。
```
echo [出力したい内容] >> [ログファイル名]
```
例えば以下の通りです。
```
MAIN_LOG_FILE=main_$TODAY.log
echo main.sh start >> $MAIN_LOG_FILE
```

## 権限変更

chmodコマンドを使えば権限の変更し、元々アクセスできないファイルにアクセスできるようになります。
例えば以下の例は、全てのユーザーに対して、読み込み、書き込み、実行の権限を付与するという意味です。

```
chmod 777 [ファイル名]
```

777はどういう意味でしょう？と思う方がいると思いますが、以下記事に詳細な内容が書かれています。

https://qiita.com/koara-local/items/185838ea3fa37d9007f7

数字でファイルの権限を変更する以外に以下のように権限の変更もできます。
例えば、以下例はファイルに実行の権限を付与するという意味です。
```
chmod -x [ファイル名]
```
以下の記事にいろんな権限を変更する方法が記載されています。

https://qiita.com/shisama/items/5f4c4fa768642aad9e06

# dockerコマンドの操作

## 動いているdocker imageを探す

シンプルに以下のコマンドです。
```
docker ps
```
その結果に`NAMES`というカラムがあり、その名前でdockerの操作ができます。

## docker環境でのコマンド実行
以下の構文で、コマンドを実行できます。
```
docker exec -i [dockerの名前] /bin/bash -c "[コマンドの内容]"
```

そして、さらに&でコマンドを繋ぐと、複数のコマンドを同時に実行することもできます。
以下のようです。
```
docker exec -i [dockerの名前] /bin/bash -c "[コマンド1] & [コマンド2]"
```

javaのインストールなど、rootユーザーが必要な場合があります。
その場合では以下のコマンドでにすれば実行できます。
例えば以下のようです。
```
docker exec -it --user root [dockerの名前] /bin/bash -c "apt install sudo"
```

## docker環境でのJavaインストール
debianベースの環境だと、どのコマンド実行すればJavaをインストールできるかは以下の記事が参考になります。（こちらはAmazon Corretto 8をインストールする手順になります。）

https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-8-ug/generic-linux-install.html

インストールの前提としてパッケージが足りないこともありますので、以下のようなコマンドを実行すればできると思います。
```
#パッケージのインストール
docker exec -it --user root [dockerの名前] /bin/bash -c "apt install wget"
docker exec -it --user root [dockerの名前] /bin/bash -c "apt install sudo"
docker exec -it --user root [dockerの名前] /bin/bash -c "apt install software-properties-common"

#javaのインストール
docker exec -it --user root [dockerの名前] /bin/bash -c "wget -O- https://apt.corretto.aws/corretto.key | sudo apt-key add - "
docker exec -it --user root [dockerの名前] /bin/bash -c "sudo add-apt-repository 'deb https://apt.corretto.aws stable main'"
docker exec -it --user root [dockerの名前] /bin/bash -c "sudo apt-get update; sudo apt-get install -y java-1.8.0-amazon-corretto-jdk"
```

# jenkins関連

## Jenkins上のシェル実行

ビルド手順の設定の中に`shellの実行`という選択がありますが、それを選べば利用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335050/0581fe52-7a9b-1a2c-78ef-e22b7f7d97d8.png)

## JenkinsからgitにSSH通信するためのセットアップ

### 公開鍵・秘密鍵を作成する

gitにSSH通信するために公開鍵と秘密鍵が必要になります。
まずは以下のようなコマンドを作成しましょう。
（Jenkinsはdocker上に建てられたため、dockerコマンドも含めている形になります。）
```
docker exec -i [dockerの名前] /bin/bash -c "cd [.sshフォルダの場所] && ssh-keygen -o -t rsa -C '[メールアドレス名とか]'"
```

すると、.sshフォルダ以下にid_rsa.pub（公開鍵）とid_rsa(秘密鍵)が作成されます。

### 公開鍵のアップ

git関連のサービスで、github、gitlab、bitbucketなどがありますが、作成された公開鍵をそのサービスに登録する形になります。

### 秘密鍵をJenkinsに登録

Jenkinsの管理から`Manage Credential`にアクセスし、`Global`ドメインをクリックして、`+Add Credentials`ボタンを押して、認証情報を追加する形です。

秘密鍵は直接入力する形で登録します。(以下の画像のイメージです。)
![Git秘密鍵.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335050/aa0fe68e-64ec-189c-d702-3555f7cc29b2.jpeg)

### JenkinsジョブにGitの認証情報を設定

Jenkinsジョブの設定に「ソースコード管理」があり、そこにGitのリポジトリURL及びJenkinsの管理から設定した認証情報を設定すればよいのです。

### known_hostsの作成

このファイルがないと、gitサービスの認証ができず、git cloneなどのコマンドがエラーになると思います。
以下のコマンドを実行すれば作成できます。
```
docker exec -i [dockerの名前] /bin/bash -c "cd [.sshフォルダの場所] && ssh-keyscan -H [gitサービスのドメイン] >> known_hosts"
```

以上の設定をすればJenkinsでのGit操作ができるようになります。

## 古いビルドの破棄

Jenkinsのジョブにこの設定がありますが、ビルドジョブの成果物がサーバーの容量を圧迫しないように設定したほうがいいと思います。
例えば、`ビルドの保存最大数`を10に設定すれば、11回目のジョブ実行が終了した後に1回目のビルドの履歴を削除しています。

## Jenkinsジョブのスケジュール設定

この記事を見れば設定の仕方がわかると思います。

https://qiita.com/nemutas/items/3f5816eabbf0eda5e6a9

例として、毎月の1日に実行するジョブは以下のような設定になります。
```
#時 分 日 月 曜日
H 0 1 * *
```

# 最後に
初心者レベルの話は多いですが、皆さんのご参考になれればと思います！