はじめに
しばらくJenkinsから離れていたのですが、個人のリポジトリをローカル環境でビルドしたり、最近のJenkinsのキャッチアップをしたくて、久しぶりに入れてみることにしました。
目新しい内容ではありませんが、2017年4月時点での手順がこれから始める方の参考になればと思い、メモとして残します。
環境 / やること / やらないこと
環境
- MacOS Sierra
- VirtualBox / Vagrant
今回、JenkinはMac上にはインストールせずに、仮想環境(CentOS7) にインストールすることにします。Macにインストールすると、起動や停止の仕方、アンインストールの際の確認がちょっとしずらいため、仮想環境に立ち上げることにします。
(このほうが、失敗してもゲストOSごと消すだけで済むので)
やること
- VirtualBox/Vagrantを使ってのCentOSの立ち上げ
- Jenkinsのインストール
- 起動の確認方法
- 簡単なスクリプトの定期実行
やらないこと
以下については細かくは触れません。
- Jenkinsってそもそもなに?な説明
- Vagrant/VirtualBoxの仕組みについて
- GitやGitHubとのリポジトリ連携について
- Linux (CentOS) の基本について
- Jenkins Blue Ocean
- モダンなUIに変えてくれますが、今回は詳しく触れません
仮想環境(ゲストOS) でCentOS7の起動
Vagrantfile
とりあえず、最小構成のVagrantfileです。
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
# デフォルトはNATのみ。ホストとゲストが相互に通信できるように
# private netrowkを指定。ゲストは 192.168.33.10
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.provider "virtualbox" do |vb|
# うまくsshで入れないときは、ここをコメントアウト。
# 起動時にVirtualBoxのGUIが立ち上がるので、そこから
# ログインして中を確認。
#vb.gui = true
# メモリ割当を変えたい場合はここをコメントアウトして調整
#vb.memory = "1024"
end
end
Vagrantの起動
初回は、vagrant up時にCentOS7のイメージがなければ公式サイトからダウンロードされてきます。そのままセットアップが進みます。
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'centos/7' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'centos/7'
default: URL: https://atlas.hashicorp.com/centos/7
==> default: Adding box 'centos/7' (v1703.01) for provider: virtualbox
... しばらく待つ ...
==> default: Successfully added box 'centos/7' (v1703.01) for 'virtualbox'!
==> default: Importing base box 'centos/7'...
... しばらく待つ ...
==> default: [vagrant-hostsupdater] Checking for host entries
==> default: Configuring and enabling network interfaces...
==> default: Rsyncing folder: /Users/akiko/vm/cent7/ => /vagrant
完了。
起動したので接続確認します。
$ vagrant ssh
Last login: Sat Apr 22 07:53:31 2017 from 10.0.2.2
[vagrant@localhost ~]$
ip addr show でIPの確認をします。
- eth0がNAT
- eth1が、ホストオンリーアダプタ追加でできたプライベートネットワークでのIP
[vagrant@localhost ~]$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:88:15:b6 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0
valid_lft 84260sec preferred_lft 84260sec
inet6 fe80::5054:ff:fe88:15b6/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:72:57:84 brd ff:ff:ff:ff:ff:ff
inet 192.168.33.10/24 brd 192.168.33.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe72:5784/64 scope link
valid_lft forever preferred_lft forever
起動が確認できたので、 vagrant ssh ではなく ssh 192.168.33.10 でログインできるようにします。
鍵の設定
Mac上(ホストOS上)から、192.168.33.10 のIPで通常のsshコマンドでログインできるように設定します。
以下のコマンドで、こんなことをしています。
- IPアドレス 192.168.33.10 が割り当たったサーバとして、sshの設定にエントリを追加します
- こちらを設定すると、ssh 192.168.33.10 とコマンドを打つと、ユーザ: vagrant としてログインできるようになります
$ vagrant ssh-config --host 192.168.33.10 >> ~/.ssh/config
# 書き出された内容の確認
$ grep -A 10 192.168.33.10 ~/.ssh/config
Host 192.168.33.10
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/..../Vagrantfileのあるディレクトリ/.vagrant/machines/default/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
※実際のところは、sshで192.168.33.10につなぎに行ってるわけではなく、127.0.0.1のport: 2222に対して.vagrant/ 以下に作成された鍵を使ってログインしています。
(Vagrantで操作するのでなければ、普通にゲストOSをセットアップしてプライベートネットワークを構成して、port: 22で接続できますが、Vagrantで管理する場合は、ゲストOSのport: 22をホスト側のport: 2222にポートフォワードしています)
鍵設定後に ssh でログイン
ssh に -v オプションをつけると、どの設定を使ってどういった流れで接続しているかが表示されます。
この場合は、実際に192.168.33.10 というIPアドレスのサーバに接続に行くわけではなく、127.0.0.1:2222 にsshのコネクションを張っているのが分かりますね。
また、ホストのユーザ名がなんであろうと、ゲストOS側には、user: vagrant で接続しに行っているのが分かります。 (Authenticating to 127.0.0.1:2222 as 'vagrant')
$ ssh -v 192.168.33.10
OpenSSH_7.4p1, LibreSSL 2.5.0
debug1: Reading configuration data /Users/xxx/.ssh/config
debug1: /Users/xxx/.ssh/config line 27: Applying options for 192.168.33.*
debug1: /Users/xxx/.ssh/config line 31: Applying options for 192.168.33.10
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 2222.
debug1: Connection established.
debug1: key_load_public: No such file or directory
... 中略 ...
debug1: match: OpenSSH_6.6.1 pat OpenSSH_6.6.1* compat 0x04000000
debug1: Authenticating to 127.0.0.1:2222 as 'vagrant'
... 以下略 ...
debug1: pledge: network
Last login: Sat Apr 22 08:05:24 2017 from 10.0.2.2
[vagrant@localhost ~]$
以上で基本のゲストOSセットアップは完了です。
ゲストOSに対しては、ポートフォワードで127.0.0.1:2222として接続していますが、これは sshに限ってのことです。(Vagrantでの管理上)
Webサーバ (Apacheやniginx) を起動したら、そちらは 192.168.33.10 としてアクセスできます。
追加パッケージのインストール
Jenkinsを動かすにあたって、入れておいたほうがいいもの&入れないといけないものを記載します。
- ネットワーク系のコマンドを入れる
必須ではないですが、思ったようにホストOSと疎通が取れていなかったり、プラグインが更新できなかったりする場合に、ネットワーク系のコマンドを良く使います。
CentOS7からネットワーク系のコマンドが変わっていたりするので、以前のネットワーク系コマンドに慣れている方は、以下も参考に追加してみてください。
- 参考: CentOS7から変わったネットワーク系のコマンド haisaihirokiさん
その他、wget, traceroute, tcpdump, telnet, ncを個人的に追加しています。
- Javaのランタイムを入れる (1.8以上にしてください!)
Jeninsは、Javaベースのアプリケーションとして動きますので、稼働にはJavaのランタイムが必要です。
まず初めに、ゲストOS内にJavaがすでにインストールされているか確認します。
新規にVagrantで立ち上げた場合は、Javaは通常インストールされていませんので、以下のようにcommand not foundになります。
$ java -version
-bash: java: command not found
もしJavaが入っており、バージョンが1.6以前だと、Jenkinsは非対応ですので、入れ直す必要があります。
さらに、こちらのメモを書いている時点で、Jenkins最新版ではJavaの1.8でないとうまく動かないというissueが上がっていますので、Javaは1.8以上を明示して入れてみます。
Javaが入っていない場合は、以下のようにyumで追加します。
$ sudo yum install java-1.8.0-openjdk
Javaのランタイムに関しては、Oracleからのダウンロード&追加でもかまいません。
タイムゾーン / 時刻を調整する
Jenkinsで何かを定期ジックしたり、データベースを稼働させたりする場合も含め、特に時刻の設定は重要です。
タイムゾーンは問題ないか、時刻はずれていないか確認してください。
# date とすると UTCが返ってくる...
[vagrant@localhost ~]$ date
Sat Apr 22 12:54:27 UTC 2017
# 確認するとやはりUTC...
[vagrant@localhost ~]$ sudo timedatectl
Local time: Sat 2017-04-22 12:55:01 UTC
Universal time: Sat 2017-04-22 12:55:01 UTC
RTC time: Sat 2017-04-22 12:34:32
Time zone: UTC (UTC, +0000)
NTP enabled: yes
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
# timedatectl コマンドで、日本時刻に調整
[vagrant@localhost ~]$ sudo timedatectl set-timezone Asia/Tokyo
[vagrant@localhost ~]$ date
Sat Apr 22 21:55:14 JST 2017
大幅にずれてしまっている場合は、自動補正では直らない場合があるので、以下で強制的に修正してみてください。
# ずれている....
[vagrant@localhost ~]$ date
Sat Apr 22 21:55:14 JST 2017
[vagrant@localhost ~]$ sudo chronyc -a makestep
200 OK
200 OK
[vagrant@localhost ~]$ date
Sun Apr 23 15:38:12 JST 2017
Jenkinsのインストール
それでは、さっそくJenkinsのインストールに入ります。
実のところ、Jenkinsは本体の jenkins.var というファイルと、Javaさえ入って入れば一番単純な構成で動かすことができます。
ただ、それだと自動起動やログ、基本設定などは自分で設定しないといけません。
パッケージ化されたものを利用すれば、自動起動の設定、専用ユーザの追加、インストールといった一連の作業を自動で設定してもらえます。
公式サイトにも書かれているとおり、CentOSはRed Hat系になりますので、yumでインストール可能です。ただし、CentOSの標準リポジトリにはJenkinsの公式サイトのリポジトリが登録されていないので、まず、ゲストOSのリポジトリ情報に追加登録します。
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
wgetが入っていないと、"sudo: wget: command not found" と怒られます。
この場合は、上記に書いたように sudo yum install wget をするか、こちらでも構いません。
$ sudo curl http://pkg.jenkins-ci.org/redhat/jenkins.repo -o /etc/yum.repos.d/jenkins.repo
$ sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
リポジトリに追加されると、 "yum repos" コマンドでJenkinsの公式サイトが追加されているのが分かりますので、よかったら確認してみてくださいね。
yum install jenkins
前置きが長くなりましたが、yum install jenkinsを実行します。
実行すると、その時点での最新リリースのJenkinsがインストールされます。
$ sudo yum install jenkins
... 中略 ...
---> Package jenkins.noarch 0:2.55-1.1 will be installed
... 中略 ...
Total download size: 67 M
Installed size: 67 M
Is this ok [y/d/N]: # yで実行
Installed:
jenkins.noarch 0:2.55-1.1
Complete!
インストールされると、サービス(自動)で起動させるためのものが入るので、以下のように確認できます。
# 専用ユーザが作られている
$ id jenkins
uid=995(jenkins) gid=993(jenkins) groups=993(jenkins)
# 起動スクリプトが作られている
$ ls /etc/init.d/jenkins
/etc/init.d/jenkins
# Jenkins用の本体 (Javaのバイナリ)が置かれている
$ ls /usr/lib/jenkins/
jenkins.war
# Jenkins用の作業用ディレクトリが作成されている
$ ls -la /var/lib/jenkins/
total 4
drwxr-xr-x. 2 jenkins jenkins 6 Apr 16 11:11 .
drwxr-xr-x. 30 root root 4096 Apr 22 11:03 ..
# Jenkinsのサービスとして起動時の設定ファイルが作成されている
$ ls -la /etc/sysconfig/jenkins
-rw-------. 1 root root 3116 Apr 16 11:11 /etc/sysconfig/jenkins
# Jenkins用のログのディレクトリが作成されている
$ ls -la /var/log/jenkins/
Jenkinsの起動
ここまででJenkinsがインストールされました。
では、サービスとして起動してみます。
※ CentOS7からは、サービス管理にsystemdを利用していますが、yumでインストールしたJenkinsは init (SyVinit) を利用しています。
- systemdでのサービス化をしたい場合は、こちらを参考に。
initでの設定でも、起動は service start / systemctl start どちらでも実施できます。
# systemctl start の場合 / OKは出ないけど起動する
$ sudo systemctl start jenkins
# service start の場合 / 実際は systemctl 経由で起動
$ sudo service jenkins start
Starting jenkins (via systemctl): [ OK ]
プロセスの起動は、psコマンドで確認できます。
こんな感じで、いろいろなオプションが付いていますがJenkinsが起動しています。
実行ユーザがjenkins, javaコマンドを使っている、port: 8080 版を使っているというのが分かりますね。
$ ps -elf | grep [j]enkins
0 S jenkins 15774 1 11 80 0 - 300113 futex_ 11:13 ? 00:00:05 java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar /usr/lib/jenkins/jenkins.war --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon --httpPort=8080 --debug=5 --handlerCountMax=100 --handlerCountMaxIdle=20
ホストOSから確認してみる
では、ホストOSから確認してみます。
うまく起動してアクセス上問題ないと、まずは最初の画面でJenkinsを起動しているサーバの管理者だけが、確実に操作できるように、サーバ上に保存された文字列を入力することで認証をもとめられます。
以前は、この認証なしでデフォルトでJenkinsの設定を進めることができましたが、プライベートネットワーク上でないサーバでJenkinsをセットアップした場合、最初の操作を第三者に実行されてしまうと、OS上の任意のシェルなどを実行される可能性もあったので、安全性を考慮したステップを踏んでいます。
文字列は、画面の指示のとおりの場所にあるので、このような感じで取得し、貼り付けます。
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
表示された文字列をCopy & Paste してブラウザに貼り付け
サーバ管理者としての認証が通ると、プラグインの設定になります。
初めての方は、Install Suggested Pluginで問題ないと思います。
プラグインのインストールが始まると、プラグインのダウンロード&自動インストールが始まります。
プラグインのインストールは、Jenkinsのインストールされているサーバがインターネットとの接続性がないとダウンロードが出来ません。
プロキシ環境下でサーバ・ゲストOSを稼働させている場合は注意してください。
プラグインのインストールが終わると、改めて管理者アカウントの登録となります。
アカウントが登録されると、Welcome画面になります。
これでJenkinsを利用する準備が出来ました!
うまく表示されない場合
Firewalldを止めてみる
もしホスト側から接続できない場合は、Firewalldが起動していないか確認します。
$ systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
# disabled だと停止しています
原因の切り分けのため、まずFirewalldが起動していたら、停止してみてください。
ログを確認してみる
serviceで起動した場合は、Jenkinsのログは /var/log/jenkins/jenkins.log に書き出されます。まずはこちらに何かエラーが出ているかもしれないので、確認してみてください。
うまく原因が掴めなかったり、ログには何も出ていない場合は、service stop jenkins でJenkinsのプロセスを止めてみて、次にフォアグラウンドでJenkinsを実行してみます。
$ sudo service stop jenkins
$ java -jar /usr/lib/jenkins/jenkins.war
Running from: /usr/lib/jenkins/jenkins.war
webroot: $user.home/.jenkins
Apr 22, 2017 12:03:25 PM Main deleteWinstoneTempContents
WARNING: Failed to delete the temporary Winstone file /tmp/winstone/jenkins.war
Apr 22, 2017 12:03:25 PM org.eclipse.jetty.util.log.JavaUtilLog info
INFO: Logging initialized @1005ms
... 中略 ...
しばらくしてからブラウザにアクセスしてみた時に、ただしくJenkinsの画面が表示されない場合は、ターミナル側にメッセージが出ていたりします。
※ 20170423時点では、Jenkins 2.55とJava1.7の組み合わせでは Error: 503 になります。
上記のJavaのインストールの所で触れているとおり、Java1.8をインストールしてみてください。
新しいジョブを作ろう!
では、早速簡単なジョブを作ってみます。
タイトルは日本語でも大丈夫なようですが、初めての場合は「フリースタイルのビルド」を選ぶと良いです。
とにかく何ができるのか試したい、という場合は、ジョブの名前を指定して、保存をすれば、それだけで最初のジョブは出来上がります。
実際に何をやらせるか、定期実行はどうするか、という設定は後からで全然かまいません。
実行してみよう!
ジョブを保存したら、まずは画面左上部の「ビルド実行」のリンクをクリックしてみて下さい。
実行の結果は、順番に「#番号」という形で番号が振られます。
実行結果を見る場合は、画面左の「ビルド履歴」から、指定の番号をクリック -> 「コンソール出力」というリンクで表示されます。
もしくは、「ビルド履歴」の各ビルド番号のプルダウンからアクセスできます。
定期実行でない場合は、誰が実行したか、という記録も添えられます。
ジョブの名前だけで、実際はなにも設定していない場合でも、実行されると「実行したよ!」という記録がどんどん溜まっていきます。
ビルド追加でシェルを実行させよう!
では、実際になにかこのジョブで仕事をさせてみます。
もともとは、ソースコードからコンパイルしてバイナリを作ることをビルドと言っていましたが、Jenkinsでは別に何かをコンパイルするのではなくとも、何かをさせることを「ビルド」と言っています。
まずは、CentOS上で動かしているので、CentOSのshellを実行させて、その結果を確認してみましょう。
作ったばかりのジョブの設定画面に戻り、「ビルド」という項目に移動します。
ここで、「シェルの実行」を選びます。
このテキストエリアに、思いつくシェルスを入れて見ます。
単純に実行結果を見たいので、以下を入れて見ました。
- date (日時を表示)
- uname -a (OSの名前)
- id (シェルを実行しているユーザの名前)
- history 5 (シェルの実行履歴)
これで保存 -> 同じく「ビルド実行」を押し、コンソール出力を確認してみてください。
定期実行させてみよう!
簡単なジョブを登録したので、定期実行させてみます。
こちらは、「ビルド・トリガ」という項目で設定します。
いろいろ方法がありますが、まずは Cronと同じく定期実行させる設定をしてみます。
書き方が分からない場合は、他の設定箇所も同様ですが、「?」アイコンをクリックするとヒントや説明が出てきますので、参考にしてください。
例では1分おきにしてみました。
コンソールでの実行結果ですが、定期実行の場合は、"Started by timer" と表示されます。
また、シェルの実行結果を確認すると、"id" コマンドは、Jenkinsのプロセスを実行している user: jenkins になっていることが分かりますね。
このため、基本はJenkinsのサービスを動かしているプロセスのユーザとしてコマンドを実行しますので、権限が足りない場合はシェルが実行できません。
ただし、rootのような強い権限で動かしてしまうと、シェルを使ってOSに入らなくともなんでも出来てしまうので、そのあたり実行ユーザには注意して下さい。
まとめ
さて、自分の復習を兼ねて、駆け足でVagrant / CentOS7 でのJenkins起動について記載しましたが、だいぶ端折っている点や説明が足りていない点もありますので、「これは何?」「うまくいきません...」という場合は、コメントいただけると幸いです。
Jenkins自体は起動してしまえばどのOSでも基本は同じなので、どちらかというと、CentOS7の準備に文章を当てています....。
機会があれば、Blue Oceanを使ってみた点も記載したいと思います。
メモ:疎通は確認できたのでFirewalldを有効にしておきたい
とりあえず疎通確認できたので、Firewalldは有効にしておきたい場合は、port: 8080番を有効にしておきます。このような感じ。
$ sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
success
$ sudo firewall-cmd --reload
success
(※接続元IP単位で制御したい場合は、追加設定が要ります)
メモ:Jenkinsの実行ユーザについて (20170503追記)
yum installでRPMパッケージから’インストールしたJenkinsのプロセスは、jenkinsと言うユーザで動きます。
ただし、Jenkinsのジョブとして動かすshell scriptは 非対話モード で動きますので、通常のユーザが利用できるコマンドや環境変数の結果が異なる場合があります。
また、セキュリティの関係上、OS上のjenkinsユーザは外部サーバからログイン可能なアカウントとして定義されていません。
(/etc/passwdをご覧いただくと、一般ユーザのシェルが /bin/csh や /bin/bash なのに対し、user: jenkinsは /bin/false と言う設定になっています)
たとえば、上記のshell scriptのジョブで history 5 という行がありますが、実際のところ、Jenkinsのコンソール出力の結果には、historyコマンドを打っても何も表示されません。
(ログインしてのシェルの実行だと普通は.bash_historyというファイルにコマンド履歴が書かれますが、非対話モードだとこの動作はオフで、historyコマンドが無効になっているからです)
ジョブの実行がうまくいかなかったり、思ったような動作になってくれない場合は、一時的にjenkinsをログイン可能なユーザとして定義してあげて、原因をチェックするといった作業をしてみるといいと思います。
(/bin/false から /bin/bashに変更、su - jenkinsでjenkinsユーザになって権限チェック、確認が終わったら /bin/false に戻すなど)